Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
| Download
Sage Reference Manual
Project: SageManifolds
Views: 717109/*1* websupport.js2* ~~~~~~~~~~~~~3*4* sphinx.websupport utilties for all documentation.5*6* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.7* :license: BSD, see LICENSE for details.8*9*/1011(function($) {12$.fn.autogrow = function() {13return this.each(function() {14var textarea = this;1516$.fn.autogrow.resize(textarea);1718$(textarea)19.focus(function() {20textarea.interval = setInterval(function() {21$.fn.autogrow.resize(textarea);22}, 500);23})24.blur(function() {25clearInterval(textarea.interval);26});27});28};2930$.fn.autogrow.resize = function(textarea) {31var lineHeight = parseInt($(textarea).css('line-height'), 10);32var lines = textarea.value.split('\n');33var columns = textarea.cols;34var lineCount = 0;35$.each(lines, function() {36lineCount += Math.ceil(this.length / columns) || 1;37});38var height = lineHeight * (lineCount + 1);39$(textarea).css('height', height);40};41})(jQuery);4243(function($) {44var comp, by;4546function init() {47initEvents();48initComparator();49}5051function initEvents() {52$('a.comment-close').live("click", function(event) {53event.preventDefault();54hide($(this).attr('id').substring(2));55});56$('a.vote').live("click", function(event) {57event.preventDefault();58handleVote($(this));59});60$('a.reply').live("click", function(event) {61event.preventDefault();62openReply($(this).attr('id').substring(2));63});64$('a.close-reply').live("click", function(event) {65event.preventDefault();66closeReply($(this).attr('id').substring(2));67});68$('a.sort-option').live("click", function(event) {69event.preventDefault();70handleReSort($(this));71});72$('a.show-proposal').live("click", function(event) {73event.preventDefault();74showProposal($(this).attr('id').substring(2));75});76$('a.hide-proposal').live("click", function(event) {77event.preventDefault();78hideProposal($(this).attr('id').substring(2));79});80$('a.show-propose-change').live("click", function(event) {81event.preventDefault();82showProposeChange($(this).attr('id').substring(2));83});84$('a.hide-propose-change').live("click", function(event) {85event.preventDefault();86hideProposeChange($(this).attr('id').substring(2));87});88$('a.accept-comment').live("click", function(event) {89event.preventDefault();90acceptComment($(this).attr('id').substring(2));91});92$('a.delete-comment').live("click", function(event) {93event.preventDefault();94deleteComment($(this).attr('id').substring(2));95});96$('a.comment-markup').live("click", function(event) {97event.preventDefault();98toggleCommentMarkupBox($(this).attr('id').substring(2));99});100}101102/**103* Set comp, which is a comparator function used for sorting and104* inserting comments into the list.105*/106function setComparator() {107// If the first three letters are "asc", sort in ascending order108// and remove the prefix.109if (by.substring(0,3) == 'asc') {110var i = by.substring(3);111comp = function(a, b) { return a[i] - b[i]; };112} else {113// Otherwise sort in descending order.114comp = function(a, b) { return b[by] - a[by]; };115}116117// Reset link styles and format the selected sort option.118$('a.sel').attr('href', '#').removeClass('sel');119$('a.by' + by).removeAttr('href').addClass('sel');120}121122/**123* Create a comp function. If the user has preferences stored in124* the sortBy cookie, use those, otherwise use the default.125*/126function initComparator() {127by = 'rating'; // Default to sort by rating.128// If the sortBy cookie is set, use that instead.129if (document.cookie.length > 0) {130var start = document.cookie.indexOf('sortBy=');131if (start != -1) {132start = start + 7;133var end = document.cookie.indexOf(";", start);134if (end == -1) {135end = document.cookie.length;136by = unescape(document.cookie.substring(start, end));137}138}139}140setComparator();141}142143/**144* Show a comment div.145*/146function show(id) {147$('#ao' + id).hide();148$('#ah' + id).show();149var context = $.extend({id: id}, opts);150var popup = $(renderTemplate(popupTemplate, context)).hide();151popup.find('textarea[name="proposal"]').hide();152popup.find('a.by' + by).addClass('sel');153var form = popup.find('#cf' + id);154form.submit(function(event) {155event.preventDefault();156addComment(form);157});158$('#s' + id).after(popup);159popup.slideDown('fast', function() {160getComments(id);161});162}163164/**165* Hide a comment div.166*/167function hide(id) {168$('#ah' + id).hide();169$('#ao' + id).show();170var div = $('#sc' + id);171div.slideUp('fast', function() {172div.remove();173});174}175176/**177* Perform an ajax request to get comments for a node178* and insert the comments into the comments tree.179*/180function getComments(id) {181$.ajax({182type: 'GET',183url: opts.getCommentsURL,184data: {node: id},185success: function(data, textStatus, request) {186var ul = $('#cl' + id);187var speed = 100;188$('#cf' + id)189.find('textarea[name="proposal"]')190.data('source', data.source);191192if (data.comments.length === 0) {193ul.html('<li>No comments yet.</li>');194ul.data('empty', true);195} else {196// If there are comments, sort them and put them in the list.197var comments = sortComments(data.comments);198speed = data.comments.length * 100;199appendComments(comments, ul);200ul.data('empty', false);201}202$('#cn' + id).slideUp(speed + 200);203ul.slideDown(speed);204},205error: function(request, textStatus, error) {206showError('Oops, there was a problem retrieving the comments.');207},208dataType: 'json'209});210}211212/**213* Add a comment via ajax and insert the comment into the comment tree.214*/215function addComment(form) {216var node_id = form.find('input[name="node"]').val();217var parent_id = form.find('input[name="parent"]').val();218var text = form.find('textarea[name="comment"]').val();219var proposal = form.find('textarea[name="proposal"]').val();220221if (text == '') {222showError('Please enter a comment.');223return;224}225226// Disable the form that is being submitted.227form.find('textarea,input').attr('disabled', 'disabled');228229// Send the comment to the server.230$.ajax({231type: "POST",232url: opts.addCommentURL,233dataType: 'json',234data: {235node: node_id,236parent: parent_id,237text: text,238proposal: proposal239},240success: function(data, textStatus, error) {241// Reset the form.242if (node_id) {243hideProposeChange(node_id);244}245form.find('textarea')246.val('')247.add(form.find('input'))248.removeAttr('disabled');249var ul = $('#cl' + (node_id || parent_id));250if (ul.data('empty')) {251$(ul).empty();252ul.data('empty', false);253}254insertComment(data.comment);255var ao = $('#ao' + node_id);256ao.find('img').attr({'src': opts.commentBrightImage});257if (node_id) {258// if this was a "root" comment, remove the commenting box259// (the user can get it back by reopening the comment popup)260$('#ca' + node_id).slideUp();261}262},263error: function(request, textStatus, error) {264form.find('textarea,input').removeAttr('disabled');265showError('Oops, there was a problem adding the comment.');266}267});268}269270/**271* Recursively append comments to the main comment list and children272* lists, creating the comment tree.273*/274function appendComments(comments, ul) {275$.each(comments, function() {276var div = createCommentDiv(this);277ul.append($(document.createElement('li')).html(div));278appendComments(this.children, div.find('ul.comment-children'));279// To avoid stagnating data, don't store the comments children in data.280this.children = null;281div.data('comment', this);282});283}284285/**286* After adding a new comment, it must be inserted in the correct287* location in the comment tree.288*/289function insertComment(comment) {290var div = createCommentDiv(comment);291292// To avoid stagnating data, don't store the comments children in data.293comment.children = null;294div.data('comment', comment);295296var ul = $('#cl' + (comment.node || comment.parent));297var siblings = getChildren(ul);298299var li = $(document.createElement('li'));300li.hide();301302// Determine where in the parents children list to insert this comment.303for(i=0; i < siblings.length; i++) {304if (comp(comment, siblings[i]) <= 0) {305$('#cd' + siblings[i].id)306.parent()307.before(li.html(div));308li.slideDown('fast');309return;310}311}312313// If we get here, this comment rates lower than all the others,314// or it is the only comment in the list.315ul.append(li.html(div));316li.slideDown('fast');317}318319function acceptComment(id) {320$.ajax({321type: 'POST',322url: opts.acceptCommentURL,323data: {id: id},324success: function(data, textStatus, request) {325$('#cm' + id).fadeOut('fast');326$('#cd' + id).removeClass('moderate');327},328error: function(request, textStatus, error) {329showError('Oops, there was a problem accepting the comment.');330}331});332}333334function deleteComment(id) {335$.ajax({336type: 'POST',337url: opts.deleteCommentURL,338data: {id: id},339success: function(data, textStatus, request) {340var div = $('#cd' + id);341if (data == 'delete') {342// Moderator mode: remove the comment and all children immediately343div.slideUp('fast', function() {344div.remove();345});346return;347}348// User mode: only mark the comment as deleted349div350.find('span.user-id:first')351.text('[deleted]').end()352.find('div.comment-text:first')353.text('[deleted]').end()354.find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +355', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)356.remove();357var comment = div.data('comment');358comment.username = '[deleted]';359comment.text = '[deleted]';360div.data('comment', comment);361},362error: function(request, textStatus, error) {363showError('Oops, there was a problem deleting the comment.');364}365});366}367368function showProposal(id) {369$('#sp' + id).hide();370$('#hp' + id).show();371$('#pr' + id).slideDown('fast');372}373374function hideProposal(id) {375$('#hp' + id).hide();376$('#sp' + id).show();377$('#pr' + id).slideUp('fast');378}379380function showProposeChange(id) {381$('#pc' + id).hide();382$('#hc' + id).show();383var textarea = $('#pt' + id);384textarea.val(textarea.data('source'));385$.fn.autogrow.resize(textarea[0]);386textarea.slideDown('fast');387}388389function hideProposeChange(id) {390$('#hc' + id).hide();391$('#pc' + id).show();392var textarea = $('#pt' + id);393textarea.val('').removeAttr('disabled');394textarea.slideUp('fast');395}396397function toggleCommentMarkupBox(id) {398$('#mb' + id).toggle();399}400401/** Handle when the user clicks on a sort by link. */402function handleReSort(link) {403var classes = link.attr('class').split(/\s+/);404for (var i=0; i<classes.length; i++) {405if (classes[i] != 'sort-option') {406by = classes[i].substring(2);407}408}409setComparator();410// Save/update the sortBy cookie.411var expiration = new Date();412expiration.setDate(expiration.getDate() + 365);413document.cookie= 'sortBy=' + escape(by) +414';expires=' + expiration.toUTCString();415$('ul.comment-ul').each(function(index, ul) {416var comments = getChildren($(ul), true);417comments = sortComments(comments);418appendComments(comments, $(ul).empty());419});420}421422/**423* Function to process a vote when a user clicks an arrow.424*/425function handleVote(link) {426if (!opts.voting) {427showError("You'll need to login to vote.");428return;429}430431var id = link.attr('id');432if (!id) {433// Didn't click on one of the voting arrows.434return;435}436// If it is an unvote, the new vote value is 0,437// Otherwise it's 1 for an upvote, or -1 for a downvote.438var value = 0;439if (id.charAt(1) != 'u') {440value = id.charAt(0) == 'u' ? 1 : -1;441}442// The data to be sent to the server.443var d = {444comment_id: id.substring(2),445value: value446};447448// Swap the vote and unvote links.449link.hide();450$('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)451.show();452453// The div the comment is displayed in.454var div = $('div#cd' + d.comment_id);455var data = div.data('comment');456457// If this is not an unvote, and the other vote arrow has458// already been pressed, unpress it.459if ((d.value !== 0) && (data.vote === d.value * -1)) {460$('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();461$('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();462}463464// Update the comments rating in the local data.465data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);466data.vote = d.value;467div.data('comment', data);468469// Change the rating text.470div.find('.rating:first')471.text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));472473// Send the vote information to the server.474$.ajax({475type: "POST",476url: opts.processVoteURL,477data: d,478error: function(request, textStatus, error) {479showError('Oops, there was a problem casting that vote.');480}481});482}483484/**485* Open a reply form used to reply to an existing comment.486*/487function openReply(id) {488// Swap out the reply link for the hide link489$('#rl' + id).hide();490$('#cr' + id).show();491492// Add the reply li to the children ul.493var div = $(renderTemplate(replyTemplate, {id: id})).hide();494$('#cl' + id)495.prepend(div)496// Setup the submit handler for the reply form.497.find('#rf' + id)498.submit(function(event) {499event.preventDefault();500addComment($('#rf' + id));501closeReply(id);502})503.find('input[type=button]')504.click(function() {505closeReply(id);506});507div.slideDown('fast', function() {508$('#rf' + id).find('textarea').focus();509});510}511512/**513* Close the reply form opened with openReply.514*/515function closeReply(id) {516// Remove the reply div from the DOM.517$('#rd' + id).slideUp('fast', function() {518$(this).remove();519});520521// Swap out the hide link for the reply link522$('#cr' + id).hide();523$('#rl' + id).show();524}525526/**527* Recursively sort a tree of comments using the comp comparator.528*/529function sortComments(comments) {530comments.sort(comp);531$.each(comments, function() {532this.children = sortComments(this.children);533});534return comments;535}536537/**538* Get the children comments from a ul. If recursive is true,539* recursively include childrens' children.540*/541function getChildren(ul, recursive) {542var children = [];543ul.children().children("[id^='cd']")544.each(function() {545var comment = $(this).data('comment');546if (recursive)547comment.children = getChildren($(this).find('#cl' + comment.id), true);548children.push(comment);549});550return children;551}552553/** Create a div to display a comment in. */554function createCommentDiv(comment) {555if (!comment.displayed && !opts.moderator) {556return $('<div class="moderate">Thank you! Your comment will show up '557+ 'once it is has been approved by a moderator.</div>');558}559// Prettify the comment rating.560comment.pretty_rating = comment.rating + ' point' +561(comment.rating == 1 ? '' : 's');562// Make a class (for displaying not yet moderated comments differently)563comment.css_class = comment.displayed ? '' : ' moderate';564// Create a div for this comment.565var context = $.extend({}, opts, comment);566var div = $(renderTemplate(commentTemplate, context));567568// If the user has voted on this comment, highlight the correct arrow.569if (comment.vote) {570var direction = (comment.vote == 1) ? 'u' : 'd';571div.find('#' + direction + 'v' + comment.id).hide();572div.find('#' + direction + 'u' + comment.id).show();573}574575if (opts.moderator || comment.text != '[deleted]') {576div.find('a.reply').show();577if (comment.proposal_diff)578div.find('#sp' + comment.id).show();579if (opts.moderator && !comment.displayed)580div.find('#cm' + comment.id).show();581if (opts.moderator || (opts.username == comment.username))582div.find('#dc' + comment.id).show();583}584return div;585}586587/**588* A simple template renderer. Placeholders such as <%id%> are replaced589* by context['id'] with items being escaped. Placeholders such as <#id#>590* are not escaped.591*/592function renderTemplate(template, context) {593var esc = $(document.createElement('div'));594595function handle(ph, escape) {596var cur = context;597$.each(ph.split('.'), function() {598cur = cur[this];599});600return escape ? esc.text(cur || "").html() : cur;601}602603return template.replace(/<([%#])([\w\.]*)\1>/g, function() {604return handle(arguments[2], arguments[1] == '%' ? true : false);605});606}607608/** Flash an error message briefly. */609function showError(message) {610$(document.createElement('div')).attr({'class': 'popup-error'})611.append($(document.createElement('div'))612.attr({'class': 'error-message'}).text(message))613.appendTo('body')614.fadeIn("slow")615.delay(2000)616.fadeOut("slow");617}618619/** Add a link the user uses to open the comments popup. */620$.fn.comment = function() {621return this.each(function() {622var id = $(this).attr('id').substring(1);623var count = COMMENT_METADATA[id];624var title = count + ' comment' + (count == 1 ? '' : 's');625var image = count > 0 ? opts.commentBrightImage : opts.commentImage;626var addcls = count == 0 ? ' nocomment' : '';627$(this)628.append(629$(document.createElement('a')).attr({630href: '#',631'class': 'sphinx-comment-open' + addcls,632id: 'ao' + id633})634.append($(document.createElement('img')).attr({635src: image,636alt: 'comment',637title: title638}))639.click(function(event) {640event.preventDefault();641show($(this).attr('id').substring(2));642})643)644.append(645$(document.createElement('a')).attr({646href: '#',647'class': 'sphinx-comment-close hidden',648id: 'ah' + id649})650.append($(document.createElement('img')).attr({651src: opts.closeCommentImage,652alt: 'close',653title: 'close'654}))655.click(function(event) {656event.preventDefault();657hide($(this).attr('id').substring(2));658})659);660});661};662663var opts = {664processVoteURL: '/_process_vote',665addCommentURL: '/_add_comment',666getCommentsURL: '/_get_comments',667acceptCommentURL: '/_accept_comment',668deleteCommentURL: '/_delete_comment',669commentImage: '/static/_static/comment.png',670closeCommentImage: '/static/_static/comment-close.png',671loadingImage: '/static/_static/ajax-loader.gif',672commentBrightImage: '/static/_static/comment-bright.png',673upArrow: '/static/_static/up.png',674downArrow: '/static/_static/down.png',675upArrowPressed: '/static/_static/up-pressed.png',676downArrowPressed: '/static/_static/down-pressed.png',677voting: false,678moderator: false679};680681if (typeof COMMENT_OPTIONS != "undefined") {682opts = jQuery.extend(opts, COMMENT_OPTIONS);683}684685var popupTemplate = '\686<div class="sphinx-comments" id="sc<%id%>">\687<p class="sort-options">\688Sort by:\689<a href="#" class="sort-option byrating">best rated</a>\690<a href="#" class="sort-option byascage">newest</a>\691<a href="#" class="sort-option byage">oldest</a>\692</p>\693<div class="comment-header">Comments</div>\694<div class="comment-loading" id="cn<%id%>">\695loading comments... <img src="<%loadingImage%>" alt="" /></div>\696<ul id="cl<%id%>" class="comment-ul"></ul>\697<div id="ca<%id%>">\698<p class="add-a-comment">Add a comment\699(<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\700<div class="comment-markup-box" id="mb<%id%>">\701reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \702<tt>``code``</tt>, \703code blocks: <tt>::</tt> and an indented block after blank line</div>\704<form method="post" id="cf<%id%>" class="comment-form" action="">\705<textarea name="comment" cols="80"></textarea>\706<p class="propose-button">\707<a href="#" id="pc<%id%>" class="show-propose-change">\708Propose a change ▹\709</a>\710<a href="#" id="hc<%id%>" class="hide-propose-change">\711Propose a change ▿\712</a>\713</p>\714<textarea name="proposal" id="pt<%id%>" cols="80"\715spellcheck="false"></textarea>\716<input type="submit" value="Add comment" />\717<input type="hidden" name="node" value="<%id%>" />\718<input type="hidden" name="parent" value="" />\719</form>\720</div>\721</div>';722723var commentTemplate = '\724<div id="cd<%id%>" class="sphinx-comment<%css_class%>">\725<div class="vote">\726<div class="arrow">\727<a href="#" id="uv<%id%>" class="vote" title="vote up">\728<img src="<%upArrow%>" />\729</a>\730<a href="#" id="uu<%id%>" class="un vote" title="vote up">\731<img src="<%upArrowPressed%>" />\732</a>\733</div>\734<div class="arrow">\735<a href="#" id="dv<%id%>" class="vote" title="vote down">\736<img src="<%downArrow%>" id="da<%id%>" />\737</a>\738<a href="#" id="du<%id%>" class="un vote" title="vote down">\739<img src="<%downArrowPressed%>" />\740</a>\741</div>\742</div>\743<div class="comment-content">\744<p class="tagline comment">\745<span class="user-id"><%username%></span>\746<span class="rating"><%pretty_rating%></span>\747<span class="delta"><%time.delta%></span>\748</p>\749<div class="comment-text comment"><#text#></div>\750<p class="comment-opts comment">\751<a href="#" class="reply hidden" id="rl<%id%>">reply ▹</a>\752<a href="#" class="close-reply" id="cr<%id%>">reply ▿</a>\753<a href="#" id="sp<%id%>" class="show-proposal">proposal ▹</a>\754<a href="#" id="hp<%id%>" class="hide-proposal">proposal ▿</a>\755<a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\756<span id="cm<%id%>" class="moderation hidden">\757<a href="#" id="ac<%id%>" class="accept-comment">accept</a>\758</span>\759</p>\760<pre class="proposal" id="pr<%id%>">\761<#proposal_diff#>\762</pre>\763<ul class="comment-children" id="cl<%id%>"></ul>\764</div>\765<div class="clearleft"></div>\766</div>\767</div>';768769var replyTemplate = '\770<li>\771<div class="reply-div" id="rd<%id%>">\772<form id="rf<%id%>">\773<textarea name="comment" cols="80"></textarea>\774<input type="submit" value="Add reply" />\775<input type="button" value="Cancel" />\776<input type="hidden" name="parent" value="<%id%>" />\777<input type="hidden" name="node" value="" />\778</form>\779</div>\780</li>';781782$(document).ready(function() {783init();784});785})(jQuery);786787$(document).ready(function() {788// add comment anchors for all paragraphs that are commentable789$('.sphinx-has-comment').comment();790791// highlight search words in search results792$("div.context").each(function() {793var params = $.getQueryParameters();794var terms = (params.q) ? params.q[0].split(/\s+/) : [];795var result = $(this);796$.each(terms, function() {797result.highlightText(this.toLowerCase(), 'highlighted');798});799});800801// directly open comment window if requested802var anchor = document.location.hash;803if (anchor.substring(0, 9) == '#comment-') {804$('#ao' + anchor.substring(9)).click();805document.location.hash = '#s' + anchor.substring(9);806}807});808809810