Skip to content

Commit f7a0538

Browse files
committed
Merge pull request #1507 from rtfd/cleanup-doc-embed-js
Cleanup doc embed js
2 parents 964c7e0 + e907314 commit f7a0538

File tree

15 files changed

+1016
-335
lines changed

15 files changed

+1016
-335
lines changed

readthedocs/api/base.py

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
from readthedocs.builds.models import Build, Version
1919
from readthedocs.core.utils import trigger_build
2020
from readthedocs.projects.models import Project, ImportedFile
21-
from readthedocs.projects.version_handling import highest_version
22-
from readthedocs.projects.version_handling import parse_version_failsafe
21+
from readthedocs.restapi.views.footer_views import get_version_compare_data
2322

2423
from .utils import SearchMixin, PostAuthentication
2524

@@ -144,34 +143,16 @@ def get_object_list(self, request):
144143
self._meta.queryset = Version.objects.api(user=request.user, only_active=False)
145144
return super(VersionResource, self).get_object_list(request)
146145

147-
def version_compare(self, request, **kwargs):
148-
project = get_object_or_404(Project, slug=kwargs['project_slug'])
149-
highest_version_obj, highest_version_comparable = highest_version(
150-
project.versions.filter(active=True))
151-
base = kwargs.get('base', None)
152-
ret_val = {
153-
'project': highest_version_obj,
154-
'version': highest_version_comparable,
155-
'is_highest': True,
156-
}
157-
if highest_version_obj:
158-
ret_val['url'] = highest_version_obj.get_absolute_url()
159-
ret_val['slug'] = highest_version_obj.slug,
146+
def version_compare(self, request, project_slug, base=None, **kwargs):
147+
project = get_object_or_404(Project, slug=project_slug)
160148
if base and base != LATEST:
161149
try:
162-
base_version_obj = project.versions.get(slug=base)
163-
base_version_comparable = parse_version_failsafe(
164-
base_version_obj.verbose_name)
165-
if base_version_comparable:
166-
# This is only place where is_highest can get set. All
167-
# error cases will be set to True, for non- standard
168-
# versions.
169-
ret_val['is_highest'] = (
170-
base_version_comparable >= highest_version_comparable)
171-
else:
172-
ret_val['is_highest'] = True
150+
base_version = project.versions.get(slug=base)
173151
except (Version.DoesNotExist, TypeError):
174-
ret_val['is_highest'] = True
152+
base_version = None
153+
else:
154+
base_version = None
155+
ret_val = get_version_compare_data(project, base_version)
175156
return self.create_response(request, ret_val)
176157

177158
def build_version(self, request, **kwargs):
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
var Build = require('./build').Build;
2+
var rtddata = require('./rtd-data');
3+
var versionCompare = require('./version-compare');
4+
5+
6+
function init() {
7+
var rtd = rtddata.get();
8+
9+
var get_data = {
10+
project: rtd['project'],
11+
version: rtd['version'],
12+
page: rtd['page'],
13+
theme: rtd['theme'],
14+
format: "jsonp",
15+
};
16+
17+
// Crappy heuristic, but people change the theme name on us.
18+
// So we have to do some duck typing.
19+
if ("docroot" in rtd) {
20+
get_data['docroot'] = rtd['docroot'];
21+
}
22+
23+
if ("source_suffix" in rtd) {
24+
get_data['source_suffix'] = rtd['source_suffix'];
25+
}
26+
27+
if (window.location.pathname.indexOf('/projects/') === 0) {
28+
get_data['subproject'] = true;
29+
}
30+
31+
// Get footer HTML from API and inject it into the page.
32+
$.ajax({
33+
url: rtd.api_host + "/api/v2/footer_html/",
34+
crossDomain: true,
35+
xhrFields: {
36+
withCredentials: true,
37+
},
38+
dataType: "jsonp",
39+
data: get_data,
40+
success: function (data) {
41+
versionCompare.init(data.version_compare);
42+
injectFooter(data);
43+
setupBookmarkCSRFToken();
44+
},
45+
error: function () {
46+
console.error('Error loading Read the Docs footer');
47+
}
48+
});
49+
}
50+
51+
52+
function injectFooter(data) {
53+
var build = new Build(rtddata.get());
54+
55+
// If the theme looks like ours, update the existing badge
56+
// otherwise throw a a full one into the page.
57+
if (build.is_rtd_theme()) {
58+
$("div.rst-other-versions").html(data['html']);
59+
} else {
60+
$("body").append(data['html']);
61+
}
62+
63+
if (!data['version_active']) {
64+
$('.rst-current-version').addClass('rst-out-of-date');
65+
} else if (!data['version_supported']) {
66+
//$('.rst-current-version').addClass('rst-active-old-version')
67+
}
68+
69+
// Show promo selectively
70+
if (data.promo && build.show_promo()) {
71+
var promo = new sponsorship.Promo(
72+
data.promo_data.id,
73+
data.promo_data.text,
74+
data.promo_data.link,
75+
data.promo_data.image
76+
)
77+
if (promo) {
78+
promo.display();
79+
}
80+
}
81+
}
82+
83+
84+
function setupBookmarkCSRFToken() {
85+
function csrfSafeMethod(method) {
86+
// these HTTP methods do not require CSRF protection
87+
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
88+
}
89+
90+
$.ajaxSetup({
91+
beforeSend: function(xhr, settings) {
92+
if (!csrfSafeMethod(settings.type)) {
93+
xhr.setRequestHeader("X-CSRFToken", $('a.bookmark[token]').attr('token'));
94+
}
95+
}
96+
});
97+
}
98+
99+
100+
module.exports = {
101+
init: init
102+
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
function init() {
2+
// Add Grok the Docs Client
3+
$.ajax({
4+
url: "https://api.grokthedocs.com/static/javascript/bundle-client.js",
5+
crossDomain: true,
6+
dataType: "script",
7+
});
8+
}
9+
10+
11+
module.exports = {
12+
init: init
13+
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Mkdocs specific JS code.
3+
*/
4+
5+
6+
var rtddata = require('./rtd-data');
7+
8+
9+
function init() {
10+
var rtd = rtddata.get();
11+
12+
// Override MkDocs styles
13+
if ("builder" in rtd && rtd["builder"] == "mkdocs") {
14+
$('<input>').attr({
15+
type: 'hidden',
16+
name: 'project',
17+
value: rtd["project"]
18+
}).appendTo('#rtd-search-form');
19+
$('<input>').attr({
20+
type: 'hidden',
21+
name: 'version',
22+
value: rtd["version"]
23+
}).appendTo('#rtd-search-form');
24+
$('<input>').attr({
25+
type: 'hidden',
26+
name: 'type',
27+
value: 'file'
28+
}).appendTo('#rtd-search-form');
29+
30+
$("#rtd-search-form").prop("action", rtd.api_host + "/elasticsearch/");
31+
32+
// Apply stickynav to mkdocs builds
33+
var nav_bar = $('nav.wy-nav-side:first'),
34+
win = $(window),
35+
sticky_nav_class = 'stickynav',
36+
apply_stickynav = function () {
37+
if (nav_bar.height() <= win.height()) {
38+
nav_bar.addClass(sticky_nav_class);
39+
} else {
40+
nav_bar.removeClass(sticky_nav_class);
41+
}
42+
};
43+
win.on('resize', apply_stickynav);
44+
apply_stickynav();
45+
}
46+
47+
}
48+
49+
50+
module.exports = {
51+
init: init
52+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* This exposes data injected during the RTD build into the template. It's
3+
* provided via the global READTHEDOCS_DATA variable and is exposed here as a
4+
* module for cleaner usage.
5+
*/
6+
7+
8+
/*
9+
* Access READTHEDOCS_DATA on call, not on module load. The reason is that the
10+
* READTHEDOCS_DATA might not be available during script load time.
11+
*/
12+
function get() {
13+
return $.extend({
14+
api_host: 'https://readthedocs.org'
15+
}, window.READTHEDOCS_DATA);
16+
}
17+
18+
19+
module.exports = {
20+
get: get
21+
};
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Sphinx builder specific JS code.
3+
*/
4+
5+
6+
var rtddata = require('./rtd-data');
7+
8+
9+
function init() {
10+
var rtd = rtddata.get();
11+
12+
/// Click tracking on flyout
13+
$(document).on('click', "[data-toggle='rst-current-version']", function() {
14+
var flyout_state = $("[data-toggle='rst-versions']").hasClass('shift-up') ? 'was_open' : 'was_closed'
15+
if (_gaq) {
16+
_gaq.push(
17+
['rtfd._setAccount', 'UA-17997319-1'],
18+
['rtfd._trackEvent', 'Flyout', 'Click', flyout_state]
19+
);
20+
}
21+
});
22+
23+
/// Read the Docs Sphinx theme code
24+
if (!("builder" in rtd) || "builder" in rtd && rtd["builder"] != "mkdocs") {
25+
function toggleCurrent (elem) {
26+
var parent_li = elem.closest('li');
27+
parent_li.siblings('li.current').removeClass('current');
28+
parent_li.siblings().find('li.current').removeClass('current');
29+
parent_li.find('> ul li.current').removeClass('current');
30+
parent_li.toggleClass('current');
31+
}
32+
33+
// Shift nav in mobile when clicking the menu.
34+
$(document).on('click', "[data-toggle='wy-nav-top']", function() {
35+
$("[data-toggle='wy-nav-shift']").toggleClass("shift");
36+
$("[data-toggle='rst-versions']").toggleClass("shift");
37+
});
38+
// Nav menu link click operations
39+
$(document).on('click', ".wy-menu-vertical .current ul li a", function() {
40+
var target = $(this);
41+
// Close menu when you click a link.
42+
$("[data-toggle='wy-nav-shift']").removeClass("shift");
43+
$("[data-toggle='rst-versions']").toggleClass("shift");
44+
// Handle dynamic display of l3 and l4 nav lists
45+
toggleCurrent(target);
46+
if (typeof(window.SphinxRtdTheme) != 'undefined') {
47+
window.SphinxRtdTheme.StickyNav.hashChange();
48+
}
49+
});
50+
$(document).on('click', "[data-toggle='rst-current-version']", function() {
51+
$("[data-toggle='rst-versions']").toggleClass("shift-up");
52+
});
53+
// Make tables responsive
54+
$("table.docutils:not(.field-list)").wrap("<div class='wy-table-responsive'></div>");
55+
56+
// Add expand links to all parents of nested ul
57+
$('.wy-menu-vertical ul').siblings('a').each(function () {
58+
var link = $(this);
59+
expand = $('<span class="toctree-expand"></span>');
60+
expand.on('click', function (ev) {
61+
toggleCurrent(link);
62+
ev.stopPropagation();
63+
return false;
64+
});
65+
link.prepend(expand);
66+
});
67+
68+
// Sphinx theme state
69+
window.SphinxRtdTheme = (function (jquery) {
70+
var stickyNav = (function () {
71+
var navBar,
72+
win,
73+
winScroll = false,
74+
linkScroll = false,
75+
winPosition = 0,
76+
enable = function () {
77+
init();
78+
reset();
79+
win.on('hashchange', reset);
80+
81+
// Set scrolling
82+
win.on('scroll', function () {
83+
if (!linkScroll) {
84+
winScroll = true;
85+
}
86+
});
87+
setInterval(function () {
88+
if (winScroll) {
89+
winScroll = false;
90+
var newWinPosition = win.scrollTop(),
91+
navPosition = navBar.scrollTop(),
92+
newNavPosition = navPosition + (newWinPosition - winPosition);
93+
navBar.scrollTop(newNavPosition);
94+
winPosition = newWinPosition;
95+
}
96+
}, 25);
97+
},
98+
init = function () {
99+
navBar = jquery('nav.wy-nav-side:first');
100+
win = jquery(window);
101+
},
102+
reset = function () {
103+
// Get anchor from URL and open up nested nav
104+
var anchor = encodeURI(window.location.hash);
105+
if (anchor) {
106+
try {
107+
var link = $('.wy-menu-vertical')
108+
.find('[href="' + anchor + '"]');
109+
$('.wy-menu-vertical li.toctree-l1 li.current')
110+
.removeClass('current');
111+
link.closest('li.toctree-l2').addClass('current');
112+
link.closest('li.toctree-l3').addClass('current');
113+
link.closest('li.toctree-l4').addClass('current');
114+
}
115+
catch (err) {
116+
console.log("Error expanding nav for anchor", err);
117+
}
118+
}
119+
},
120+
hashChange = function () {
121+
linkScroll = true;
122+
win.one('hashchange', function () {
123+
linkScroll = false;
124+
});
125+
};
126+
jquery(init);
127+
return {
128+
enable: enable,
129+
hashChange: hashChange
130+
};
131+
}());
132+
return {
133+
StickyNav: stickyNav
134+
};
135+
}($));
136+
}
137+
138+
}
139+
140+
141+
module.exports = {
142+
init: init
143+
};

0 commit comments

Comments
 (0)