[code.view]

[top] / python / PyMOTW / docs / _static / websupport.js

     (function($) {
       $.fn.autogrow = function(){
         return this.each(function(){
         var textarea = this;
     
         $.fn.autogrow.resize(textarea);
     
         $(textarea)
           .focus(function() {
             textarea.interval = setInterval(function() {
               $.fn.autogrow.resize(textarea);
             }, 500);
           })
           .blur(function() {
             clearInterval(textarea.interval);
           });
         });
       };
     
       $.fn.autogrow.resize = function(textarea) {
         var lineHeight = parseInt($(textarea).css('line-height'), 10);
         var lines = textarea.value.split('\n');
         var columns = textarea.cols;
         var lineCount = 0;
         $.each(lines, function() {
           lineCount += Math.ceil(this.length / columns) || 1;
         });
         var height = lineHeight * (lineCount + 1);
         $(textarea).css('height', height);
       };
     })(jQuery);
     
     (function($) {
       var comp, by;
     
       function init() {
         initEvents();
         initComparator();
       }
     
       function initEvents() {
         $('a.comment_close').live("click", function(event) {
           hide($(this).attr('id').substring(2));
           return false;
         });
         $('.vote').live("click", function() {
           handleVote($(this));
           return false;
         });
         $('a.reply').live("click", function() {
           openReply($(this).attr('id').substring(2));
           return false;
         });
         $('a.close_reply').live("click", function() {
           closeReply($(this).attr('id').substring(2));
           return false;
         });
         $('a.sort_option').live("click", function(event) {
           handleReSort($(this));
           return false;
         });
         $('a.show_proposal').live("click", function() {
           showProposal($(this).attr('id').substring(2));
           return false;
         });
         $('a.hide_proposal').live("click", function() {
           hideProposal($(this).attr('id').substring(2));
           return false;
         });
         $('a.show_propose_change').live("click", function() {
           showProposeChange($(this).attr('id').substring(2));
           return false;
         });
         $('a.hide_propose_change').live("click", function() {
           hideProposeChange($(this).attr('id').substring(2));
           return false;
         });
         $('a.accept_comment').live("click", function() {
           acceptComment($(this).attr('id').substring(2));
           return false;
         });
         $('a.reject_comment').live("click", function() {
           rejectComment($(this).attr('id').substring(2));
           return false;
         });
         $('a.delete_comment').live("click", function() {
           deleteComment($(this).attr('id').substring(2));
           return false;
         });
       }
     
       /*
        Set comp, which is a comparator function used for sorting and
        inserting comments into the list.
       */
       function setComparator() {
         // If the first three letters are "asc", sort in ascending order
         // and remove the prefix.
         if (by.substring(0,3) == 'asc') {
           var i = by.substring(3);
           comp = function(a, b) { return a[i] - b[i]; };
         } else {
           // Otherwise sort in descending order.
           comp = function(a, b) { return b[by] - a[by]; };
         }
     
         // Reset link styles and format the selected sort option.
         $('a.sel').attr('href', '#').removeClass('sel');
         $('a.' + by).removeAttr('href').addClass('sel');
       }
     
       /*
        Create a comp function. If the user has preferences stored in
        the sortBy cookie, use those, otherwise use the default.
       */
       function initComparator() {
         by = 'rating'; // Default to sort by rating.
         // If the sortBy cookie is set, use that instead.
         if (document.cookie.length > 0) {
           var start = document.cookie.indexOf('sortBy=');
           if (start != -1) {
             start = start + 7;
             var end = document.cookie.indexOf(";", start);
             if (end == -1) {
               end = document.cookie.length;
               by = unescape(document.cookie.substring(start, end));
             }
           }
         }
         setComparator();
       }
     
       /*
        Show a comment div.
       */
       function show(id) {
         $('#ao' + id).hide();
         $('#ah' + id).show();
         var context = $.extend({id: id}, opts);
         var popup = $(renderTemplate(popupTemplate, context)).hide();
         popup.find('textarea[name="proposal"]').hide();
         popup.find('a.' + by).addClass('sel');
         var form = popup.find('#cf' + id);
         form.submit(function(event) {
           event.preventDefault();
           addComment(form);
         });
         $('#s' + id).after(popup);
         popup.slideDown('fast', function() {
           getComments(id);
         });
       }
     
       /*
        Hide a comment div.
       */
       function hide(id) {
         $('#ah' + id).hide();
         $('#ao' + id).show();
         var div = $('#sc' + id);
         div.slideUp('fast', function() {
           div.remove();
         });
       }
     
       /*
        Perform an ajax request to get comments for a node
        and insert the comments into the comments tree.
       */
       function getComments(id) {
         $.ajax({
          type: 'GET',
          url: opts.getCommentsURL,
          data: {node: id},
          success: function(data, textStatus, request) {
            var ul = $('#cl' + id);
            var speed = 100;
            $('#cf' + id)
              .find('textarea[name="proposal"]')
              .data('source', data.source);
     
            if (data.comments.length === 0) {
              ul.html('<li>No comments yet.</li>');
              ul.data('empty', true);
            } else {
              // If there are comments, sort them and put them in the list.
              var comments = sortComments(data.comments);
              speed = data.comments.length * 100;
              appendComments(comments, ul);
              ul.data('empty', false);
            }
            $('#cn' + id).slideUp(speed + 200);
            ul.slideDown(speed);
          },
          error: function(request, textStatus, error) {
            showError('Oops, there was a problem retrieving the comments.');
          },
          dataType: 'json'
         });
       }
     
       /*
        Add a comment via ajax and insert the comment into the comment tree.
       */
       function addComment(form) {
         // Disable the form that is being submitted.
         form.find('textarea,input').attr('disabled', 'disabled');
         var node_id = form.find('input[name="node"]').val();
         var parent_id = form.find('input[name="parent"]').val();
     
         // Send the comment to the server.
         $.ajax({
           type: "POST",
           url: opts.addCommentURL,
           dataType: 'json',
           data: {
             node: node_id,
             parent: parent_id,
             text: form.find('textarea[name="comment"]').val(),
             proposal: form.find('textarea[name="proposal"]').val()
           },
           success: function(data, textStatus, error) {
             // Reset the form.
             if (node_id) {
               hideProposeChange(node_id);
             }
             form.find('textarea')
               .val('')
               .add(form.find('input'))
               .removeAttr('disabled');
     	var ul = $('#cl' + (node_id || parent_id));
             if (ul.data('empty')) {
               $(ul).empty();
               ul.data('empty', false);
             }
             insertComment(data.comment);
           },
           error: function(request, textStatus, error) {
             form.find('textarea,input').removeAttr('disabled');
             showError('Oops, there was a problem adding the comment.');
           }
         });
       }
     
       /*
        Recursively append comments to the main comment list and children
        lists, creating the comment tree.
       */
       function appendComments(comments, ul) {
         $.each(comments, function() {
           var div = createCommentDiv(this);
           ul.append($(document.createElement('li')).html(div));
           appendComments(this.children, div.find('ul.children'));
           // To avoid stagnating data, don't store the comments children in data.
           this.children = null;
           div.data('comment', this);
         });
       }
     
       /*
        After adding a new comment, it must be inserted in the correct
        location in the comment tree.
       */
       function insertComment(comment) {
         var div = createCommentDiv(comment);
     
         // To avoid stagnating data, don't store the comments children in data.
         comment.children = null;
         div.data('comment', comment);
     
         var ul = $('#cl' + (comment.node || comment.parent));
         var siblings = getChildren(ul);
     
         var li = $(document.createElement('li'));
         li.hide();
     
         // Determine where in the parents children list to insert this comment.
         for(i=0; i < siblings.length; i++) {
           if (comp(comment, siblings[i]) <= 0) {
             $('#cd' + siblings[i].id)
               .parent()
               .before(li.html(div));
             li.slideDown('fast');
             return;
           }
         }
     
         // If we get here, this comment rates lower than all the others,
         // or it is the only comment in the list.
         ul.append(li.html(div));
         li.slideDown('fast');
       }
     
       function acceptComment(id) {
         $.ajax({
           type: 'POST',
           url: opts.acceptCommentURL,
           data: {id: id},
           success: function(data, textStatus, request) {
             $('#cm' + id).fadeOut('fast');
           },
           error: function(request, textStatus, error) {
             showError("Oops, there was a problem accepting the comment.");
           }
         });
       }
     
       function rejectComment(id) {
         $.ajax({
           type: 'POST',
           url: opts.rejectCommentURL,
           data: {id: id},
           success: function(data, textStatus, request) {
             var div = $('#cd' + id);
             div.slideUp('fast', function() {
             div.remove();
             });
           },
           error: function(request, textStatus, error) {
             showError("Oops, there was a problem rejecting the comment.");
           }
         });
       }
     
       function deleteComment(id) {
         $.ajax({
           type: 'POST',
           url: opts.deleteCommentURL,
           data: {id: id},
           success: function(data, textStatus, request) {
             var div = $('#cd' + id);
             div
               .find('span.user_id:first')
               .text('[deleted]').end()
               .find('p.comment_text:first')
               .text('[deleted]').end()
               .find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
                     ', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
               .remove();
             var comment = div.data('comment');
             comment.username = '[deleted]';
             comment.text = '[deleted]';
             div.data('comment', comment);
           },
           error: function(request, textStatus, error) {
             showError("Oops, there was a problem deleting the comment.");
           }
         });
       }
     
       function showProposal(id) {
         $('#sp' + id).hide();
         $('#hp' + id).show();
         $('#pr' + id).slideDown('fast');
       }
     
       function hideProposal(id) {
         $('#hp' + id).hide();
         $('#sp' + id).show();
         $('#pr' + id).slideUp('fast');
       }
     
       function showProposeChange(id) {
         $('#pc' + id).hide();
         $('#hc' + id).show();
         var textarea = $('#pt' + id);
         textarea.val(textarea.data('source'));
         $.fn.autogrow.resize(textarea[0]);
         textarea.slideDown('fast');
       }
     
       function hideProposeChange(id) {
         $('#hc' + id).hide();
         $('#pc' + id).show();
         var textarea = $('#pt' + id);
         textarea.val('').removeAttr('disabled');
         textarea.slideUp('fast');
       }
     
       /*
        Handle when the user clicks on a sort by link.
       */
       function handleReSort(link) {
         var classes = link.attr('class').split(/\s+/);
         for (var i=0; i<classes.length; i++) {
           if (classes[i] != 'sort_option') {
     	by = classes[i];
           }
         }
         setComparator();
         // Save/update the sortBy cookie.
         var expiration = new Date();
         expiration.setDate(expiration.getDate() + 365);
         document.cookie= 'sortBy=' + escape(by) +
                          ';expires=' + expiration.toUTCString();
         $('ul.comment_ul').each(function(index, ul) {
           var comments = getChildren($(ul), true);
           comments = sortComments(comments);
           appendComments(comments, $(ul).empty());
         });
       }
     
       /*
        Function to process a vote when a user clicks an arrow.
       */
       function handleVote(link) {
         if (!opts.voting) {
           showError("You'll need to login to vote.");
           return;
         }
     
         var id = link.attr('id');
         // If it is an unvote, the new vote value is 0,
         // Otherwise it's 1 for an upvote, or -1 for a downvote.
         var value = 0;
         if (id.charAt(1) != 'u') {
           value = id.charAt(0) == 'u' ? 1 : -1;
         }
         // The data to be sent to the server.
         var d = {
           comment_id: id.substring(2),
           value: value
         };
     
         // Swap the vote and unvote links.
         link.hide();
         $('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)
           .show();
     
         // The div the comment is displayed in.
         var div = $('div#cd' + d.comment_id);
         var data = div.data('comment');
     
         // If this is not an unvote, and the other vote arrow has
         // already been pressed, unpress it.
         if ((d.value !== 0) && (data.vote === d.value * -1)) {
           $('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();
           $('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();
         }
     
         // Update the comments rating in the local data.
         data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);
         data.vote = d.value;
         div.data('comment', data);
     
         // Change the rating text.
         div.find('.rating:first')
           .text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));
     
         // Send the vote information to the server.
         $.ajax({
           type: "POST",
           url: opts.processVoteURL,
           data: d,
           error: function(request, textStatus, error) {
             showError("Oops, there was a problem casting that vote.");
           }
         });
       }
     
       /*
        Open a reply form used to reply to an existing comment.
       */
       function openReply(id) {
         // Swap out the reply link for the hide link
         $('#rl' + id).hide();
         $('#cr' + id).show();
     
         // Add the reply li to the children ul.
         var div = $(renderTemplate(replyTemplate, {id: id})).hide();
         $('#cl' + id)
           .prepend(div)
           // Setup the submit handler for the reply form.
           .find('#rf' + id)
           .submit(function(event) {
             event.preventDefault();
             addComment($('#rf' + id));
             closeReply(id);
           });
         div.slideDown('fast');
       }
     
       /*
        Close the reply form opened with openReply.
       */
       function closeReply(id) {
         // Remove the reply div from the DOM.
         $('#rd' + id).slideUp('fast', function() {
           $(this).remove();
         });
     
         // Swap out the hide link for the reply link
         $('#cr' + id).hide();
         $('#rl' + id).show();
       }
     
       /*
        Recursively sort a tree of comments using the comp comparator.
       */
       function sortComments(comments) {
         comments.sort(comp);
         $.each(comments, function() {
           this.children = sortComments(this.children);
         });
         return comments;
       }
     
       /*
        Get the children comments from a ul. If recursive is true,
        recursively include childrens' children.
       */
       function getChildren(ul, recursive) {
         var children = [];
         ul.children().children("[id^='cd']")
           .each(function() {
             var comment = $(this).data('comment');
             if (recursive) {
               comment.children = getChildren($(this).find('#cl' + comment.id), true);
             }
             children.push(comment);
           });
         return children;
       }
     
       /*
        Create a div to display a comment in.
       */
       function createCommentDiv(comment) {
         // Prettify the comment rating.
         comment.pretty_rating = comment.rating + ' point' +
         (comment.rating == 1 ? '' : 's');
         // Create a div for this comment.
         var context = $.extend({}, opts, comment);
         var div = $(renderTemplate(commentTemplate, context));
     
         // If the user has voted on this comment, highlight the correct arrow.
         if (comment.vote) {
           var direction = (comment.vote == 1) ? 'u' : 'd';
           div.find('#' + direction + 'v' + comment.id).hide();
           div.find('#' + direction + 'u' + comment.id).show();
         }
     
         if (comment.text != '[deleted]') {
           div.find('a.reply').show();
           if (comment.proposal_diff) {
             div.find('#sp' + comment.id).show();
           }
           if (opts.moderator && !comment.displayed) {
             div.find('#cm' + comment.id).show();
           }
           if (opts.moderator || (opts.username == comment.username)) {
             div.find('#dc' + comment.id).show();
           }
         }
         return div;
       }
     
       /*
        A simple template renderer. Placeholders such as <%id%> are replaced
        by context['id'] with items being escaped. Placeholders such as <#id#>
        are not escaped.
       */
       function renderTemplate(template, context) {
         var esc = $(document.createElement('div'));
     
         function handle(ph, escape) {
           var cur = context;
           $.each(ph.split('.'), function() {
             cur = cur[this];
           });
           return escape ? esc.text(cur || "").html() : cur;
         }
     
         return template.replace(/<([%#])([\w\.]*)\1>/g, function(){
           return handle(arguments[2], arguments[1] == '%' ? true : false);
         });
       }
     
       function showError(message) {
         $(document.createElement('div')).attr({'class': 'popup_error'})
           .append($(document.createElement('h1')).text(message))
           .appendTo('body')
           .fadeIn("slow")
           .delay(2000)
           .fadeOut("slow");
       }
     
       /*
        Add a link the user uses to open the comments popup.
       */
       $.fn.comment = function() {
         return this.each(function() {
           var id = $(this).attr('id').substring(1);
           var count = COMMENT_METADATA[id];
           var title = count + ' comment' + (count == 1 ? '' : 's');
           var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
           $(this)
             .append(
               $(document.createElement('a')).attr({
                 href: '#',
                 'class': 'sphinx_comment',
                 id: 'ao' + id
               })
                 .append($(document.createElement('img')).attr({
                   src: image,
                   alt: 'comment',
                   title: title
                 }))
                 .click(function(event) {
                   event.preventDefault();
                   show($(this).attr('id').substring(2));
                 })
             )
             .append(
               $(document.createElement('a')).attr({
                 href: '#',
                 'class': 'sphinx_comment_close hidden',
                 id: 'ah' + id
               })
                 .append($(document.createElement('img')).attr({
                   src: opts.closeCommentImage,
                   alt: 'close',
                   title: 'close'
                 }))
                 .click(function(event) {
                   event.preventDefault();
                   hide($(this).attr('id').substring(2));
                 })
             );
         });
       };
     
       var opts = jQuery.extend({
         processVoteURL: '/process_vote',
         addCommentURL: '/add_comment',
         getCommentsURL: '/get_comments',
         acceptCommentURL: '/accept_comment',
         rejectCommentURL: '/reject_comment',
         deleteCommentURL: '/delete_comment',
         commentImage: '/static/_static/comment.png',
         closeCommentImage: '/static/_static/comment-close.png',
         loadingImage: '/static/_static/ajax-loader.gif',
         commentBrightImage: '/static/_static/comment-bright.png',
         upArrow: '/static/_static/up.png',
         downArrow: '/static/_static/down.png',
         upArrowPressed: '/static/_static/up-pressed.png',
         downArrowPressed: '/static/_static/down-pressed.png',
         voting: false,
         moderator: false
       }, COMMENT_OPTIONS);
     
       var replyTemplate = '\
         <li>\
           <div class="reply_div" id="rd<%id%>">\
             <form id="rf<%id%>">\
               <textarea name="comment" cols="80"></textarea>\
               <input type="submit" value="add reply" />\
               <input type="hidden" name="parent" value="<%id%>" />\
               <input type="hidden" name="node" value="" />\
             </form>\
           </div>\
         </li>';
     
       var commentTemplate = '\
         <div  id="cd<%id%>" class="spxcdiv">\
           <div class="vote">\
             <div class="arrow">\
               <a href="#" id="uv<%id%>" class="vote">\
                 <img src="<%upArrow%>" />\
               </a>\
               <a href="#" id="uu<%id%>" class="un vote">\
                 <img src="<%upArrowPressed%>" />\
               </a>\
             </div>\
             <div class="arrow">\
               <a href="#" id="dv<%id%>" class="vote">\
                 <img src="<%downArrow%>" id="da<%id%>" />\
               </a>\
               <a href="#" id="du<%id%>" class="un vote">\
                 <img src="<%downArrowPressed%>" />\
               </a>\
             </div>\
           </div>\
           <div class="comment_content">\
             <p class="tagline comment">\
               <span class="user_id"><%username%></span>\
               <span class="rating"><%pretty_rating%></span>\
               <span class="delta"><%time.delta%></span>\
             </p>\
             <p class="comment_text comment"><%text%></p>\
             <p class="comment_opts comment">\
               <a href="#" class="reply hidden" id="rl<%id%>">reply ▹</a>\
               <a href="#" class="close_reply" id="cr<%id%>">reply ▿</a>\
               <a href="#" id="sp<%id%>" class="show_proposal">\
                 proposal ▹\
               </a>\
               <a href="#" id="hp<%id%>" class="hide_proposal">\
                 proposal ▿\
               </a>\
               <a href="#" id="dc<%id%>" class="delete_comment hidden">\
                 delete\
               </a>\
               <span id="cm<%id%>" class="moderation hidden">\
                 <a href="#" id="ac<%id%>" class="accept_comment">accept</a>\
                 <a href="#" id="rc<%id%>" class="reject_comment">reject</a>\
               </span>\
             </p>\
             <pre class="proposal" id="pr<%id%>">\
     <#proposal_diff#>\
             </pre>\
               <ul class="children" id="cl<%id%>"></ul>\
             </div>\
             <div class="clearleft"></div>\
           </div>\
         </div>';
     
       var popupTemplate = '\
         <div class="sphinx_comments" id="sc<%id%>">\
           <h1>Comments</h1>\
           <form method="post" id="cf<%id%>" class="comment_form" action="/docs/add_comment">\
             <textarea name="comment" cols="80"></textarea>\
             <p class="propose_button">\
               <a href="#" id="pc<%id%>" class="show_propose_change">\
                 Propose a change ▹\
               </a>\
               <a href="#" id="hc<%id%>" class="hide_propose_change">\
                 Propose a change ▿\
               </a>\
             </p>\
             <textarea name="proposal" id="pt<%id%>" cols="80" spellcheck="false"></textarea>\
             <input type="submit" value="add comment" />\
             <input type="hidden" name="node" value="<%id%>" />\
             <input type="hidden" name="parent" value="" />\
             <p class="sort_options">\
               Sort by:\
               <a href="#" class="sort_option rating">top</a>\
               <a href="#" class="sort_option ascage">newest</a>\
               <a href="#" class="sort_option age">oldest</a>\
             </p>\
           </form>\
           <h3 id="cn<%id%>">loading comments... <img src="<%loadingImage%>" alt="" /></h3>\
           <ul id="cl<%id%>" class="comment_ul"></ul>\
         </div>';
     
       $(document).ready(function() {
         init();
       });
     })(jQuery);
     
     $(document).ready(function() {
       $('.spxcmt').comment();
     
       /** Highlight search words in search results. */
       $("div.context").each(function() {
         var params = $.getQueryParameters();
         var terms = (params.q) ? params.q[0].split(/\s+/) : [];
         var result = $(this);
         $.each(terms, function() {
           result.highlightText(this.toLowerCase(), 'highlighted');
         });
       });
     });
     

[top] / python / PyMOTW / docs / _static / websupport.js

contact | logmethods.com