From b80b4a31fa12005312d9206124faf33b8015d157 Mon Sep 17 00:00:00 2001 From: Tobias Kunze Date: Thu, 9 Mar 2017 15:08:57 +0100 Subject: [PATCH 001/190] Fix page redirect preview It included '//' - this ought to fix #2380. --- readthedocs/templates/projects/project_redirects.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/readthedocs/templates/projects/project_redirects.html b/readthedocs/templates/projects/project_redirects.html index 7bfc33a8cf2..d82a4b20904 100644 --- a/readthedocs/templates/projects/project_redirects.html +++ b/readthedocs/templates/projects/project_redirects.html @@ -22,8 +22,12 @@ redirect_target = "/$lang/$version/faq.html"; } else if (option === "page" ) { - redirect_from = "/$lang/$version/" + field_from_url.val(); - redirect_target = "/$lang/$version/" + field_to_url.val(); + field_from = field_from_url.val(); + field_to = field_to_url.val(); + field_from_absolute = (field_from.length > 0) && (field_from[0] === "/"); + field_to_absolute = (field_to.length > 0) && (field_to[0] === "/"); + redirect_from = "/$lang/$version" + (field_from_absolute ? "" : "/") + field_from; + redirect_target = "/$lang/$version" + (field_to_absolute ? "" : "/") + field_to; } else if (option === "exact" ) { redirect_from = field_from_url.val(); From 9130f3875281367e5a17a57e8516b2ffda615fa6 Mon Sep 17 00:00:00 2001 From: Matt Wheeler Date: Mon, 10 Apr 2017 15:02:53 +0100 Subject: [PATCH 002/190] check for matching alias before subproject slug fixes #2731 --- readthedocs/core/views/serve.py | 20 +++++++------ readthedocs/rtd_tests/tests/test_resolver.py | 30 +++++++++++++++++++ .../rtd_tests/tests/test_subprojects.py | 17 +++++++++-- 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/readthedocs/core/views/serve.py b/readthedocs/core/views/serve.py index 09f663015c7..bf6d2e9e385 100644 --- a/readthedocs/core/views/serve.py +++ b/readthedocs/core/views/serve.py @@ -56,17 +56,19 @@ def map_subproject_slug(view_func): @wraps(view_func) def inner_view(request, subproject=None, subproject_slug=None, *args, **kwargs): if subproject is None and subproject_slug: + # Try to fetch by subproject alias first, otherwise we might end up + # redirected to an unrelated project. try: - subproject = Project.objects.get(slug=subproject_slug) - except Project.DoesNotExist: + # Depends on a project passed into kwargs + rel = ProjectRelationship.objects.get( + parent=kwargs['project'], + alias=subproject_slug, + ) + subproject = rel.child + except (ProjectRelationship.DoesNotExist, KeyError): try: - # Depends on a project passed into kwargs - rel = ProjectRelationship.objects.get( - parent=kwargs['project'], - alias=subproject_slug, - ) - subproject = rel.child - except (ProjectRelationship.DoesNotExist, KeyError): + subproject = Project.objects.get(slug=subproject_slug) + except Project.DoesNotExist: raise Http404 return view_func(request, subproject=subproject, *args, **kwargs) return inner_view diff --git a/readthedocs/rtd_tests/tests/test_resolver.py b/readthedocs/rtd_tests/tests/test_resolver.py index 1c67cf11735..df1fd7b536f 100644 --- a/readthedocs/rtd_tests/tests/test_resolver.py +++ b/readthedocs/rtd_tests/tests/test_resolver.py @@ -385,3 +385,33 @@ def test_resolver_public_domain_overrides(self): self.assertEqual(url, 'http://docs.foobar.com/en/latest/') url = resolve(project=self.pip, private=False) self.assertEqual(url, 'http://docs.foobar.com/en/latest/') + + +class ResolverAltSetUp(object): + + def setUp(self): + with mock.patch('readthedocs.projects.models.broadcast'): + with mock.patch('readthedocs.projects.models.update_static_metadata'): + self.owner = create_user(username='owner', password='test') + self.tester = create_user(username='tester', password='test') + self.pip = get(Project, slug='pip', users=[self.owner], main_language_project=None) + self.seed = get(Project, slug='sub', users=[self.owner], main_language_project=None) + self.subproject = get(Project, slug='subproject', language='ja', users=[self.owner], main_language_project=None) + self.translation = get(Project, slug='trans', language='ja', users=[self.owner], main_language_project=None) + self.pip.add_subproject(self.subproject, alias='sub') + self.pip.translations.add(self.translation) + + +@override_settings(PUBLIC_DOMAIN='readthedocs.org') +class ResolverDomainTestsAlt(ResolverAltSetUp, ResolverDomainTests): + pass + + +@override_settings(PUBLIC_DOMAIN='readthedocs.org') +class SmartResolverPathTestsAlt(ResolverAltSetUp, SmartResolverPathTests): + pass + + +@override_settings(PUBLIC_DOMAIN='readthedocs.org') +class ResolverTestsAlt(ResolverAltSetUp, ResolverTests): + pass diff --git a/readthedocs/rtd_tests/tests/test_subprojects.py b/readthedocs/rtd_tests/tests/test_subprojects.py index d2e63dcd88b..0bf378a237f 100644 --- a/readthedocs/rtd_tests/tests/test_subprojects.py +++ b/readthedocs/rtd_tests/tests/test_subprojects.py @@ -77,12 +77,14 @@ def setUp(self): self.owner], main_language_project=None) self.pip.add_subproject(self.subproject) self.pip.translations.add(self.translation) - - @override_settings(PRODUCTION_DOMAIN='readthedocs.org') - def test_resolver_subproject_alias(self): relation = self.pip.subprojects.first() relation.alias = 'sub_alias' relation.save() + get(Project, slug='sub_alias', language='ya') + + + @override_settings(PRODUCTION_DOMAIN='readthedocs.org') + def test_resolver_subproject_alias(self): with override_settings(USE_SUBDOMAIN=False): resp = self.client.get('/docs/pip/projects/sub_alias/') self.assertEqual(resp.status_code, 302) @@ -90,3 +92,12 @@ def test_resolver_subproject_alias(self): resp._headers['location'][1], 'http://readthedocs.org/docs/pip/projects/sub_alias/ja/latest/' ) + + def test_resolver_subproject_subdomain_alias(self): + with override_settings(USE_SUBDOMAIN=True): + resp = self.client.get('/projects/sub_alias/', HTTP_HOST='pip.readthedocs.org') + self.assertEqual(resp.status_code, 302) + self.assertEqual( + resp._headers['location'][1], + 'http://pip.readthedocs.org/projects/sub_alias/ja/latest/' + ) From c3d2ddc2847e4c17b27269db5605731f510af8ee Mon Sep 17 00:00:00 2001 From: Matt Wheeler Date: Thu, 26 Oct 2017 12:18:34 +0100 Subject: [PATCH 003/190] Address PR comments --- .../rtd_tests/tests/test_subprojects.py | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/readthedocs/rtd_tests/tests/test_subprojects.py b/readthedocs/rtd_tests/tests/test_subprojects.py index f3e83513510..59f4b2b3633 100644 --- a/readthedocs/rtd_tests/tests/test_subprojects.py +++ b/readthedocs/rtd_tests/tests/test_subprojects.py @@ -165,21 +165,23 @@ def setUp(self): fixture.get(Project, slug='sub_alias', language='ya') - @override_settings(PRODUCTION_DOMAIN='readthedocs.org') - def test_resolver_subproject_alias(self): - with override_settings(USE_SUBDOMAIN=False): - resp = self.client.get('/docs/pip/projects/sub_alias/') - self.assertEqual(resp.status_code, 302) - self.assertEqual( - resp._headers['location'][1], - 'http://readthedocs.org/docs/pip/projects/sub_alias/ja/latest/' + @override_settings( + PRODUCTION_DOMAIN='readthedocs.org', + USE_SUBDOMAIN=False, ) + def test_resolver_subproject_alias(self): + resp = self.client.get('/docs/pip/projects/sub_alias/') + self.assertEqual(resp.status_code, 302) + self.assertEqual( + resp._headers['location'][1], + 'http://readthedocs.org/docs/pip/projects/sub_alias/ja/latest/' + ) + @override_settings(USE_SUBDOMAIN=True) def test_resolver_subproject_subdomain_alias(self): - with override_settings(USE_SUBDOMAIN=True): - resp = self.client.get('/projects/sub_alias/', HTTP_HOST='pip.readthedocs.org') - self.assertEqual(resp.status_code, 302) - self.assertEqual( - resp._headers['location'][1], - 'http://pip.readthedocs.org/projects/sub_alias/ja/latest/' - ) + resp = self.client.get('/projects/sub_alias/', HTTP_HOST='pip.readthedocs.org') + self.assertEqual(resp.status_code, 302) + self.assertEqual( + resp._headers['location'][1], + 'http://pip.readthedocs.org/projects/sub_alias/ja/latest/' + ) From d2d4a1e05c9dda8ce3fffb37d8b8016574bb2a70 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Wed, 3 Jan 2018 19:18:12 -0500 Subject: [PATCH 004/190] Improve "Sharing" docs --- docs/business/sharing.rst | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/docs/business/sharing.rst b/docs/business/sharing.rst index 2700f703a4f..8c37a8133fe 100644 --- a/docs/business/sharing.rst +++ b/docs/business/sharing.rst @@ -4,26 +4,39 @@ Sharing .. note:: This feature only exists on our Business offering at `readthedocs.com `_. You can share your project with users outside of your company. -This works by sending them a link, -which will allow them to view a specific project inside your company. +There are two way to do this: + +* by sending them a *secret link*, +* by giving them a *password*. + +These methods will allow them to view a specific project inside your company. Enabling ~~~~~~~~ -* Go into your *Project Admin* page and to the *Sharing* link. -* Under the *Add Token* heading, add a *Description* so you remember who you're sharing it with. -* Click *Share* to create. -* Copy the link that is generated, and give that to the person who you want to give access. +* Go into your *Project Admin* page and to the *Sharing* menu. +* Under the *Share with someone new* heading, select the way you prefer (secret link or password), add an expiration date and a *Description* so you remember who you're sharing it with. +* Click *Share!* to create. +* Get the info needed to share your documentation with other users: + * If you have selected secret link, copy the link that is generated + * In case of password, copy the link and password +* Give that information to the person who you want to give access. .. note:: You can always revoke access in the same panel. Effects ~~~~~~~ +Secret Link +*********** + Once the person you send the link to clicks the link, they will have access to view your project. -It will only work for the specific browser that they click the link from. -.. warning:: They will be able to share this token with other people, - so only share with people you trust. - We only let sharing links be activated **five** times to prevent abuse. +Password +******** + +Once the person you send the link to clicks on the link, they will see +a *Authorization required* page asking them for the password you +generated. When the user enters the password, they will have access to +view your project. From a4bb8e3db4e73b4a40cd9ea8da90e1303cb8d771 Mon Sep 17 00:00:00 2001 From: Matt Wheeler Date: Fri, 12 Jan 2018 19:17:35 +0000 Subject: [PATCH 005/190] use get_object_or_404 shortcut --- readthedocs/core/views/serve.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/readthedocs/core/views/serve.py b/readthedocs/core/views/serve.py index db0ef091d66..becd40953d4 100644 --- a/readthedocs/core/views/serve.py +++ b/readthedocs/core/views/serve.py @@ -27,7 +27,7 @@ from __future__ import absolute_import from django.conf import settings from django.http import HttpResponse, HttpResponseRedirect, Http404 -from django.shortcuts import render_to_response +from django.shortcuts import get_object_or_404, render_to_response from django.template import RequestContext from django.views.static import serve @@ -67,10 +67,7 @@ def inner_view(request, subproject=None, subproject_slug=None, *args, **kwargs): ) subproject = rel.child except (ProjectRelationship.DoesNotExist, KeyError): - try: - subproject = Project.objects.get(slug=subproject_slug) - except Project.DoesNotExist: - raise Http404 + get_object_or_404(Project, slug=subproject_slug) return view_func(request, subproject=subproject, *args, **kwargs) return inner_view From 83b4b4ab3ae54a45987bf9c6cb28fb3f99ded9c4 Mon Sep 17 00:00:00 2001 From: Oliver Bristow Date: Fri, 29 Dec 2017 11:44:13 +0000 Subject: [PATCH 006/190] Document creation of slumber user This is a quick edit to give people more information as they come into this. --- docs/install.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/install.rst b/docs/install.rst index 242b884d51e..d74d65c9b6b 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -126,6 +126,9 @@ By now, it is the right time to load in a couple users and a test project:: If you do not opt to install test data, you'll need to create an account for API use and set ``SLUMBER_USERNAME`` and ``SLUMBER_PASSWORD`` in order for everything to work properly. + This can be done by using ``createsuperuser``, then attempting a manual login to + create an ``EmailAddress`` entry for the user, then you can use ``shell_plus`` to + update the object with ``primary=True``, ``verified=True``. Finally, you're ready to start the webserver:: From 9bb0f28d778e6adcd3a70cd04f5a56c45e4ae83e Mon Sep 17 00:00:00 2001 From: Matt Wheeler Date: Thu, 18 Jan 2018 19:28:20 +0000 Subject: [PATCH 007/190] revert style changes (where did they even come from?) --- readthedocs/rtd_tests/tests/test_subprojects.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/readthedocs/rtd_tests/tests/test_subprojects.py b/readthedocs/rtd_tests/tests/test_subprojects.py index 59f4b2b3633..485eb9b9228 100644 --- a/readthedocs/rtd_tests/tests/test_subprojects.py +++ b/readthedocs/rtd_tests/tests/test_subprojects.py @@ -152,10 +152,12 @@ def setUp(self): self.owner = create_user(username='owner', password='test') self.tester = create_user(username='tester', password='test') self.pip = fixture.get(Project, slug='pip', users=[self.owner], main_language_project=None) - self.subproject = fixture.get(Project, slug='sub', language='ja', users=[ - self.owner], main_language_project=None) - self.translation = fixture.get(Project, slug='trans', language='ja', users=[ - self.owner], main_language_project=None) + self.subproject = fixture.get(Project, slug='sub', language='ja', + users=[ self.owner], + main_language_project=None) + self.translation = fixture.get(Project, slug='trans', language='ja', + users=[ self.owner], + main_language_project=None) self.pip.add_subproject(self.subproject) self.pip.translations.add(self.translation) From 828ec8a10bc9b53034f868577ef71de96ab47f41 Mon Sep 17 00:00:00 2001 From: aasis21 Date: Sun, 18 Feb 2018 20:04:42 +0530 Subject: [PATCH 008/190] fixed formatting buttons in edit project text editor --- media/lib/markitup/jquery.markitup.js | 280 ++++++++++++------ media/lib/markitup/jquery.markitup.pack.js | 10 +- media/lib/markitup/sets/sphinx/editor.css | 38 ++- media/lib/markitup/sets/sphinx/editor.js | 89 +++--- .../templates/projects/project_edit.html | 2 +- 5 files changed, 272 insertions(+), 147 deletions(-) diff --git a/media/lib/markitup/jquery.markitup.js b/media/lib/markitup/jquery.markitup.js index ee8f40faa46..eb4c1a0f1bd 100644 --- a/media/lib/markitup/jquery.markitup.js +++ b/media/lib/markitup/jquery.markitup.js @@ -1,9 +1,9 @@ // ---------------------------------------------------------------------------- // markItUp! Universal MarkUp Engine, JQuery plugin -// v 1.1.7 +// v 1.1.x // Dual licensed under the MIT and GPL licenses. // ---------------------------------------------------------------------------- -// Copyright (C) 2007-2010 Jay Salvat +// Copyright (C) 2007-2012 Jay Salvat // http://markitup.jaysalvat.com/ // ---------------------------------------------------------------------------- // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -12,10 +12,10 @@ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -26,16 +26,23 @@ // ---------------------------------------------------------------------------- (function($) { $.fn.markItUp = function(settings, extraSettings) { - var options, ctrlKey, shiftKey, altKey; - ctrlKey = shiftKey = altKey = false; + var method, params, options, ctrlKey, shiftKey, altKey; ctrlKey = shiftKey = altKey = false; + + if (typeof settings == 'string') { + method = settings; + params = extraSettings; + } options = { id: '', nameSpace: '', root: '', + previewHandler: false, previewInWindow: '', // 'width=800, height=600, resizable=yes, scrollbars=yes' + previewInElement: '', previewAutoRefresh: true, previewPosition: 'after', previewTemplatePath: '~/templates/preview.html', + previewParser: false, previewParserPath: '', previewParserVar: 'data', resizeHandle: true, @@ -59,6 +66,35 @@ }); } + // Quick patch to keep compatibility with jQuery 1.9 + var uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + var matched = uaMatch( navigator.userAgent ); + var browser = {}; + + if (matched.browser) { + browser[matched.browser] = true; + browser.version = matched.version; + } + if (browser.chrome) { + browser.webkit = true; + } else if (browser.webkit) { + browser.safari = true; + } + return this.each(function() { var $$, textarea, levels, scrollPosition, caretPosition, caretOffset, clicked, hash, header, footer, previewWindow, template, iFrame, abort; @@ -72,6 +108,20 @@ options.previewParserPath = localize(options.previewParserPath); options.previewTemplatePath = localize(options.previewTemplatePath); + if (method) { + switch(method) { + case 'remove': + remove(); + break; + case 'insert': + markup(params); + break; + default: + $.error('Method ' + method + ' does not exist on jQuery.markItUp'); + } + return; + } + // apply the computed path to ~/ function localize(data, inText) { if (inText) { @@ -105,29 +155,29 @@ footer = $('
').insertAfter($$); // add the resize handle after textarea - if (options.resizeHandle === true && $.browser.safari !== true) { + if (options.resizeHandle === true && browser.safari !== true) { resizeHandle = $('
') .insertAfter($$) - .bind("mousedown", function(e) { + .bind("mousedown.markItUp", function(e) { var h = $$.height(), y = e.clientY, mouseMove, mouseUp; mouseMove = function(e) { $$.css("height", Math.max(20, e.clientY+h-y)+"px"); return false; }; mouseUp = function(e) { - $("html").unbind("mousemove", mouseMove).unbind("mouseup", mouseUp); + $("html").unbind("mousemove.markItUp", mouseMove).unbind("mouseup.markItUp", mouseUp); return false; }; - $("html").bind("mousemove", mouseMove).bind("mouseup", mouseUp); + $("html").bind("mousemove.markItUp", mouseMove).bind("mouseup.markItUp", mouseUp); }); footer.append(resizeHandle); } // listen key events - $$.keydown(keyPressed).keyup(keyPressed); - + $$.bind('keydown.markItUp', keyPressed).bind('keyup', keyPressed); + // bind an event to catch external calls - $$.bind("insertion", function(e, settings) { + $$.bind("insertion.markItUp", function(e, settings) { if (settings.target !== false) { get(); } @@ -137,9 +187,13 @@ }); // remember the last focus - $$.focus(function() { + $$.bind('focus.markItUp', function() { $.markItUp.focused = this; }); + + if (options.previewInElement) { + refreshPreview(); + } } // recursively build header with dropMenus from markupset @@ -158,32 +212,33 @@ t += levels[j]+"-"; } li = $('
  • '+(button.name||'')+'
  • ') - .bind("contextmenu", function() { // prevent contextmenu on mac and allow ctrl+click - return false; - }).click(function() { + .bind("contextmenu.markItUp", function() { // prevent contextmenu on mac and allow ctrl+click return false; - }).mousedown(function() { + }).bind('click.markItUp', function(e) { + e.preventDefault(); + }).bind("focusin.markItUp", function(){ + $$.focus(); + }).bind('mouseup', function() { if (button.call) { eval(button.call)(); } setTimeout(function() { markup(button) },1); return false; - }).hover(function() { + }).bind('mouseenter.markItUp', function() { $('> ul', this).show(); $(document).one('click', function() { // close dropmenu if click outside $('ul ul', header).hide(); } ); - }, function() { + }).bind('mouseleave.markItUp', function() { $('> ul', this).hide(); - } - ).appendTo(ul); + }).appendTo(ul); if (button.dropMenu) { levels.push(i); $(li).addClass('markItUpDropMenu').append(dropMenus(button.dropMenu)); } } - }); + }); levels.pop(); return ul; } @@ -231,22 +286,49 @@ // build block to insert function build(string) { - openWith = prepare(clicked.openWith); - placeHolder = prepare(clicked.placeHolder); - replaceWith = prepare(clicked.replaceWith); - closeWith = prepare(clicked.closeWith); + var openWith = prepare(clicked.openWith); + var placeHolder = prepare(clicked.placeHolder); + var replaceWith = prepare(clicked.replaceWith); + var closeWith = prepare(clicked.closeWith); + var openBlockWith = prepare(clicked.openBlockWith); + var closeBlockWith = prepare(clicked.closeBlockWith); + var multiline = clicked.multiline; + if (replaceWith !== "") { block = openWith + replaceWith + closeWith; } else if (selection === '' && placeHolder !== '') { block = openWith + placeHolder + closeWith; } else { - block = openWith + (string||selection) + closeWith; + string = string || selection; + + var lines = [string], blocks = []; + + if (multiline === true) { + lines = string.split(/\r?\n/); + } + + for (var l = 0; l < lines.length; l++) { + line = lines[l]; + var trailingSpaces; + if (trailingSpaces = line.match(/ *$/)) { + blocks.push(openWith + line.replace(/ *$/g, '') + closeWith + trailingSpaces); + } else { + blocks.push(openWith + line + closeWith); + } + } + + block = blocks.join("\n"); } - return { block:block, - openWith:openWith, - replaceWith:replaceWith, + + block = openBlockWith + block + closeBlockWith; + + return { block:block, + openBlockWith:openBlockWith, + openWith:openWith, + replaceWith:replaceWith, placeHolder:placeHolder, - closeWith:closeWith + closeWith:closeWith, + closeBlockWith:closeBlockWith }; } @@ -255,26 +337,25 @@ var len, j, n, i; hash = clicked = button; get(); - - $.extend(hash, { line:"", + $.extend(hash, { line:"", root:options.root, - textarea:textarea, - selection:(selection||''), + textarea:textarea, + selection:(selection||''), caretPosition:caretPosition, - ctrlKey:ctrlKey, - shiftKey:shiftKey, + ctrlKey:ctrlKey, + shiftKey:shiftKey, altKey:altKey } ); // callbacks before insertion prepare(options.beforeInsert); prepare(clicked.beforeInsert); - if (ctrlKey === true && shiftKey === true) { + if ((ctrlKey === true && shiftKey === true) || button.multiline === true) { prepare(clicked.beforeMultiInsert); - } + } $.extend(hash, { line:1 }); - - if (ctrlKey === true && shiftKey === true) { + + if ((ctrlKey === true && shiftKey === true)) { lines = selection.split(/\r?\n/); for (j = 0, n = lines.length, i = 0; i < n; i++) { if ($.trim(lines[i]) !== '') { @@ -284,13 +365,15 @@ lines[i] = ""; } } + string = { block:lines.join('\n')}; start = caretPosition; - len = string.block.length + (($.browser.opera) ? n : 0); + len = string.block.length + ((browser.opera) ? n-1 : 0); } else if (ctrlKey === true) { string = build(selection); start = caretPosition + string.openWith.length; len = string.block.length - string.openWith.length - string.closeWith.length; + len = len - (string.block.match(/ $/) ? 1 : 0); len -= fixIeBug(string.block); } else if (shiftKey === true) { string = build(selection); @@ -305,9 +388,9 @@ } if ((selection === '' && string.replaceWith === '')) { caretOffset += fixOperaBug(string.block); - - start = caretPosition + string.openWith.length; - len = string.block.length - string.openWith.length - string.closeWith.length; + + start = caretPosition + string.openBlockWith.length + string.openWith.length; + len = string.block.length - string.openBlockWith.length - string.openWith.length - string.closeWith.length - string.closeBlockWith.length; caretOffset = $$.val().substring(caretPosition, $$.val().length).length; caretOffset -= fixOperaBug($$.val().substring(0, caretPosition)); @@ -325,7 +408,7 @@ $.extend(hash, { line:'', selection:selection }); // callbacks after insertion - if (ctrlKey === true && shiftKey === true) { + if ((ctrlKey === true && shiftKey === true) || button.multiline === true) { prepare(clicked.afterMultiInsert); } prepare(clicked.afterInsert); @@ -333,35 +416,35 @@ // refresh preview if opened if (previewWindow && options.previewAutoRefresh) { - refreshPreview(); + refreshPreview(); } - + // reinit keyevent shiftKey = altKey = ctrlKey = abort = false; } // Substract linefeed in Opera function fixOperaBug(string) { - if ($.browser.opera) { + if (browser.opera) { return string.length - string.replace(/\n*/g, '').length; } return 0; } // Substract linefeed in IE function fixIeBug(string) { - if ($.browser.msie) { + if (browser.msie) { return string.length - string.replace(/\r*/g, '').length; } return 0; } - + // add markup - function insert(block) { + function insert(block) { if (document.selection) { var newSelection = document.selection.createRange(); newSelection.text = block; } else { - $$.val($$.val().substring(0, caretPosition) + block + $$.val().substring(caretPosition + selection.length, $$.val().length)); + textarea.value = textarea.value.substring(0, caretPosition) + block + textarea.value.substring(caretPosition + selection.length, textarea.value.length); } } @@ -369,13 +452,13 @@ function set(start, len) { if (textarea.createTextRange){ // quick fix to make it work on Opera 9.5 - if ($.browser.opera && $.browser.version >= 9.5 && len == 0) { + if (browser.opera && browser.version >= 9.5 && len == 0) { return false; } range = textarea.createTextRange(); range.collapse(true); - range.moveStart('character', start); - range.moveEnd('character', len); + range.moveStart('character', start); + range.moveEnd('character', len); range.select(); } else if (textarea.setSelectionRange ){ textarea.setSelectionRange(start, start + len); @@ -391,11 +474,11 @@ scrollPosition = textarea.scrollTop; if (document.selection) { selection = document.selection.createRange().text; - if ($.browser.msie) { // ie + if (browser.msie) { // ie var range = document.selection.createRange(), rangeCopy = range.duplicate(); rangeCopy.moveToElementText(textarea); caretPosition = -1; - while(rangeCopy.inRange(range)) { // fix most of the ie bugs with linefeeds... + while(rangeCopy.inRange(range)) { rangeCopy.moveStart('character'); caretPosition ++; } @@ -404,27 +487,34 @@ } } else { // gecko & webkit caretPosition = textarea.selectionStart; - selection = $$.val().substring(caretPosition, textarea.selectionEnd); - } + + selection = textarea.value.substring(caretPosition, textarea.selectionEnd); + } return selection; } // open preview window function preview() { - if (!previewWindow || previewWindow.closed) { + if (typeof options.previewHandler === 'function') { + previewWindow = true; + } else if (options.previewInElement) { + previewWindow = $(options.previewInElement); + } else if (!previewWindow || previewWindow.closed) { if (options.previewInWindow) { previewWindow = window.open('', 'preview', options.previewInWindow); + $(window).unload(function() { + previewWindow.close(); + }); } else { iFrame = $(''); if (options.previewPosition == 'after') { iFrame.insertAfter(footer); } else { iFrame.insertBefore(header); - } + } previewWindow = iFrame[iFrame.length - 1].contentWindow || frame[iFrame.length - 1]; } } else if (altKey === true) { - // Thx Stephen M. Redd for the IE8 fix if (iFrame) { iFrame.remove(); } else { @@ -433,7 +523,10 @@ previewWindow = iFrame = false; } if (!options.previewAutoRefresh) { - refreshPreview(); + refreshPreview(); + } + if (options.previewInWindow) { + previewWindow.focus(); } } @@ -442,60 +535,68 @@ renderPreview(); } - function renderPreview() { + function renderPreview() { var phtml; - if (options.previewParserPath !== '') { - $.ajax( { + if (options.previewHandler && typeof options.previewHandler === 'function') { + options.previewHandler( $$.val() ); + } else if (options.previewParser && typeof options.previewParser === 'function') { + var data = options.previewParser( $$.val() ); + writeInPreview(localize(data, 1) ); + } else if (options.previewParserPath !== '') { + $.ajax({ type: 'POST', + dataType: 'text', + global: false, url: options.previewParserPath, data: options.previewParserVar+'='+encodeURIComponent($$.val()), success: function(data) { - writeInPreview( localize(data, 1) ); + writeInPreview( localize(data, 1) ); } - } ); + }); } else { if (!template) { - $.ajax( { + $.ajax({ url: options.previewTemplatePath, + dataType: 'text', + global: false, success: function(data) { writeInPreview( localize(data, 1).replace(//g, $$.val()) ); } - } ); + }); } } return false; } - + function writeInPreview(data) { - if (previewWindow.document) { + if (options.previewInElement) { + $(options.previewInElement).html(data); + } else if (previewWindow && previewWindow.document) { try { sp = previewWindow.document.documentElement.scrollTop } catch(e) { sp = 0; - } + } previewWindow.document.open(); previewWindow.document.write(data); previewWindow.document.close(); previewWindow.document.documentElement.scrollTop = sp; } - if (options.previewInWindow) { - previewWindow.focus(); - } } - + // set keys pressed - function keyPressed(e) { + function keyPressed(e) { shiftKey = e.shiftKey; altKey = e.altKey; - ctrlKey = (!(e.altKey && e.ctrlKey)) ? e.ctrlKey : false; + ctrlKey = (!(e.altKey && e.ctrlKey)) ? (e.ctrlKey || e.metaKey) : false; if (e.type === 'keydown') { if (ctrlKey === true) { - li = $("a[accesskey="+String.fromCharCode(e.keyCode)+"]", header).parent('li'); + li = $('a[accesskey="'+((e.keyCode == 13) ? '\\n' : String.fromCharCode(e.keyCode))+'"]', header).parent('li'); if (li.length !== 0) { ctrlKey = false; setTimeout(function() { - li.triggerHandler('mousedown'); + li.triggerHandler('mouseup'); },1); return false; } @@ -515,8 +616,8 @@ } } if (e.keyCode === 9) { // Tab key - if (shiftKey == true || ctrlKey == true || altKey == true) { // Thx Dr Floob. - return false; + if (shiftKey == true || ctrlKey == true || altKey == true) { + return false; } if (caretOffset !== -1) { get(); @@ -532,14 +633,19 @@ } } + function remove() { + $$.unbind(".markItUp").removeClass('markItUpEditor'); + $$.parent('div').parent('div.markItUp').parent('div').replaceWith($$); + $$.data('markItUp', null); + } + init(); }); }; $.fn.markItUpRemove = function() { return this.each(function() { - var $$ = $(this).unbind().removeClass('markItUpEditor'); - $$.parent('div').parent('div.markItUp').parent('div').replaceWith($$); + $(this).markItUp('remove'); } ); }; diff --git a/media/lib/markitup/jquery.markitup.pack.js b/media/lib/markitup/jquery.markitup.pack.js index cbe46f739bb..16e1d48e52a 100644 --- a/media/lib/markitup/jquery.markitup.pack.js +++ b/media/lib/markitup/jquery.markitup.pack.js @@ -1,9 +1 @@ -// ---------------------------------------------------------------------------- -// markItUp! Universal MarkUp Engine, JQuery plugin -// v 1.1.7 -// Dual licensed under the MIT and GPL licenses. -// ---------------------------------------------------------------------------- -// Copyright (C) 2007-2010 Jay Salvat -// http://markitup.jaysalvat.com/ -// ---------------------------------------------------------------------------- -eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(3($){$.23.T=3(f,g){B k,v,A,F;v=A=F=l;k={D:\'\',12:\'\',U:\'\',1j:\'\',1y:7,24:\'25\',1k:\'~/2R/1z.1A\',1b:\'\',26:\'27\',1l:7,1B:\'\',1C:\'\',1D:{},1E:{},1F:{},1G:{},28:[{}]};$.V(k,f,g);2(!k.U){$(\'2S\').1c(3(a,b){1H=$(b).14(0).2T.2U(/(.*)2V\\.2W(\\.2X)?\\.2Y$/);2(1H!==29){k.U=1H[1]}})}4 G.1c(3(){B d,u,15,16,p,H,L,P,17,1m,w,2a,M,18;d=$(G);u=G;15=[];18=l;16=p=0;H=-1;k.1b=1d(k.1b);k.1k=1d(k.1k);3 1d(a,b){2(b){4 a.W(/("|\')~\\//g,"$1"+k.U)}4 a.W(/^~\\//,k.U)}3 2b(){D=\'\';12=\'\';2(k.D){D=\'D="\'+k.D+\'"\'}8 2(d.1I("D")){D=\'D="T\'+(d.1I("D").2c(0,1).2Z())+(d.1I("D").2c(1))+\'"\'}2(k.12){12=\'N="\'+k.12+\'"\'}d.1J(\'\');d.1J(\'\');d.1J(\'\');d.2d("2e");17=$(\'\').2f(d);$(1K(k.28)).1L(17);1m=$(\'\').1M(d);2(k.1l===7&&$.X.33!==7){1l=$(\'\').1M(d).1e("1N",3(e){B h=d.2g(),y=e.2h,1n,1o;1n=3(e){d.2i("2g",35.36(20,e.2h+h-y)+"37");4 l};1o=3(e){$("1A").1O("2j",1n).1O("2k",1o);4 l};$("1A").1e("2j",1n).1e("2k",1o)});1m.2l(1l)}d.2m(1P).38(1P);d.1e("1Q",3(e,a){2(a.1p!==l){14()}2(u===$.T.2n){Y(a)}});d.1f(3(){$.T.2n=G})}3 1K(b){B c=$(\'\'),i=0;$(\'C:2o > Z\',c).2i(\'39\',\'q\');$.1c(b,3(){B a=G,t=\'\',1q,C,j;1q=(a.19)?(a.1R||\'\')+\' [3a+\'+a.19+\']\':(a.1R||\'\');19=(a.19)?\'2p="\'+a.19+\'"\':\'\';2(a.2q){C=$(\'\'+(a.2q||\'\')+\'\').1L(c)}8{i++;2r(j=15.6-1;j>=0;j--){t+=15[j]+"-"}C=$(\'\'+(a.1R||\'\')+\'\').1e("3e",3(){4 l}).2t(3(){4 l}).1N(3(){2(a.2u){3f(a.2u)()}2v(3(){Y(a)},1);4 l}).2o(3(){$(\'> Z\',G).3g();$(E).3h(\'2t\',3(){$(\'Z Z\',17).2w()})},3(){$(\'> Z\',G).2w()}).1L(c);2(a.2x){15.3i(i);$(C).2d(\'3j\').2l(1K(a.2x))}}});15.3k();4 c}3 2y(c){2(c){c=c.3l();c=c.W(/\\(\\!\\(([\\s\\S]*?)\\)\\!\\)/g,3(x,a){B b=a.1S(\'|!|\');2(F===7){4(b[1]!==2z)?b[1]:b[0]}8{4(b[1]===2z)?"":b[0]}});c=c.W(/\\[\\!\\[([\\s\\S]*?)\\]\\!\\]/g,3(x,a){B b=a.1S(\':!:\');2(18===7){4 l}1T=3m(b[0],(b[1])?b[1]:\'\');2(1T===29){18=7}4 1T});4 c}4""}3 I(a){2($.3n(a)){a=a(P)}4 2y(a)}3 1g(a){J=I(L.J);1a=I(L.1a);Q=I(L.Q);O=I(L.O);2(Q!==""){q=J+Q+O}8 2(m===\'\'&&1a!==\'\'){q=J+1a+O}8{q=J+(a||m)+O}4{q:q,J:J,Q:Q,1a:1a,O:O}}3 Y(a){B b,j,n,i;P=L=a;14();$.V(P,{1r:"",U:k.U,u:u,m:(m||\'\'),p:p,v:v,A:A,F:F});I(k.1B);I(L.1B);2(v===7&&A===7){I(L.3o)}$.V(P,{1r:1});2(v===7&&A===7){R=m.1S(/\\r?\\n/);2r(j=0,n=R.6,i=0;i=9.5&&b==0){4 l}1i=u.2D();1i.3t(7);1i.2E(\'1Z\',a);1i.3u(\'1Z\',b);1i.3v()}8 2(u.2F){u.2F(a,a+b)}u.1t=16;u.1f()}3 14(){u.1f();16=u.1t;2(E.m){m=E.m.1Y().2C;2($.X.2B){B a=E.m.1Y(),1u=a.3w();1u.3x(u);p=-1;3y(1u.3z(a)){1u.2E(\'1Z\');p++}}8{p=u.2G}}8{p=u.2G;m=d.K().1h(p,u.3A)}4 m}3 1z(){2(!w||w.3B){2(k.1j){w=3C.2H(\'\',\'1z\',k.1j)}8{M=$(\'<2I N="3D">\');2(k.24==\'25\'){M.1M(1m)}8{M.2f(17)}w=M[M.6-1].3E||3F[M.6-1]}}8 2(F===7){2(M){M.3G()}8{w.2J()}w=M=l}2(!k.1y){1X()}}3 1X(){2K()}3 2K(){B b;2(k.1b!==\'\'){$.2L({2M:\'3H\',2N:k.1b,27:k.26+\'=\'+3I(d.K()),2O:3(a){21(1d(a,1))}})}8{2(!2a){$.2L({2N:k.1k,2O:3(a){21(1d(a,1).W(//g,d.K()))}})}}4 l}3 21(a){2(w.E){3K{22=w.E.2P.1t}3L(e){22=0}w.E.2H();w.E.3M(a);w.E.2J();w.E.2P.1t=22}2(k.1j){w.1f()}}3 1P(e){A=e.A;F=e.F;v=(!(e.F&&e.v))?e.v:l;2(e.2M===\'2m\'){2(v===7){C=$("a[2p="+3N.3O(e.1v)+"]",17).1w(\'C\');2(C.6!==0){v=l;2v(3(){C.3P(\'1N\')},1);4 l}}2(e.1v===13||e.1v===10){2(v===7){v=l;Y(k.1F);4 k.1F.1x}8 2(A===7){A=l;Y(k.1E);4 k.1E.1x}8{Y(k.1D);4 k.1D.1x}}2(e.1v===9){2(A==7||v==7||F==7){4 l}2(H!==-1){14();H=d.K().6-H;1W(H,0);H=-1;4 l}8{Y(k.1G);4 k.1G.1x}}}}2b()})};$.23.3Q=3(){4 G.1c(3(){B a=$(G).1O().3R(\'2e\');a.1w(\'z\').1w(\'z.T\').1w(\'z\').Q(a)})};$.T=3(a){B b={1p:l};$.V(b,a);2(b.1p){4 $(b.1p).1c(3(){$(G).1f();$(G).2Q(\'1Q\',[b])})}8{$(\'u\').2Q(\'1Q\',[b])}}})(3S);',62,241,'||if|function|return||length|true|else|||||||||||||false|selection||string|caretPosition|block||||textarea|ctrlKey|previewWindow|||div|shiftKey|var|li|id|document|altKey|this|caretOffset|prepare|openWith|val|clicked|iFrame|class|closeWith|hash|replaceWith|lines||markItUp|root|extend|replace|browser|markup|ul||start|nameSpace||get|levels|scrollPosition|header|abort|key|placeHolder|previewParserPath|each|localize|bind|focus|build|substring|range|previewInWindow|previewTemplatePath|resizeHandle|footer|mouseMove|mouseUp|target|title|line|fixIeBug|scrollTop|rangeCopy|keyCode|parent|keepDefault|previewAutoRefresh|preview|html|beforeInsert|afterInsert|onEnter|onShiftEnter|onCtrlEnter|onTab|miuScript|attr|wrap|dropMenus|appendTo|insertAfter|mousedown|unbind|keyPressed|insertion|name|split|value|opera|fixOperaBug|set|refreshPreview|createRange|character||writeInPreview|sp|fn|previewPosition|after|previewParserVar|data|markupSet|null|template|init|substr|addClass|markItUpEditor|insertBefore|height|clientY|css|mousemove|mouseup|append|keydown|focused|hover|accesskey|separator|for|markItUpButton|click|call|setTimeout|hide|dropMenu|magicMarkups|undefined|insert|msie|text|createTextRange|moveStart|setSelectionRange|selectionStart|open|iframe|close|renderPreview|ajax|type|url|success|documentElement|trigger|templates|script|src|match|jquery|markitup|pack|js|toUpperCase|markItUpContainer|markItUpHeader|markItUpFooter|safari|markItUpResizeHandle|Math|max|px|keyup|display|Ctrl|markItUpSeparator|className|href|contextmenu|eval|show|one|push|markItUpDropMenu|pop|toString|prompt|isFunction|beforeMultiInsert|trim|join|afterMultiInsert|version|collapse|moveEnd|select|duplicate|moveToElementText|while|inRange|selectionEnd|closed|window|markItUpPreviewFrame|contentWindow|frame|remove|POST|encodeURIComponent|content|try|catch|write|String|fromCharCode|triggerHandler|markItUpRemove|removeClass|jQuery'.split('|'),0,{})) \ No newline at end of file +!function($){$.fn.markItUp=function(settings,extraSettings){var method,params,options,ctrlKey,shiftKey,altKey;ctrlKey=shiftKey=altKey=!1,"string"==typeof settings&&(method=settings,params=extraSettings),options={id:"",nameSpace:"",root:"",previewHandler:!1,previewInWindow:"",previewInElement:"",previewAutoRefresh:!0,previewPosition:"after",previewTemplatePath:"~/templates/preview.html",previewParser:!1,previewParserPath:"",previewParserVar:"data",resizeHandle:!0,beforeInsert:"",afterInsert:"",onEnter:{},onShiftEnter:{},onCtrlEnter:{},onTab:{},markupSet:[{}]},$.extend(options,settings,extraSettings),options.root||$("script").each(function(e,t){miuScript=$(t).get(0).src.match(/(.*)jquery\.markitup(\.pack)?\.js$/),null!==miuScript&&(options.root=miuScript[1])});var uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},matched=uaMatch(navigator.userAgent),browser={};return matched.browser&&(browser[matched.browser]=!0,browser.version=matched.version),browser.chrome?browser.webkit=!0:browser.webkit&&(browser.safari=!0),this.each(function(){var $$,textarea,levels,scrollPosition,caretPosition,caretOffset,clicked,hash,header,footer,previewWindow,template,iFrame,abort;if($$=$(this),textarea=this,levels=[],abort=!1,scrollPosition=caretPosition=0,caretOffset=-1,options.previewParserPath=localize(options.previewParserPath),options.previewTemplatePath=localize(options.previewTemplatePath),method)switch(method){case"remove":remove();break;case"insert":markup(params);break;default:$.error("Method "+method+" does not exist on jQuery.markItUp")}else init();function localize(e,t){return t?e.replace(/("|')~\//g,"$1"+options.root):e.replace(/^~\//,options.root)}function init(){id="",nameSpace="",options.id?id='id="'+options.id+'"':$$.attr("id")&&(id='id="markItUp'+$$.attr("id").substr(0,1).toUpperCase()+$$.attr("id").substr(1)+'"'),options.nameSpace&&(nameSpace='class="'+options.nameSpace+'"'),$$.wrap("
    "),$$.wrap("
    '),$$.wrap('
    '),$$.addClass("markItUpEditor"),header=$('
    ').insertBefore($$),$(dropMenus(options.markupSet)).appendTo(header),footer=$('
    ').insertAfter($$),!0===options.resizeHandle&&!0!==browser.safari&&(resizeHandle=$('
    ').insertAfter($$).bind("mousedown.markItUp",function(e){var t,r,i=$$.height(),n=e.clientY;t=function(e){return $$.css("height",Math.max(20,e.clientY+i-n)+"px"),!1},r=function(e){return $("html").unbind("mousemove.markItUp",t).unbind("mouseup.markItUp",r),!1},$("html").bind("mousemove.markItUp",t).bind("mouseup.markItUp",r)}),footer.append(resizeHandle)),$$.bind("keydown.markItUp",keyPressed).bind("keyup",keyPressed),$$.bind("insertion.markItUp",function(e,t){!1!==t.target&&get(),textarea===$.markItUp.focused&&markup(t)}),$$.bind("focus.markItUp",function(){$.markItUp.focused=this}),options.previewInElement&&refreshPreview()}function dropMenus(markupSet){var ul=$("
      "),i=0;return $("li:hover > ul",ul).css("display","block"),$.each(markupSet,function(){var button=this,t="",title,li,j;if(title=button.key?(button.name||"")+" [Ctrl+"+button.key+"]":button.name||"",key=button.key?'accesskey="'+button.key+'"':"",button.separator)li=$('
    • '+(button.separator||"")+"
    • ").appendTo(ul);else{for(i++,j=levels.length-1;j>=0;j--)t+=levels[j]+"-";li=$('
    • '+(button.name||"")+"
    • ").bind("contextmenu.markItUp",function(){return!1}).bind("click.markItUp",function(e){e.preventDefault()}).bind("focusin.markItUp",function(){$$.focus()}).bind("mouseup",function(){return button.call&&eval(button.call)(),setTimeout(function(){markup(button)},1),!1}).bind("mouseenter.markItUp",function(){$("> ul",this).show(),$(document).one("click",function(){$("ul ul",header).hide()})}).bind("mouseleave.markItUp",function(){$("> ul",this).hide()}).appendTo(ul),button.dropMenu&&(levels.push(i),$(li).addClass("markItUpDropMenu").append(dropMenus(button.dropMenu)))}}),levels.pop(),ul}function magicMarkups(e){return e?e=(e=(e=e.toString()).replace(/\(\!\(([\s\S]*?)\)\!\)/g,function(e,t){var r=t.split("|!|");return!0===altKey?void 0!==r[1]?r[1]:r[0]:void 0===r[1]?"":r[0]})).replace(/\[\!\[([\s\S]*?)\]\!\]/g,function(e,t){var r=t.split(":!:");return!0!==abort&&(value=prompt(r[0],r[1]?r[1]:""),null===value&&(abort=!0),value)}):""}function prepare(e){return $.isFunction(e)&&(e=e(hash)),magicMarkups(e)}function build(e){var t=prepare(clicked.openWith),r=prepare(clicked.placeHolder),i=prepare(clicked.replaceWith),n=prepare(clicked.closeWith),o=prepare(clicked.openBlockWith),a=prepare(clicked.closeBlockWith),s=clicked.multiline;if(""!==i)block=t+i+n;else if(""===selection&&""!==r)block=t+r+n;else{var l=[e=e||selection],c=[];!0===s&&(l=e.split(/\r?\n/));for(var p=0;p=9.5&&0==t)return!1;range=textarea.createTextRange(),range.collapse(!0),range.moveStart("character",e),range.moveEnd("character",t),range.select()}else textarea.setSelectionRange&&textarea.setSelectionRange(e,e+t);textarea.scrollTop=scrollPosition,textarea.focus()}function get(){if(textarea.focus(),scrollPosition=textarea.scrollTop,document.selection)if(selection=document.selection.createRange().text,browser.msie){var e=document.selection.createRange(),t=e.duplicate();for(t.moveToElementText(textarea),caretPosition=-1;t.inRange(e);)t.moveStart("character"),caretPosition++}else caretPosition=textarea.selectionStart;else caretPosition=textarea.selectionStart,selection=textarea.value.substring(caretPosition,textarea.selectionEnd);return selection}function preview(){"function"==typeof options.previewHandler?previewWindow=!0:options.previewInElement?previewWindow=$(options.previewInElement):!previewWindow||previewWindow.closed?options.previewInWindow?(previewWindow=window.open("","preview",options.previewInWindow),$(window).unload(function(){previewWindow.close()})):(iFrame=$(''),"after"==options.previewPosition?iFrame.insertAfter(footer):iFrame.insertBefore(header),previewWindow=iFrame[iFrame.length-1].contentWindow||frame[iFrame.length-1]):!0===altKey&&(iFrame?iFrame.remove():previewWindow.close(),previewWindow=iFrame=!1),options.previewAutoRefresh||refreshPreview(),options.previewInWindow&&previewWindow.focus()}function refreshPreview(){renderPreview()}function renderPreview(){if(options.previewHandler&&"function"==typeof options.previewHandler)options.previewHandler($$.val());else if(options.previewParser&&"function"==typeof options.previewParser){writeInPreview(localize(options.previewParser($$.val()),1))}else""!==options.previewParserPath?$.ajax({type:"POST",dataType:"text",global:!1,url:options.previewParserPath,data:options.previewParserVar+"="+encodeURIComponent($$.val()),success:function(e){writeInPreview(localize(e,1))}}):template||$.ajax({url:options.previewTemplatePath,dataType:"text",global:!1,success:function(e){writeInPreview(localize(e,1).replace(//g,$$.val()))}});return!1}function writeInPreview(e){if(options.previewInElement)$(options.previewInElement).html(e);else if(previewWindow&&previewWindow.document){try{sp=previewWindow.document.documentElement.scrollTop}catch(e){sp=0}previewWindow.document.open(),previewWindow.document.write(e),previewWindow.document.close(),previewWindow.document.documentElement.scrollTop=sp}}function keyPressed(e){if(shiftKey=e.shiftKey,altKey=e.altKey,ctrlKey=(!e.altKey||!e.ctrlKey)&&(e.ctrlKey||e.metaKey),"keydown"===e.type){if(!0===ctrlKey&&(li=$('a[accesskey="'+(13==e.keyCode?"\\n":String.fromCharCode(e.keyCode))+'"]',header).parent("li"),0!==li.length))return ctrlKey=!1,setTimeout(function(){li.triggerHandler("mouseup")},1),!1;if(13===e.keyCode||10===e.keyCode)return!0===ctrlKey?(ctrlKey=!1,markup(options.onCtrlEnter),options.onCtrlEnter.keepDefault):!0===shiftKey?(shiftKey=!1,markup(options.onShiftEnter),options.onShiftEnter.keepDefault):(markup(options.onEnter),options.onEnter.keepDefault);if(9===e.keyCode)return 1!=shiftKey&&1!=ctrlKey&&1!=altKey&&(-1!==caretOffset?(get(),set(caretOffset=$$.val().length-caretOffset,0),caretOffset=-1,!1):(markup(options.onTab),options.onTab.keepDefault))}}function remove(){$$.unbind(".markItUp").removeClass("markItUpEditor"),$$.parent("div").parent("div.markItUp").parent("div").replaceWith($$),$$.data("markItUp",null)}})},$.fn.markItUpRemove=function(){return this.each(function(){$(this).markItUp("remove")})},$.markItUp=function(e){var t={target:!1};if($.extend(t,e),t.target)return $(t.target).each(function(){$(this).focus(),$(this).trigger("insertion",[t])});$("textarea").trigger("insertion",[t])}}(jQuery); diff --git a/media/lib/markitup/sets/sphinx/editor.css b/media/lib/markitup/sets/sphinx/editor.css index 7455a297bdf..e2b6ded6499 100644 --- a/media/lib/markitup/sets/sphinx/editor.css +++ b/media/lib/markitup/sets/sphinx/editor.css @@ -1,40 +1,48 @@ -.markItUp .btnHeading a { +/* ------------------------------------------------------------------- +// ReST! +// ------------------------------------------------------------------*/ +.ReST .markItUpButton1 a { background-image:url(images/h1.png); } -.markItUp .btnSubheading a { +.ReST .markItUpButton2 a { background-image:url(images/h2.png); } -.markItUp .btnSubsubheading a { +.ReST .markItUpButton3 a { background-image:url(images/h3.png); } -.markItUp .btnBold a { - background-image:url(images/bold.png); + +.ReST .markItUpButton4 a { + background-image:url(images/bold.png); } -.markItUp .btnItalic a { + +.ReST .markItUpButton5 a { background-image:url(images/italic.png); } -.markItUp .btnBulletedList a { +.ReST .markItUpButton6 a { background-image:url(images/list-bullet.png); } -.markItUp .btnNumberedList a { +.ReST .markItUpButton7 a { background-image:url(images/list-numeric.png); } -.markItUp .btnInternalLink a { +.ReST .markItUpButton8 a { background-image:url(images/book_link.png); } -.markItUp .btnLink a { +.ReST .markItUpButton9 a { background-image:url(images/link_go.png); } -.markItUp .btnQuotes a { + +.ReST .markItUpButton10 a { + background-image:url(images/picture.png); +} +.ReST .markItUpButton11 a { background-image:url(images/quotes.png); } -.markItUp .btnCode a { +.ReST .markItUpButton12 a { background-image:url(images/code.png); } - -.markItUp .btnIndent a { - background-image:url(images/indent.png); +.ReST .markItUpButton13 a { + background-image:url(images/indent.png); } diff --git a/media/lib/markitup/sets/sphinx/editor.js b/media/lib/markitup/sets/sphinx/editor.js index 7953446e5e1..aba41f5cbcd 100644 --- a/media/lib/markitup/sets/sphinx/editor.js +++ b/media/lib/markitup/sets/sphinx/editor.js @@ -1,49 +1,68 @@ -SphinxDocsSettings = { - nameSpace: 'restructuredtext', - onShiftEnter: {keepDefault:false, openWith:'\n\n'}, - markupSet: [ - {name:'Top-level Heading', className: 'btnHeading', key:"1", placeHolder:'Your heading here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '=') } }, - {name:'Sub-heading', className: 'btnSubheading', key:"2", placeHolder:'Your sub-heading here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '-') } }, - {name:'Sub-sub-heading', className: 'btnSubsubheading', key:"3", placeHolder:'Your sub-sub-heading here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '^') } }, - {separator:'---------------' }, - {name:'Bold', className: 'btnBold', key:"B", openWith:'**', closeWith:'**'}, - {name:'Italic', className: 'btnItalic', key:"I", openWith:'*', closeWith:'*'}, - {separator:'---------------' }, - {name:'Bulleted List', className: 'btnBulletedList', openWith:'* ' }, - {name:'Numeric List', className: 'btnNumberedList', openWith:function(markItUp) { - return markItUp.line+'. '; - }}, - {separator:'---------------' }, - //{name:'Picture', key:"P", replaceWith:'![[![Alternative text]!]]([![Url:!:http://]!] "[![Title]!]")'}, - {name:'Internal Link', className: 'btnInternalLink', key:"L", openWith:':doc:`', closeWith:' <[![Heading:!:]!]>`', placeHolder:'Your text to link here...' }, - {name:'External Link', className: 'btnLink', key:"E", openWith:'`', closeWith:' <[![Url:!:http://]!]>`_', placeHolder:'Your text to link here...' }, - {separator:'---------------'}, - {name:'Quotes', className: 'btnQuotes', placeHolder: 'block quote text here...', replaceWith:function(markItUp) { +// ------------------------------------------------------------------- +// markItUp! +// ------------------------------------------------------------------- +// Copyright (C) 2008 Jay Salvat +// http://markitup.jaysalvat.com/ +// ------------------------------------------------------------------- +// ReStructured Text +// http://docutils.sourceforge.net/ +// http://docutils.sourceforge.net/rst.html +// ------------------------------------------------------------------- +// Mark Renron +// http://www.indexofire.com +// ------------------------------------------------------------------- +// Jannis Leidel +// http://enn.io +// ------------------------------------------------------------------- +mySettings = { + nameSpace: 'ReST', + onShiftEnter: {keepDefault:false, openWith:'\n\n'}, + onTab: {keepDefault:false, replaceWith:' '}, + markupSet: [ + //{name:'Level 1 Heading', key:'1', placeHolder:'Your title Here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '#'); } }, + //{name:'Level 2 Heading', key:'2', placeHolder:'Your title here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '*'); } }, + {name:'Level 1 Heading', key:'1', placeHolder:'Your heading here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '='); } }, + {name:'Level 2 Heading', key:'2', placeHolder:'Your sub-heading here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '-'); } }, + {name:'Level 3 Heading', key:'3', placeHolder:'Your sub-sub-heading here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '^'); } }, + //{name:'Level 6 Heading', key:'6', placeHolder:'Your title here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '"'); } }, + {separator:'---------------' }, + {name:'Bold', key:'B', openWith:'**', closeWith:'**', placeHolder:'Input Your Bold Text Here...'}, + {name:'Italic', key:'I', openWith:'`', closeWith:'`', placeHolder:'Input Your Italic Text Here...'}, + {separator:'---------------' }, + {name:'Bulleted List', openWith:'* ' }, + {name:'Numeric List', openWith:function(markItUp) { return markItUp.line+'. '; } }, + {separator:'---------------' }, + {name:'Internal Link', key:"L", openWith:':doc:`', closeWith:' <[![Heading:!:]!]>`', placeHolder:'Your text to link here...' }, + {name:'External Link', key:"E", openWith:'`', closeWith:' <[![Url:!:http://]!]>`_', placeHolder:'Your text to link here...' }, + {separator:'---------------' }, + {name:'Picture', key:'P', openWith:'.. image:: ', placeHolder:'Link Your Images Here...'}, + {name:'Quotes', placeHolder: 'block quote text here...', replaceWith:function(markItUp) { return miu.indentText(markItUp); }}, - {name:'Code Block / Code', className: 'btnCode', placeHolder:'Code here...', replaceWith:function(markItUp) { + {name:'Code Block / Code', placeHolder:'Code here...', replaceWith:function(markItUp) { directive = '\n.. code-block:: python\n\n'; indented = miu.indentText(markItUp); return directive + indented; }}, {separator:'---------------'}, - {name:'Indent', className:"btnIndent", replaceWith:function(markItUp) { + {name:'Indent', replaceWith:function(markItUp) { return miu.indentText(markItUp); }} - ] -} + ] +}; + // mIu nameSpace to avoid conflict. miu = { - markdownTitle: function(markItUp, char) { - heading = ''; - n = $.trim(markItUp.selection||markItUp.placeHolder).length; - for(i = 0; i < n; i++) { - heading += char; - } - return '\n'+heading+'\n'; - }, - indentText: function(markItUp) { + markdownTitle: function(markItUp, character) { + heading = ''; + n = $.trim(markItUp.selection||markItUp.placeHolder).length; + for(i = 0; i < n; i++) { + heading += character; + } + return '\n'+heading + '\n'; + }, + indentText: function(markItUp) { text_block = markItUp.selection || markItUp.placeHolder; indented = ''; $.each(text_block.split('\n'), function(idx, text) { @@ -51,4 +70,4 @@ miu = { }); return indented; } -} +}; diff --git a/readthedocs/templates/projects/project_edit.html b/readthedocs/templates/projects/project_edit.html index cbbf75db99a..785d4d373dc 100644 --- a/readthedocs/templates/projects/project_edit.html +++ b/readthedocs/templates/projects/project_edit.html @@ -14,7 +14,7 @@ {% endblock %} From a129799faaec00f167e4cc4eb82c4c2c8b1d6913 Mon Sep 17 00:00:00 2001 From: David Fischer Date: Wed, 21 Feb 2018 11:03:09 -0800 Subject: [PATCH 009/190] Add a sustainability API from non-OSS code --- readthedocs/restapi/urls.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/readthedocs/restapi/urls.py b/readthedocs/restapi/urls.py index 9d6fbd19229..904ba6cef60 100644 --- a/readthedocs/restapi/urls.py +++ b/readthedocs/restapi/urls.py @@ -97,3 +97,12 @@ urlpatterns += api_search_urls except ImportError: pass + +try: + from readthedocsext.donate.restapi.urls import urlpatterns as sustainability_urls + + urlpatterns += [ + url(r'^sustainability/', include(sustainability_urls)), + ] +except ImportError: + pass From a9239fd5dc8ad891fff768f2a8b59debc95eac18 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Fri, 23 Feb 2018 12:32:46 -0500 Subject: [PATCH 010/190] Upgrade django-pagination to a "maintained" fork Closes #3664 The package `django-pagination` got unmaintained, so a fork by Linaro was created at https://github.com/zyga/django-pagination and got unmaintained again (https://github.com/zyga/django-pagination/issues/42). Now, there is another fork at https://github.com/pydanny/dj-pagination) that contains more compatibility releases. So, I'm upgrading to this one. --- readthedocs/settings/base.py | 4 ++-- requirements/pip.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/readthedocs/settings/base.py b/readthedocs/settings/base.py index 1131bed6531..51f779b6ef9 100644 --- a/readthedocs/settings/base.py +++ b/readthedocs/settings/base.py @@ -71,7 +71,7 @@ def INSTALLED_APPS(self): # noqa 'django.contrib.humanize', # third party apps - 'linaro_django_pagination', + 'dj_pagination', 'taggit', 'guardian', 'django_gravatar', @@ -131,7 +131,7 @@ def USE_PROMOS(self): # noqa 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', - 'linaro_django_pagination.middleware.PaginationMiddleware', + 'dj_pagination.middleware.PaginationMiddleware', 'readthedocs.core.middleware.SubdomainMiddleware', 'readthedocs.core.middleware.SingleVersionMiddleware', 'corsheaders.middleware.CorsMiddleware', diff --git a/requirements/pip.txt b/requirements/pip.txt index e94471cf34b..a5e02452936 100644 --- a/requirements/pip.txt +++ b/requirements/pip.txt @@ -56,6 +56,7 @@ django-textclassifier==1.0 django-annoying==0.10.1 django-messages-extends==0.5 djangorestframework-jsonp==1.0.2 +dj-pagination==2.3.2 # Docs sphinxcontrib-httpdomain==1.4.0 @@ -70,5 +71,4 @@ django-cors-middleware==1.3.1 nilsimsa==0.3.7 # Pegged git requirements -git+https://github.com/zyga/django-pagination.git@86caf15#egg=django_pagination-dev git+https://github.com/alex/django-taggit.git#egg=django_taggit-dev From 2065c590e7cf9275102f7e16bde883523d0ff47e Mon Sep 17 00:00:00 2001 From: Ashish Kumar Date: Sat, 24 Feb 2018 04:21:58 +0530 Subject: [PATCH 011/190] Documentation for build notifications using webhooks --- docs/guides/build-notifications.rst | 37 +++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/docs/guides/build-notifications.rst b/docs/guides/build-notifications.rst index 1d54ce52764..051637894fa 100644 --- a/docs/guides/build-notifications.rst +++ b/docs/guides/build-notifications.rst @@ -1,13 +1,46 @@ Enabling Build Notifications ============================ +Using Email +****************** + Read the Docs allows you to configure emails that can be sent on failing builds. This makes sure you know when your builds have failed. -Take these steps to enable build notifications: +Take these steps to enable build notifications using email: * Going to **Admin > Notifications** in your project. * Fill in the **Email** field under the **New Email Notifications** heading * Submit the form -You should now get notified when your builds fail! +You should now get notified on your email when your builds fail! + +Using Webhook +****************** + +Read the Docs also allows webhooks configuration to receive notification regarding builds fails. + +Take these steps to enable build notifications using webhook: + +* Going to **Admin > Notifications** in your project. +* Fill in the **Url** field under the **New Webhook Notifications** heading +* Submit the form + +The project name, id and its bulid instance that failed will be sent to your webhook url: + +.. code-block:: json + + { + 'name': project.name, + 'slug': project.slug, + 'build': { + 'id': build.id, + 'success': build.success, + 'date': build.date.strftime('%Y-%m-%d %H:%M:%S'), + } + } + + + + +You should now get notified on your webhook when your builds fail! From 77d79a84dddb5504f01dc9d5ef0fa8042b3bc372 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Date: Sat, 24 Feb 2018 06:22:29 +0530 Subject: [PATCH 012/190] Update build-notifications.rst --- docs/guides/build-notifications.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/guides/build-notifications.rst b/docs/guides/build-notifications.rst index 051637894fa..8a77ad73e47 100644 --- a/docs/guides/build-notifications.rst +++ b/docs/guides/build-notifications.rst @@ -2,7 +2,7 @@ Enabling Build Notifications ============================ Using Email -****************** +----------- Read the Docs allows you to configure emails that can be sent on failing builds. This makes sure you know when your builds have failed. @@ -16,7 +16,7 @@ Take these steps to enable build notifications using email: You should now get notified on your email when your builds fail! Using Webhook -****************** +------------- Read the Docs also allows webhooks configuration to receive notification regarding builds fails. @@ -31,12 +31,12 @@ The project name, id and its bulid instance that failed will be sent to your web .. code-block:: json { - 'name': project.name, - 'slug': project.slug, - 'build': { - 'id': build.id, - 'success': build.success, - 'date': build.date.strftime('%Y-%m-%d %H:%M:%S'), + "name": "Read the Docs", + "slug": "rtd", + "build": { + "id": 6321373, + "success": false, + "date": "2017-02-15 20:35:54", } } From cfc7d1c5a6752cc82ed3f566657a9589d872f807 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Date: Sat, 24 Feb 2018 16:28:21 +0530 Subject: [PATCH 013/190] Update build-notifications.rst --- docs/guides/build-notifications.rst | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/guides/build-notifications.rst b/docs/guides/build-notifications.rst index 8a77ad73e47..f183cb05839 100644 --- a/docs/guides/build-notifications.rst +++ b/docs/guides/build-notifications.rst @@ -1,7 +1,7 @@ Enabling Build Notifications ============================ -Using Email +Using email ----------- Read the Docs allows you to configure emails that can be sent on failing builds. @@ -15,7 +15,7 @@ Take these steps to enable build notifications using email: You should now get notified on your email when your builds fail! -Using Webhook +Using webhook ------------- Read the Docs also allows webhooks configuration to receive notification regarding builds fails. @@ -26,7 +26,7 @@ Take these steps to enable build notifications using webhook: * Fill in the **Url** field under the **New Webhook Notifications** heading * Submit the form -The project name, id and its bulid instance that failed will be sent to your webhook url: +The project name, slug and its bulid instance that failed will be sent as POST request to your webhook url: .. code-block:: json @@ -40,7 +40,4 @@ The project name, id and its bulid instance that failed will be sent to your web } } - - - You should now get notified on your webhook when your builds fail! From b1ff7d35a2bb68a4b65739b1bfde351227a5fe4f Mon Sep 17 00:00:00 2001 From: Ashish Kumar Date: Sun, 25 Feb 2018 01:54:23 +0530 Subject: [PATCH 014/190] corrected typo --- docs/guides/build-notifications.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/build-notifications.rst b/docs/guides/build-notifications.rst index f183cb05839..4881f8d750c 100644 --- a/docs/guides/build-notifications.rst +++ b/docs/guides/build-notifications.rst @@ -26,7 +26,7 @@ Take these steps to enable build notifications using webhook: * Fill in the **Url** field under the **New Webhook Notifications** heading * Submit the form -The project name, slug and its bulid instance that failed will be sent as POST request to your webhook url: +The project name, slug and its build instance that failed will be sent as POST request to your webhook url: .. code-block:: json From 17be1c11d24621e8a857796a26728deedfab5184 Mon Sep 17 00:00:00 2001 From: Eric Holscher Date: Mon, 26 Feb 2018 22:14:52 +0700 Subject: [PATCH 015/190] Show the project slug in the project admin (to make it more explicit what project is what) --- readthedocs/projects/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/projects/admin.py b/readthedocs/projects/admin.py index cca3e9c3ce4..fac08e3b087 100644 --- a/readthedocs/projects/admin.py +++ b/readthedocs/projects/admin.py @@ -102,7 +102,7 @@ class ProjectAdmin(GuardedModelAdmin): """Project model admin view.""" prepopulated_fields = {'slug': ('name',)} - list_display = ('name', 'repo', 'repo_type', 'allow_comments', 'featured', 'theme') + list_display = ('name', 'slug', 'repo', 'repo_type', 'allow_comments', 'featured', 'theme') list_filter = ('repo_type', 'allow_comments', 'featured', 'privacy_level', 'documentation_type', 'programming_language', ProjectOwnerBannedFilter) From 2950fdab1c59f7c17de52afd410a6ec14dfb38dc Mon Sep 17 00:00:00 2001 From: aasis21 Date: Tue, 27 Feb 2018 00:53:31 +0530 Subject: [PATCH 016/190] removed rich text editor and its related markitup media files --- media/lib/markitup/jquery.markitup.js | 665 ------------------ media/lib/markitup/jquery.markitup.pack.js | 1 - .../lib/markitup/sets/default/images/bold.png | Bin 304 -> 0 bytes .../markitup/sets/default/images/clean.png | Bin 667 -> 0 bytes .../markitup/sets/default/images/image.png | Bin 516 -> 0 bytes .../markitup/sets/default/images/italic.png | Bin 223 -> 0 bytes .../lib/markitup/sets/default/images/link.png | Bin 343 -> 0 bytes .../markitup/sets/default/images/picture.png | Bin 606 -> 0 bytes .../markitup/sets/default/images/preview.png | Bin 537 -> 0 bytes .../markitup/sets/default/images/stroke.png | Bin 269 -> 0 bytes media/lib/markitup/sets/default/set.js | 27 - media/lib/markitup/sets/default/style.css | 27 - media/lib/markitup/sets/sphinx/editor.css | 48 -- media/lib/markitup/sets/sphinx/editor.js | 73 -- .../lib/markitup/sets/sphinx/images/bold.png | Bin 304 -> 0 bytes .../markitup/sets/sphinx/images/book_link.png | Bin 789 -> 0 bytes .../lib/markitup/sets/sphinx/images/clean.png | Bin 667 -> 0 bytes .../lib/markitup/sets/sphinx/images/code.png | Bin 859 -> 0 bytes media/lib/markitup/sets/sphinx/images/h1.png | Bin 276 -> 0 bytes media/lib/markitup/sets/sphinx/images/h2.png | Bin 304 -> 0 bytes media/lib/markitup/sets/sphinx/images/h3.png | Bin 306 -> 0 bytes .../lib/markitup/sets/sphinx/images/image.png | Bin 516 -> 0 bytes .../markitup/sets/sphinx/images/indent.png | Bin 353 -> 0 bytes .../markitup/sets/sphinx/images/italic.png | Bin 223 -> 0 bytes .../lib/markitup/sets/sphinx/images/link.png | Bin 343 -> 0 bytes .../markitup/sets/sphinx/images/link_go.png | Bin 655 -> 0 bytes .../sets/sphinx/images/list-bullet.png | Bin 344 -> 0 bytes .../sets/sphinx/images/list-numeric.png | Bin 357 -> 0 bytes .../markitup/sets/sphinx/images/picture.png | Bin 606 -> 0 bytes .../markitup/sets/sphinx/images/preview.png | Bin 537 -> 0 bytes .../markitup/sets/sphinx/images/quotes.png | Bin 743 -> 0 bytes .../markitup/sets/sphinx/images/stroke.png | Bin 269 -> 0 bytes .../skins/markitup/images/bg-container.png | Bin 28455 -> 0 bytes .../markitup/images/bg-editor-bbcode.png | Bin 1642 -> 0 bytes .../markitup/images/bg-editor-dotclear.png | Bin 1682 -> 0 bytes .../skins/markitup/images/bg-editor-html.png | Bin 1534 -> 0 bytes .../skins/markitup/images/bg-editor-json.png | Bin 1529 -> 0 bytes .../markitup/images/bg-editor-markdown.png | Bin 1783 -> 0 bytes .../markitup/images/bg-editor-textile.png | Bin 1659 -> 0 bytes .../skins/markitup/images/bg-editor-wiki.png | Bin 1488 -> 0 bytes .../skins/markitup/images/bg-editor-xml.png | Bin 1495 -> 0 bytes .../skins/markitup/images/bg-editor.png | Bin 1745 -> 0 bytes .../markitup/skins/markitup/images/handle.png | Bin 258 -> 0 bytes .../markitup/skins/markitup/images/menu.png | Bin 27151 -> 0 bytes .../skins/markitup/images/submenu.png | Bin 240 -> 0 bytes media/lib/markitup/skins/markitup/style.css | 148 ---- .../markitup/skins/simple/images/handle.png | Bin 258 -> 0 bytes .../lib/markitup/skins/simple/images/menu.png | Bin 27151 -> 0 bytes .../markitup/skins/simple/images/submenu.png | Bin 240 -> 0 bytes media/lib/markitup/skins/simple/style.css | 118 ---- media/lib/markitup/templates/preview.css | 5 - media/lib/markitup/templates/preview.html | 11 - .../templates/projects/import_extra.html | 15 - .../templates/projects/project_advanced.html | 15 - .../templates/projects/project_create.html | 17 - .../templates/projects/project_edit.html | 14 - 56 files changed, 1184 deletions(-) delete mode 100644 media/lib/markitup/jquery.markitup.js delete mode 100644 media/lib/markitup/jquery.markitup.pack.js delete mode 100644 media/lib/markitup/sets/default/images/bold.png delete mode 100644 media/lib/markitup/sets/default/images/clean.png delete mode 100644 media/lib/markitup/sets/default/images/image.png delete mode 100644 media/lib/markitup/sets/default/images/italic.png delete mode 100644 media/lib/markitup/sets/default/images/link.png delete mode 100644 media/lib/markitup/sets/default/images/picture.png delete mode 100644 media/lib/markitup/sets/default/images/preview.png delete mode 100644 media/lib/markitup/sets/default/images/stroke.png delete mode 100644 media/lib/markitup/sets/default/set.js delete mode 100644 media/lib/markitup/sets/default/style.css delete mode 100644 media/lib/markitup/sets/sphinx/editor.css delete mode 100644 media/lib/markitup/sets/sphinx/editor.js delete mode 100644 media/lib/markitup/sets/sphinx/images/bold.png delete mode 100644 media/lib/markitup/sets/sphinx/images/book_link.png delete mode 100644 media/lib/markitup/sets/sphinx/images/clean.png delete mode 100644 media/lib/markitup/sets/sphinx/images/code.png delete mode 100644 media/lib/markitup/sets/sphinx/images/h1.png delete mode 100644 media/lib/markitup/sets/sphinx/images/h2.png delete mode 100644 media/lib/markitup/sets/sphinx/images/h3.png delete mode 100644 media/lib/markitup/sets/sphinx/images/image.png delete mode 100644 media/lib/markitup/sets/sphinx/images/indent.png delete mode 100644 media/lib/markitup/sets/sphinx/images/italic.png delete mode 100644 media/lib/markitup/sets/sphinx/images/link.png delete mode 100644 media/lib/markitup/sets/sphinx/images/link_go.png delete mode 100644 media/lib/markitup/sets/sphinx/images/list-bullet.png delete mode 100644 media/lib/markitup/sets/sphinx/images/list-numeric.png delete mode 100644 media/lib/markitup/sets/sphinx/images/picture.png delete mode 100644 media/lib/markitup/sets/sphinx/images/preview.png delete mode 100644 media/lib/markitup/sets/sphinx/images/quotes.png delete mode 100644 media/lib/markitup/sets/sphinx/images/stroke.png delete mode 100644 media/lib/markitup/skins/markitup/images/bg-container.png delete mode 100644 media/lib/markitup/skins/markitup/images/bg-editor-bbcode.png delete mode 100644 media/lib/markitup/skins/markitup/images/bg-editor-dotclear.png delete mode 100644 media/lib/markitup/skins/markitup/images/bg-editor-html.png delete mode 100644 media/lib/markitup/skins/markitup/images/bg-editor-json.png delete mode 100644 media/lib/markitup/skins/markitup/images/bg-editor-markdown.png delete mode 100644 media/lib/markitup/skins/markitup/images/bg-editor-textile.png delete mode 100644 media/lib/markitup/skins/markitup/images/bg-editor-wiki.png delete mode 100644 media/lib/markitup/skins/markitup/images/bg-editor-xml.png delete mode 100644 media/lib/markitup/skins/markitup/images/bg-editor.png delete mode 100644 media/lib/markitup/skins/markitup/images/handle.png delete mode 100644 media/lib/markitup/skins/markitup/images/menu.png delete mode 100644 media/lib/markitup/skins/markitup/images/submenu.png delete mode 100644 media/lib/markitup/skins/markitup/style.css delete mode 100644 media/lib/markitup/skins/simple/images/handle.png delete mode 100644 media/lib/markitup/skins/simple/images/menu.png delete mode 100644 media/lib/markitup/skins/simple/images/submenu.png delete mode 100644 media/lib/markitup/skins/simple/style.css delete mode 100644 media/lib/markitup/templates/preview.css delete mode 100644 media/lib/markitup/templates/preview.html diff --git a/media/lib/markitup/jquery.markitup.js b/media/lib/markitup/jquery.markitup.js deleted file mode 100644 index eb4c1a0f1bd..00000000000 --- a/media/lib/markitup/jquery.markitup.js +++ /dev/null @@ -1,665 +0,0 @@ -// ---------------------------------------------------------------------------- -// markItUp! Universal MarkUp Engine, JQuery plugin -// v 1.1.x -// Dual licensed under the MIT and GPL licenses. -// ---------------------------------------------------------------------------- -// Copyright (C) 2007-2012 Jay Salvat -// http://markitup.jaysalvat.com/ -// ---------------------------------------------------------------------------- -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// ---------------------------------------------------------------------------- -(function($) { - $.fn.markItUp = function(settings, extraSettings) { - var method, params, options, ctrlKey, shiftKey, altKey; ctrlKey = shiftKey = altKey = false; - - if (typeof settings == 'string') { - method = settings; - params = extraSettings; - } - - options = { id: '', - nameSpace: '', - root: '', - previewHandler: false, - previewInWindow: '', // 'width=800, height=600, resizable=yes, scrollbars=yes' - previewInElement: '', - previewAutoRefresh: true, - previewPosition: 'after', - previewTemplatePath: '~/templates/preview.html', - previewParser: false, - previewParserPath: '', - previewParserVar: 'data', - resizeHandle: true, - beforeInsert: '', - afterInsert: '', - onEnter: {}, - onShiftEnter: {}, - onCtrlEnter: {}, - onTab: {}, - markupSet: [ { /* set */ } ] - }; - $.extend(options, settings, extraSettings); - - // compute markItUp! path - if (!options.root) { - $('script').each(function(a, tag) { - miuScript = $(tag).get(0).src.match(/(.*)jquery\.markitup(\.pack)?\.js$/); - if (miuScript !== null) { - options.root = miuScript[1]; - } - }); - } - - // Quick patch to keep compatibility with jQuery 1.9 - var uaMatch = function(ua) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || - /(webkit)[ \/]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - }; - var matched = uaMatch( navigator.userAgent ); - var browser = {}; - - if (matched.browser) { - browser[matched.browser] = true; - browser.version = matched.version; - } - if (browser.chrome) { - browser.webkit = true; - } else if (browser.webkit) { - browser.safari = true; - } - - return this.each(function() { - var $$, textarea, levels, scrollPosition, caretPosition, caretOffset, - clicked, hash, header, footer, previewWindow, template, iFrame, abort; - $$ = $(this); - textarea = this; - levels = []; - abort = false; - scrollPosition = caretPosition = 0; - caretOffset = -1; - - options.previewParserPath = localize(options.previewParserPath); - options.previewTemplatePath = localize(options.previewTemplatePath); - - if (method) { - switch(method) { - case 'remove': - remove(); - break; - case 'insert': - markup(params); - break; - default: - $.error('Method ' + method + ' does not exist on jQuery.markItUp'); - } - return; - } - - // apply the computed path to ~/ - function localize(data, inText) { - if (inText) { - return data.replace(/("|')~\//g, "$1"+options.root); - } - return data.replace(/^~\//, options.root); - } - - // init and build editor - function init() { - id = ''; nameSpace = ''; - if (options.id) { - id = 'id="'+options.id+'"'; - } else if ($$.attr("id")) { - id = 'id="markItUp'+($$.attr("id").substr(0, 1).toUpperCase())+($$.attr("id").substr(1))+'"'; - - } - if (options.nameSpace) { - nameSpace = 'class="'+options.nameSpace+'"'; - } - $$.wrap('
      '); - $$.wrap('
      '); - $$.wrap('
      '); - $$.addClass("markItUpEditor"); - - // add the header before the textarea - header = $('
      ').insertBefore($$); - $(dropMenus(options.markupSet)).appendTo(header); - - // add the footer after the textarea - footer = $('
      ').insertAfter($$); - - // add the resize handle after textarea - if (options.resizeHandle === true && browser.safari !== true) { - resizeHandle = $('
      ') - .insertAfter($$) - .bind("mousedown.markItUp", function(e) { - var h = $$.height(), y = e.clientY, mouseMove, mouseUp; - mouseMove = function(e) { - $$.css("height", Math.max(20, e.clientY+h-y)+"px"); - return false; - }; - mouseUp = function(e) { - $("html").unbind("mousemove.markItUp", mouseMove).unbind("mouseup.markItUp", mouseUp); - return false; - }; - $("html").bind("mousemove.markItUp", mouseMove).bind("mouseup.markItUp", mouseUp); - }); - footer.append(resizeHandle); - } - - // listen key events - $$.bind('keydown.markItUp', keyPressed).bind('keyup', keyPressed); - - // bind an event to catch external calls - $$.bind("insertion.markItUp", function(e, settings) { - if (settings.target !== false) { - get(); - } - if (textarea === $.markItUp.focused) { - markup(settings); - } - }); - - // remember the last focus - $$.bind('focus.markItUp', function() { - $.markItUp.focused = this; - }); - - if (options.previewInElement) { - refreshPreview(); - } - } - - // recursively build header with dropMenus from markupset - function dropMenus(markupSet) { - var ul = $('
        '), i = 0; - $('li:hover > ul', ul).css('display', 'block'); - $.each(markupSet, function() { - var button = this, t = '', title, li, j; - title = (button.key) ? (button.name||'')+' [Ctrl+'+button.key+']' : (button.name||''); - key = (button.key) ? 'accesskey="'+button.key+'"' : ''; - if (button.separator) { - li = $('
      • '+(button.separator||'')+'
      • ').appendTo(ul); - } else { - i++; - for (j = levels.length -1; j >= 0; j--) { - t += levels[j]+"-"; - } - li = $('
      • '+(button.name||'')+'
      • ') - .bind("contextmenu.markItUp", function() { // prevent contextmenu on mac and allow ctrl+click - return false; - }).bind('click.markItUp', function(e) { - e.preventDefault(); - }).bind("focusin.markItUp", function(){ - $$.focus(); - }).bind('mouseup', function() { - if (button.call) { - eval(button.call)(); - } - setTimeout(function() { markup(button) },1); - return false; - }).bind('mouseenter.markItUp', function() { - $('> ul', this).show(); - $(document).one('click', function() { // close dropmenu if click outside - $('ul ul', header).hide(); - } - ); - }).bind('mouseleave.markItUp', function() { - $('> ul', this).hide(); - }).appendTo(ul); - if (button.dropMenu) { - levels.push(i); - $(li).addClass('markItUpDropMenu').append(dropMenus(button.dropMenu)); - } - } - }); - levels.pop(); - return ul; - } - - // markItUp! markups - function magicMarkups(string) { - if (string) { - string = string.toString(); - string = string.replace(/\(\!\(([\s\S]*?)\)\!\)/g, - function(x, a) { - var b = a.split('|!|'); - if (altKey === true) { - return (b[1] !== undefined) ? b[1] : b[0]; - } else { - return (b[1] === undefined) ? "" : b[0]; - } - } - ); - // [![prompt]!], [![prompt:!:value]!] - string = string.replace(/\[\!\[([\s\S]*?)\]\!\]/g, - function(x, a) { - var b = a.split(':!:'); - if (abort === true) { - return false; - } - value = prompt(b[0], (b[1]) ? b[1] : ''); - if (value === null) { - abort = true; - } - return value; - } - ); - return string; - } - return ""; - } - - // prepare action - function prepare(action) { - if ($.isFunction(action)) { - action = action(hash); - } - return magicMarkups(action); - } - - // build block to insert - function build(string) { - var openWith = prepare(clicked.openWith); - var placeHolder = prepare(clicked.placeHolder); - var replaceWith = prepare(clicked.replaceWith); - var closeWith = prepare(clicked.closeWith); - var openBlockWith = prepare(clicked.openBlockWith); - var closeBlockWith = prepare(clicked.closeBlockWith); - var multiline = clicked.multiline; - - if (replaceWith !== "") { - block = openWith + replaceWith + closeWith; - } else if (selection === '' && placeHolder !== '') { - block = openWith + placeHolder + closeWith; - } else { - string = string || selection; - - var lines = [string], blocks = []; - - if (multiline === true) { - lines = string.split(/\r?\n/); - } - - for (var l = 0; l < lines.length; l++) { - line = lines[l]; - var trailingSpaces; - if (trailingSpaces = line.match(/ *$/)) { - blocks.push(openWith + line.replace(/ *$/g, '') + closeWith + trailingSpaces); - } else { - blocks.push(openWith + line + closeWith); - } - } - - block = blocks.join("\n"); - } - - block = openBlockWith + block + closeBlockWith; - - return { block:block, - openBlockWith:openBlockWith, - openWith:openWith, - replaceWith:replaceWith, - placeHolder:placeHolder, - closeWith:closeWith, - closeBlockWith:closeBlockWith - }; - } - - // define markup to insert - function markup(button) { - var len, j, n, i; - hash = clicked = button; - get(); - $.extend(hash, { line:"", - root:options.root, - textarea:textarea, - selection:(selection||''), - caretPosition:caretPosition, - ctrlKey:ctrlKey, - shiftKey:shiftKey, - altKey:altKey - } - ); - // callbacks before insertion - prepare(options.beforeInsert); - prepare(clicked.beforeInsert); - if ((ctrlKey === true && shiftKey === true) || button.multiline === true) { - prepare(clicked.beforeMultiInsert); - } - $.extend(hash, { line:1 }); - - if ((ctrlKey === true && shiftKey === true)) { - lines = selection.split(/\r?\n/); - for (j = 0, n = lines.length, i = 0; i < n; i++) { - if ($.trim(lines[i]) !== '') { - $.extend(hash, { line:++j, selection:lines[i] } ); - lines[i] = build(lines[i]).block; - } else { - lines[i] = ""; - } - } - - string = { block:lines.join('\n')}; - start = caretPosition; - len = string.block.length + ((browser.opera) ? n-1 : 0); - } else if (ctrlKey === true) { - string = build(selection); - start = caretPosition + string.openWith.length; - len = string.block.length - string.openWith.length - string.closeWith.length; - len = len - (string.block.match(/ $/) ? 1 : 0); - len -= fixIeBug(string.block); - } else if (shiftKey === true) { - string = build(selection); - start = caretPosition; - len = string.block.length; - len -= fixIeBug(string.block); - } else { - string = build(selection); - start = caretPosition + string.block.length ; - len = 0; - start -= fixIeBug(string.block); - } - if ((selection === '' && string.replaceWith === '')) { - caretOffset += fixOperaBug(string.block); - - start = caretPosition + string.openBlockWith.length + string.openWith.length; - len = string.block.length - string.openBlockWith.length - string.openWith.length - string.closeWith.length - string.closeBlockWith.length; - - caretOffset = $$.val().substring(caretPosition, $$.val().length).length; - caretOffset -= fixOperaBug($$.val().substring(0, caretPosition)); - } - $.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } ); - - if (string.block !== selection && abort === false) { - insert(string.block); - set(start, len); - } else { - caretOffset = -1; - } - get(); - - $.extend(hash, { line:'', selection:selection }); - - // callbacks after insertion - if ((ctrlKey === true && shiftKey === true) || button.multiline === true) { - prepare(clicked.afterMultiInsert); - } - prepare(clicked.afterInsert); - prepare(options.afterInsert); - - // refresh preview if opened - if (previewWindow && options.previewAutoRefresh) { - refreshPreview(); - } - - // reinit keyevent - shiftKey = altKey = ctrlKey = abort = false; - } - - // Substract linefeed in Opera - function fixOperaBug(string) { - if (browser.opera) { - return string.length - string.replace(/\n*/g, '').length; - } - return 0; - } - // Substract linefeed in IE - function fixIeBug(string) { - if (browser.msie) { - return string.length - string.replace(/\r*/g, '').length; - } - return 0; - } - - // add markup - function insert(block) { - if (document.selection) { - var newSelection = document.selection.createRange(); - newSelection.text = block; - } else { - textarea.value = textarea.value.substring(0, caretPosition) + block + textarea.value.substring(caretPosition + selection.length, textarea.value.length); - } - } - - // set a selection - function set(start, len) { - if (textarea.createTextRange){ - // quick fix to make it work on Opera 9.5 - if (browser.opera && browser.version >= 9.5 && len == 0) { - return false; - } - range = textarea.createTextRange(); - range.collapse(true); - range.moveStart('character', start); - range.moveEnd('character', len); - range.select(); - } else if (textarea.setSelectionRange ){ - textarea.setSelectionRange(start, start + len); - } - textarea.scrollTop = scrollPosition; - textarea.focus(); - } - - // get the selection - function get() { - textarea.focus(); - - scrollPosition = textarea.scrollTop; - if (document.selection) { - selection = document.selection.createRange().text; - if (browser.msie) { // ie - var range = document.selection.createRange(), rangeCopy = range.duplicate(); - rangeCopy.moveToElementText(textarea); - caretPosition = -1; - while(rangeCopy.inRange(range)) { - rangeCopy.moveStart('character'); - caretPosition ++; - } - } else { // opera - caretPosition = textarea.selectionStart; - } - } else { // gecko & webkit - caretPosition = textarea.selectionStart; - - selection = textarea.value.substring(caretPosition, textarea.selectionEnd); - } - return selection; - } - - // open preview window - function preview() { - if (typeof options.previewHandler === 'function') { - previewWindow = true; - } else if (options.previewInElement) { - previewWindow = $(options.previewInElement); - } else if (!previewWindow || previewWindow.closed) { - if (options.previewInWindow) { - previewWindow = window.open('', 'preview', options.previewInWindow); - $(window).unload(function() { - previewWindow.close(); - }); - } else { - iFrame = $(''); - if (options.previewPosition == 'after') { - iFrame.insertAfter(footer); - } else { - iFrame.insertBefore(header); - } - previewWindow = iFrame[iFrame.length - 1].contentWindow || frame[iFrame.length - 1]; - } - } else if (altKey === true) { - if (iFrame) { - iFrame.remove(); - } else { - previewWindow.close(); - } - previewWindow = iFrame = false; - } - if (!options.previewAutoRefresh) { - refreshPreview(); - } - if (options.previewInWindow) { - previewWindow.focus(); - } - } - - // refresh Preview window - function refreshPreview() { - renderPreview(); - } - - function renderPreview() { - var phtml; - if (options.previewHandler && typeof options.previewHandler === 'function') { - options.previewHandler( $$.val() ); - } else if (options.previewParser && typeof options.previewParser === 'function') { - var data = options.previewParser( $$.val() ); - writeInPreview(localize(data, 1) ); - } else if (options.previewParserPath !== '') { - $.ajax({ - type: 'POST', - dataType: 'text', - global: false, - url: options.previewParserPath, - data: options.previewParserVar+'='+encodeURIComponent($$.val()), - success: function(data) { - writeInPreview( localize(data, 1) ); - } - }); - } else { - if (!template) { - $.ajax({ - url: options.previewTemplatePath, - dataType: 'text', - global: false, - success: function(data) { - writeInPreview( localize(data, 1).replace(//g, $$.val()) ); - } - }); - } - } - return false; - } - - function writeInPreview(data) { - if (options.previewInElement) { - $(options.previewInElement).html(data); - } else if (previewWindow && previewWindow.document) { - try { - sp = previewWindow.document.documentElement.scrollTop - } catch(e) { - sp = 0; - } - previewWindow.document.open(); - previewWindow.document.write(data); - previewWindow.document.close(); - previewWindow.document.documentElement.scrollTop = sp; - } - } - - // set keys pressed - function keyPressed(e) { - shiftKey = e.shiftKey; - altKey = e.altKey; - ctrlKey = (!(e.altKey && e.ctrlKey)) ? (e.ctrlKey || e.metaKey) : false; - - if (e.type === 'keydown') { - if (ctrlKey === true) { - li = $('a[accesskey="'+((e.keyCode == 13) ? '\\n' : String.fromCharCode(e.keyCode))+'"]', header).parent('li'); - if (li.length !== 0) { - ctrlKey = false; - setTimeout(function() { - li.triggerHandler('mouseup'); - },1); - return false; - } - } - if (e.keyCode === 13 || e.keyCode === 10) { // Enter key - if (ctrlKey === true) { // Enter + Ctrl - ctrlKey = false; - markup(options.onCtrlEnter); - return options.onCtrlEnter.keepDefault; - } else if (shiftKey === true) { // Enter + Shift - shiftKey = false; - markup(options.onShiftEnter); - return options.onShiftEnter.keepDefault; - } else { // only Enter - markup(options.onEnter); - return options.onEnter.keepDefault; - } - } - if (e.keyCode === 9) { // Tab key - if (shiftKey == true || ctrlKey == true || altKey == true) { - return false; - } - if (caretOffset !== -1) { - get(); - caretOffset = $$.val().length - caretOffset; - set(caretOffset, 0); - caretOffset = -1; - return false; - } else { - markup(options.onTab); - return options.onTab.keepDefault; - } - } - } - } - - function remove() { - $$.unbind(".markItUp").removeClass('markItUpEditor'); - $$.parent('div').parent('div.markItUp').parent('div').replaceWith($$); - $$.data('markItUp', null); - } - - init(); - }); - }; - - $.fn.markItUpRemove = function() { - return this.each(function() { - $(this).markItUp('remove'); - } - ); - }; - - $.markItUp = function(settings) { - var options = { target:false }; - $.extend(options, settings); - if (options.target) { - return $(options.target).each(function() { - $(this).focus(); - $(this).trigger('insertion', [options]); - }); - } else { - $('textarea').trigger('insertion', [options]); - } - }; -})(jQuery); diff --git a/media/lib/markitup/jquery.markitup.pack.js b/media/lib/markitup/jquery.markitup.pack.js deleted file mode 100644 index 16e1d48e52a..00000000000 --- a/media/lib/markitup/jquery.markitup.pack.js +++ /dev/null @@ -1 +0,0 @@ -!function($){$.fn.markItUp=function(settings,extraSettings){var method,params,options,ctrlKey,shiftKey,altKey;ctrlKey=shiftKey=altKey=!1,"string"==typeof settings&&(method=settings,params=extraSettings),options={id:"",nameSpace:"",root:"",previewHandler:!1,previewInWindow:"",previewInElement:"",previewAutoRefresh:!0,previewPosition:"after",previewTemplatePath:"~/templates/preview.html",previewParser:!1,previewParserPath:"",previewParserVar:"data",resizeHandle:!0,beforeInsert:"",afterInsert:"",onEnter:{},onShiftEnter:{},onCtrlEnter:{},onTab:{},markupSet:[{}]},$.extend(options,settings,extraSettings),options.root||$("script").each(function(e,t){miuScript=$(t).get(0).src.match(/(.*)jquery\.markitup(\.pack)?\.js$/),null!==miuScript&&(options.root=miuScript[1])});var uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},matched=uaMatch(navigator.userAgent),browser={};return matched.browser&&(browser[matched.browser]=!0,browser.version=matched.version),browser.chrome?browser.webkit=!0:browser.webkit&&(browser.safari=!0),this.each(function(){var $$,textarea,levels,scrollPosition,caretPosition,caretOffset,clicked,hash,header,footer,previewWindow,template,iFrame,abort;if($$=$(this),textarea=this,levels=[],abort=!1,scrollPosition=caretPosition=0,caretOffset=-1,options.previewParserPath=localize(options.previewParserPath),options.previewTemplatePath=localize(options.previewTemplatePath),method)switch(method){case"remove":remove();break;case"insert":markup(params);break;default:$.error("Method "+method+" does not exist on jQuery.markItUp")}else init();function localize(e,t){return t?e.replace(/("|')~\//g,"$1"+options.root):e.replace(/^~\//,options.root)}function init(){id="",nameSpace="",options.id?id='id="'+options.id+'"':$$.attr("id")&&(id='id="markItUp'+$$.attr("id").substr(0,1).toUpperCase()+$$.attr("id").substr(1)+'"'),options.nameSpace&&(nameSpace='class="'+options.nameSpace+'"'),$$.wrap("
        "),$$.wrap("
        '),$$.wrap('
        '),$$.addClass("markItUpEditor"),header=$('
        ').insertBefore($$),$(dropMenus(options.markupSet)).appendTo(header),footer=$('
        ').insertAfter($$),!0===options.resizeHandle&&!0!==browser.safari&&(resizeHandle=$('
        ').insertAfter($$).bind("mousedown.markItUp",function(e){var t,r,i=$$.height(),n=e.clientY;t=function(e){return $$.css("height",Math.max(20,e.clientY+i-n)+"px"),!1},r=function(e){return $("html").unbind("mousemove.markItUp",t).unbind("mouseup.markItUp",r),!1},$("html").bind("mousemove.markItUp",t).bind("mouseup.markItUp",r)}),footer.append(resizeHandle)),$$.bind("keydown.markItUp",keyPressed).bind("keyup",keyPressed),$$.bind("insertion.markItUp",function(e,t){!1!==t.target&&get(),textarea===$.markItUp.focused&&markup(t)}),$$.bind("focus.markItUp",function(){$.markItUp.focused=this}),options.previewInElement&&refreshPreview()}function dropMenus(markupSet){var ul=$("
          "),i=0;return $("li:hover > ul",ul).css("display","block"),$.each(markupSet,function(){var button=this,t="",title,li,j;if(title=button.key?(button.name||"")+" [Ctrl+"+button.key+"]":button.name||"",key=button.key?'accesskey="'+button.key+'"':"",button.separator)li=$('
        • '+(button.separator||"")+"
        • ").appendTo(ul);else{for(i++,j=levels.length-1;j>=0;j--)t+=levels[j]+"-";li=$('
        • '+(button.name||"")+"
        • ").bind("contextmenu.markItUp",function(){return!1}).bind("click.markItUp",function(e){e.preventDefault()}).bind("focusin.markItUp",function(){$$.focus()}).bind("mouseup",function(){return button.call&&eval(button.call)(),setTimeout(function(){markup(button)},1),!1}).bind("mouseenter.markItUp",function(){$("> ul",this).show(),$(document).one("click",function(){$("ul ul",header).hide()})}).bind("mouseleave.markItUp",function(){$("> ul",this).hide()}).appendTo(ul),button.dropMenu&&(levels.push(i),$(li).addClass("markItUpDropMenu").append(dropMenus(button.dropMenu)))}}),levels.pop(),ul}function magicMarkups(e){return e?e=(e=(e=e.toString()).replace(/\(\!\(([\s\S]*?)\)\!\)/g,function(e,t){var r=t.split("|!|");return!0===altKey?void 0!==r[1]?r[1]:r[0]:void 0===r[1]?"":r[0]})).replace(/\[\!\[([\s\S]*?)\]\!\]/g,function(e,t){var r=t.split(":!:");return!0!==abort&&(value=prompt(r[0],r[1]?r[1]:""),null===value&&(abort=!0),value)}):""}function prepare(e){return $.isFunction(e)&&(e=e(hash)),magicMarkups(e)}function build(e){var t=prepare(clicked.openWith),r=prepare(clicked.placeHolder),i=prepare(clicked.replaceWith),n=prepare(clicked.closeWith),o=prepare(clicked.openBlockWith),a=prepare(clicked.closeBlockWith),s=clicked.multiline;if(""!==i)block=t+i+n;else if(""===selection&&""!==r)block=t+r+n;else{var l=[e=e||selection],c=[];!0===s&&(l=e.split(/\r?\n/));for(var p=0;p=9.5&&0==t)return!1;range=textarea.createTextRange(),range.collapse(!0),range.moveStart("character",e),range.moveEnd("character",t),range.select()}else textarea.setSelectionRange&&textarea.setSelectionRange(e,e+t);textarea.scrollTop=scrollPosition,textarea.focus()}function get(){if(textarea.focus(),scrollPosition=textarea.scrollTop,document.selection)if(selection=document.selection.createRange().text,browser.msie){var e=document.selection.createRange(),t=e.duplicate();for(t.moveToElementText(textarea),caretPosition=-1;t.inRange(e);)t.moveStart("character"),caretPosition++}else caretPosition=textarea.selectionStart;else caretPosition=textarea.selectionStart,selection=textarea.value.substring(caretPosition,textarea.selectionEnd);return selection}function preview(){"function"==typeof options.previewHandler?previewWindow=!0:options.previewInElement?previewWindow=$(options.previewInElement):!previewWindow||previewWindow.closed?options.previewInWindow?(previewWindow=window.open("","preview",options.previewInWindow),$(window).unload(function(){previewWindow.close()})):(iFrame=$(''),"after"==options.previewPosition?iFrame.insertAfter(footer):iFrame.insertBefore(header),previewWindow=iFrame[iFrame.length-1].contentWindow||frame[iFrame.length-1]):!0===altKey&&(iFrame?iFrame.remove():previewWindow.close(),previewWindow=iFrame=!1),options.previewAutoRefresh||refreshPreview(),options.previewInWindow&&previewWindow.focus()}function refreshPreview(){renderPreview()}function renderPreview(){if(options.previewHandler&&"function"==typeof options.previewHandler)options.previewHandler($$.val());else if(options.previewParser&&"function"==typeof options.previewParser){writeInPreview(localize(options.previewParser($$.val()),1))}else""!==options.previewParserPath?$.ajax({type:"POST",dataType:"text",global:!1,url:options.previewParserPath,data:options.previewParserVar+"="+encodeURIComponent($$.val()),success:function(e){writeInPreview(localize(e,1))}}):template||$.ajax({url:options.previewTemplatePath,dataType:"text",global:!1,success:function(e){writeInPreview(localize(e,1).replace(//g,$$.val()))}});return!1}function writeInPreview(e){if(options.previewInElement)$(options.previewInElement).html(e);else if(previewWindow&&previewWindow.document){try{sp=previewWindow.document.documentElement.scrollTop}catch(e){sp=0}previewWindow.document.open(),previewWindow.document.write(e),previewWindow.document.close(),previewWindow.document.documentElement.scrollTop=sp}}function keyPressed(e){if(shiftKey=e.shiftKey,altKey=e.altKey,ctrlKey=(!e.altKey||!e.ctrlKey)&&(e.ctrlKey||e.metaKey),"keydown"===e.type){if(!0===ctrlKey&&(li=$('a[accesskey="'+(13==e.keyCode?"\\n":String.fromCharCode(e.keyCode))+'"]',header).parent("li"),0!==li.length))return ctrlKey=!1,setTimeout(function(){li.triggerHandler("mouseup")},1),!1;if(13===e.keyCode||10===e.keyCode)return!0===ctrlKey?(ctrlKey=!1,markup(options.onCtrlEnter),options.onCtrlEnter.keepDefault):!0===shiftKey?(shiftKey=!1,markup(options.onShiftEnter),options.onShiftEnter.keepDefault):(markup(options.onEnter),options.onEnter.keepDefault);if(9===e.keyCode)return 1!=shiftKey&&1!=ctrlKey&&1!=altKey&&(-1!==caretOffset?(get(),set(caretOffset=$$.val().length-caretOffset,0),caretOffset=-1,!1):(markup(options.onTab),options.onTab.keepDefault))}}function remove(){$$.unbind(".markItUp").removeClass("markItUpEditor"),$$.parent("div").parent("div.markItUp").parent("div").replaceWith($$),$$.data("markItUp",null)}})},$.fn.markItUpRemove=function(){return this.each(function(){$(this).markItUp("remove")})},$.markItUp=function(e){var t={target:!1};if($.extend(t,e),t.target)return $(t.target).each(function(){$(this).focus(),$(this).trigger("insertion",[t])});$("textarea").trigger("insertion",[t])}}(jQuery); diff --git a/media/lib/markitup/sets/default/images/bold.png b/media/lib/markitup/sets/default/images/bold.png deleted file mode 100644 index 889ae80e37b6167cc15f2a89e05a183815ec18b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 304 zcmV-00nh%4P)b^}|6b=Y6y(;Y{!a!g z@UQp#@Aw}>L3(}s|7f5BUjeuKZvQRjV<2U7yvu*H{aAbvQ6K!@3oKzW z-{Qa8d3gae1^)HE{~f^!v<1}u>;4xnKvUpW540I-w9J3a{{r=B3T*2g{_BH1CtaZO zpZ`6V0*V5g1e5i;`_=Z#_e=H*@8|93RG@lX;D!K7TKswwko8{x0000LlS^n5Q5c2KWM*m}YV3eAws|yDY&wl?DsIf8f*>k% z<*Hc~7ec_5rHi-`yO3f)SBkFeMi8|t(GpA*#H3ciSWBp+c{r^&PVFO&3C&}i$+#MA zZCZ-`mgm3cyWAfxp=la+gJD~$f3lF*v;Jqx`Q8T$Z@WYD zo5ULg-eG}Z89L0f4Zd=*mecc6xt8;=w2x)zu;*%)sVnHZF8Gfgv50&V?aO?Vg=C`G zqt8;QwVsqD3w#sp>uk4(?#r`&eMV@ShR&fc4IOUt64yxY7gl5?KAAs}zQf1Y-^2&g z$Gu&9-`V$(R7R2uQ}2HsoE!1T1^`G5aq_1Rg+NBCRv6kqwQ}ZBXMdtuFS`d*&78wH z%FqTXD^)8WCsqSp-l}5wzGHH~3TMv4``ZJRQO3=(w6oCI`;E z`gMDg;9p*xrm`moLYyi48W1M{s};+X6Y)q)IQvrJsBPN-$Qt1?9(Dn}gMTvW8Vj;U zv~1YHR;Z*VmZrvRmZz6cE&o6XK(RnVCGj2D!Cx>lhwjfzzEPx#2?dhIYK}l!BvcK! z3)ER+Jz{0oSgT$J*kO*Aq9I~CW*s{G*(t$KS{OS+#aO%?udUme<*TTEO`Fr@r_QT zk=#}u-n~>Vm!+9S1PE{@3<)G~CPb<$Za;W?3+O}|+q)?*Pn355=}S(XIZmEANjZci zf5 zj<%@MX^bD1^BwlS^+AD|$dm-1wial0hwPI;CDM?Y9SXW#@w-UF0SQ8OgplRTleOB2 zUjkDS|0U9pI|lSN*EvXUa~*UIclJdZ#)Npbwh9>YT?Z;=B8|l&^t~P~om?<5Lre$+ z;%`P>SL7`djY#8Y9$wv9dv|3p)C#5QQ<|d}62BjvZR2H60wE-$B^mK6y(Kw&{<9vg>Q9!g~ne(gm zmj4swoA@7?D86%i^8WzK9JM17E&sp&Z#dpHfz$E-U9ks&4?Z9Gyg!%0k2Q{M-Tz#> z2OnD>vrPZ*#{EHKLq)>Jcx{H|Ovdb&|4aQZWSipI{El%e^Cxx{^9vSw28s;a3IDB= TS1%U=TF&6<>gTe~DWM4fm>N^1 diff --git a/media/lib/markitup/sets/default/images/link.png b/media/lib/markitup/sets/default/images/link.png deleted file mode 100644 index 25eacb7c2524142262d68bf729c5e2b61adfd6d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 343 zcmV-d0jU0oP)$`dXYaZs9=SbAto%g@>T~?_bH&lTUn@`uo|1bXE{eSR(AO)ESb=V4`uk}mK|39Px&03WLbv~pzk+s7D@lK^ zn+aB+sp)&Y_x-B3>;6ywU--WQNUr<8>TU0P-|L#1U&;A)67w(+> pDf@fM7q9#F25QXo3rUI;002ro52U44e~JJA002ovPDHLkV1l;_q@Mr) diff --git a/media/lib/markitup/sets/default/images/picture.png b/media/lib/markitup/sets/default/images/picture.png deleted file mode 100644 index 4a158fef7e0da8fd19525f574f2c4966443866cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 606 zcmV-k0-^nhP)Q2rnAt>LM%-F zK|rtwgcU)}7x~z1Hrcs5bH*ZO$!>xO8K#?==bZPQ_ecnV>#P`H`QzGaRhd62G_&rC zTLU$c7_x*nFP_dW#Q+*);mMHE?j)HexK784D4x9l_tfpz2$@1y}9rkF+ zI+J5NMWeZyObc!d+rUc=>D+uOdAOg#%+Ej6h+wn5^xPmVVH*Eu446Y0A_@ zo$rlds-+sL10DbHs{AQG2a)rMyf zFQK~pm1x3+7!nu%-M`k}``c>^00{o_1pjWJUTfl8mg=3qGEl8H@}^@w`VUx0_$uy4 z2FhRqKX}xI*?Tv1DJd8z#F#0c%*~rM30HE1@2o5m~}ZyoWhqv>ql{V z1ZGE0lgcoK^lx+eqc*rAX1Ky;Xx3U%u#zG!m-;eD1Qsn@kf3|F9qz~|95=&g3(7!X zB}JAT>RU;a%vaNOGnJ%e1=K6eAh43c(QN8RQ6~GP%O}Jju$~Ld*%`mO1pC#5QQ<|d}62BjvZR2H60wE-%c@9E+gqH#X?$N2_%qkv$?&V++! z-fX$@sb%KG-5a$|R8J4(Tcmu7`G0cYgxS-++3#dN^zA^J(=P8r|6lx9G_LLaZ+v5S z!d9iC@)!RP{FnQmdw#}3Ee(C$|NPA#|L6YmR@fBO9w|C7oMMQ$vc`Tu(RETvC<`(>OPJ!ieM-fH~m>7>j\n'}, - onCtrlEnter: {keepDefault:false, openWith:'\n

          ', closeWith:'

          '}, - onTab: {keepDefault:false, replaceWith:' '}, - markupSet: [ - {name:'Bold', key:'B', openWith:'(!(|!|)!)', closeWith:'(!(|!|)!)' }, - {name:'Italic', key:'I', openWith:'(!(|!|)!)', closeWith:'(!(|!|)!)' }, - {name:'Stroke through', key:'S', openWith:'', closeWith:'' }, - {separator:'---------------' }, - {name:'Picture', key:'P', replaceWith:'[![Alternative text]!]' }, - {name:'Link', key:'L', openWith:'', closeWith:'', placeHolder:'Your text to link...' }, - {separator:'---------------' }, - {name:'Clean', className:'clean', replaceWith:function(markitup) { return markitup.selection.replace(/<(.*?)>/g, "") } }, - {name:'Preview', className:'preview', call:'preview'} - ] -} \ No newline at end of file diff --git a/media/lib/markitup/sets/default/style.css b/media/lib/markitup/sets/default/style.css deleted file mode 100644 index 26cb927b830..00000000000 --- a/media/lib/markitup/sets/default/style.css +++ /dev/null @@ -1,27 +0,0 @@ -/* ------------------------------------------------------------------- -// markItUp! -// By Jay Salvat - http://markitup.jaysalvat.com/ -// ------------------------------------------------------------------*/ -.markItUp .markItUpButton1 a { - background-image:url(images/bold.png); -} -.markItUp .markItUpButton2 a { - background-image:url(images/italic.png); -} -.markItUp .markItUpButton3 a { - background-image:url(images/stroke.png); -} - -.markItUp .markItUpButton4 a { - background-image:url(images/picture.png); -} -.markItUp .markItUpButton5 a { - background-image:url(images/link.png); -} - -.markItUp .markItUpButton6 a { - background-image:url(images/clean.png); -} -.markItUp .preview a { - background-image:url(images/preview.png); -} \ No newline at end of file diff --git a/media/lib/markitup/sets/sphinx/editor.css b/media/lib/markitup/sets/sphinx/editor.css deleted file mode 100644 index e2b6ded6499..00000000000 --- a/media/lib/markitup/sets/sphinx/editor.css +++ /dev/null @@ -1,48 +0,0 @@ -/* ------------------------------------------------------------------- -// ReST! -// ------------------------------------------------------------------*/ -.ReST .markItUpButton1 a { - background-image:url(images/h1.png); -} -.ReST .markItUpButton2 a { - background-image:url(images/h2.png); -} -.ReST .markItUpButton3 a { - background-image:url(images/h3.png); -} - - -.ReST .markItUpButton4 a { - background-image:url(images/bold.png); -} - -.ReST .markItUpButton5 a { - background-image:url(images/italic.png); -} - -.ReST .markItUpButton6 a { - background-image:url(images/list-bullet.png); -} -.ReST .markItUpButton7 a { - background-image:url(images/list-numeric.png); -} - -.ReST .markItUpButton8 a { - background-image:url(images/book_link.png); -} -.ReST .markItUpButton9 a { - background-image:url(images/link_go.png); -} - -.ReST .markItUpButton10 a { - background-image:url(images/picture.png); -} -.ReST .markItUpButton11 a { - background-image:url(images/quotes.png); -} -.ReST .markItUpButton12 a { - background-image:url(images/code.png); -} -.ReST .markItUpButton13 a { - background-image:url(images/indent.png); -} diff --git a/media/lib/markitup/sets/sphinx/editor.js b/media/lib/markitup/sets/sphinx/editor.js deleted file mode 100644 index aba41f5cbcd..00000000000 --- a/media/lib/markitup/sets/sphinx/editor.js +++ /dev/null @@ -1,73 +0,0 @@ -// ------------------------------------------------------------------- -// markItUp! -// ------------------------------------------------------------------- -// Copyright (C) 2008 Jay Salvat -// http://markitup.jaysalvat.com/ -// ------------------------------------------------------------------- -// ReStructured Text -// http://docutils.sourceforge.net/ -// http://docutils.sourceforge.net/rst.html -// ------------------------------------------------------------------- -// Mark Renron -// http://www.indexofire.com -// ------------------------------------------------------------------- -// Jannis Leidel -// http://enn.io -// ------------------------------------------------------------------- -mySettings = { - nameSpace: 'ReST', - onShiftEnter: {keepDefault:false, openWith:'\n\n'}, - onTab: {keepDefault:false, replaceWith:' '}, - markupSet: [ - //{name:'Level 1 Heading', key:'1', placeHolder:'Your title Here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '#'); } }, - //{name:'Level 2 Heading', key:'2', placeHolder:'Your title here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '*'); } }, - {name:'Level 1 Heading', key:'1', placeHolder:'Your heading here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '='); } }, - {name:'Level 2 Heading', key:'2', placeHolder:'Your sub-heading here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '-'); } }, - {name:'Level 3 Heading', key:'3', placeHolder:'Your sub-sub-heading here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '^'); } }, - //{name:'Level 6 Heading', key:'6', placeHolder:'Your title here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '"'); } }, - {separator:'---------------' }, - {name:'Bold', key:'B', openWith:'**', closeWith:'**', placeHolder:'Input Your Bold Text Here...'}, - {name:'Italic', key:'I', openWith:'`', closeWith:'`', placeHolder:'Input Your Italic Text Here...'}, - {separator:'---------------' }, - {name:'Bulleted List', openWith:'* ' }, - {name:'Numeric List', openWith:function(markItUp) { return markItUp.line+'. '; } }, - {separator:'---------------' }, - {name:'Internal Link', key:"L", openWith:':doc:`', closeWith:' <[![Heading:!:]!]>`', placeHolder:'Your text to link here...' }, - {name:'External Link', key:"E", openWith:'`', closeWith:' <[![Url:!:http://]!]>`_', placeHolder:'Your text to link here...' }, - {separator:'---------------' }, - {name:'Picture', key:'P', openWith:'.. image:: ', placeHolder:'Link Your Images Here...'}, - {name:'Quotes', placeHolder: 'block quote text here...', replaceWith:function(markItUp) { - return miu.indentText(markItUp); - }}, - {name:'Code Block / Code', placeHolder:'Code here...', replaceWith:function(markItUp) { - directive = '\n.. code-block:: python\n\n'; - indented = miu.indentText(markItUp); - return directive + indented; - }}, - {separator:'---------------'}, - {name:'Indent', replaceWith:function(markItUp) { - return miu.indentText(markItUp); - }} - ] -}; - - -// mIu nameSpace to avoid conflict. -miu = { - markdownTitle: function(markItUp, character) { - heading = ''; - n = $.trim(markItUp.selection||markItUp.placeHolder).length; - for(i = 0; i < n; i++) { - heading += character; - } - return '\n'+heading + '\n'; - }, - indentText: function(markItUp) { - text_block = markItUp.selection || markItUp.placeHolder; - indented = ''; - $.each(text_block.split('\n'), function(idx, text) { - indented += ' ' + text + '\n'; - }); - return indented; - } -}; diff --git a/media/lib/markitup/sets/sphinx/images/bold.png b/media/lib/markitup/sets/sphinx/images/bold.png deleted file mode 100644 index 889ae80e37b6167cc15f2a89e05a183815ec18b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 304 zcmV-00nh%4P)b^}|6b=Y6y(;Y{!a!g z@UQp#@Aw}>L3(}s|7f5BUjeuKZvQRjV<2U7yvu*H{aAbvQ6K!@3oKzW z-{Qa8d3gae1^)HE{~f^!v<1}u>;4xnKvUpW540I-w9J3a{{r=B3T*2g{_BH1CtaZO zpZ`6V0*V5g1e5i;`_=Z#_e=H*@8|93RG@lX;D!K7TKswwko8{x0000Ibg27S@bI=*bsb;IgkCPuV5Vkc|%HT6t6!`B9|*t zHpjbmR#Y%cB>BZ6G~K|TYq0zotNP0+pjRo1^k6y zQ(zK-ZCXSU!1IwY=-xjmu$Tf4f+)hU{HAV5V3E@>O&HWaHz0u%1Ry{!z_DJC&*o_V zmjEy=8pfOy7Z^<;&>NY@@?}se=09I0f1Ga6p zG?rs_c2-+00f7M84LlS^n5Q5c2KWM*m}YV3eAws|yDY&wl?DsIf8f*>k% z<*Hc~7ec_5rHi-`yO3f)SBkFeMi8|t(GpA*#H3ciSWBp+c{r^&PVFO&3C&}i$+#MA zZCZ-`mgm3cyWAfxp=la+gJD~$f3lF*v;Jqx`Q8T$Z@WYD zo5ULg-eG}Z89L0f4Zd=*mecc6xt8;=w2x)zu;*%)sVnHZF8Gfgv50&V?aO?Vg=C`G zqt8;QwVsqD3w#sp>uk4(?#r`&eMV@ShR&fc4IOUt64yxY7gl5?KAAs}zQf1Y-^2&g z$Gu&9-`V$(R7R2uQ}2HsoE!1T1^`G5aq_1Rg+NBCRv6kqwQ}ZBXMdtuFS`d*&78wH z%FqTXD^)8WCsqSp-l}5wzGHH~3TMv4``ZJRQO3=(w6oCI`;E z`gMDg;9p*xrm`moLYyi48W1M{s};+X6Y)q)IQvrJsBPN-$Qt1?9(Dn}gMTvW8Vj;U zv~1YHR;Z*VmZrvRmZz6cE&o6XK(RnVCGj2D!Cx>lhwjfzzEPx#2?dhIYK}l!BvcK! z3)ER+Jz{5>jf6w4x#gTU%_MMNlkNp$oSbvBp&uHw9M;u0-4@=t5BI zP6Hx#-C_{5RMJ z0_P+Xkumexn8%)S+Y)#l(gR;YJP<6#1-=jjK0LONWPdJQIR8uK1HpvVIxBIQ2ztt+ zqoEx_X9S%QGMe=~(k#sebCL-an)%CR%a7YtUOQUgv+G>~?N~XSWhx=? z@$fx}0MB;$`JWcQ-Re{XV~5|{DvU(#*+NF*g)j^qk#b~G9_O!i*y&mZVZ=a3;Go(K z`DkskYn56Nhu+k@1Ke*uY|x zI&k6j$JfNe_a{GH%=n2rZOz$Z8R9V?Pe36hIk}jo+A-`;dt9vyvBu#Xm@veu&@v`| zzt%mwc_$nd0-sMVx2d)b0!MqGxmfCumx7yB#nIUWvA{!HOMfslMyW1iV&nY>zxwyj z8^JfLN|kT z4m^Q1mhO(_r4w@`V?H=YNkOf(i&bHT3Auc3bryK1_{hDSetLoLN{VLB^78ULiNFy^ zkUqqG$fjVkJj5tfWkOn|P5`HVEp5@-mGnc0wvJGHC=+39MC2TWT#i?t*~fNch*he_ zgtS^8dH$(KlW)EF1b4Fzv~?&0IQaNdg;W5&{t&Bmg9&N1-rBBr_;Rg8ekw^mn;@T# zlS{|Rq+-Nlg18i%UY;i|q1NnSwf>I@85#4U4002ovPDHLkV1mEDi4_0< diff --git a/media/lib/markitup/sets/sphinx/images/h1.png b/media/lib/markitup/sets/sphinx/images/h1.png deleted file mode 100644 index 9c122e91e358860733eaf08fd543e5fc585d4cfd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-$x=IP=XqH%ujg^j!|20W|*-XbO@ zAtBSd^khRzd{=pNv@vN)9uZDqGTXuVPf6#I=?;x2B`Y;1YQMI>>GxvE??vtn{c>{A z7MYxUVrui2JTF|YR&ldntL8M3{q7no52$4`vIX;r@S8@YTFOM5*~nV4Gk-UYI5L$} zDw(h9UDksmVjphbEsSQ?UdGUxU4Htk{EZoY&3@-Y5*_;Wwk`ZAkg@!FaC~ii{N>;; VD%(>GD}XL$@O1TaS?83{1OVXtVO9VD diff --git a/media/lib/markitup/sets/sphinx/images/h2.png b/media/lib/markitup/sets/sphinx/images/h2.png deleted file mode 100644 index fbd87657fbe001c0a78fb095284fffc32e739497..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-$ROXGNhtQ`{C(%$wdeB3 zGTnLdz~IMJtNg?T>Z(s;oVU0)KW5x*9xvq)rPF;` zY|Fc4&#rLa>Txf#@y+aKf+ac0%`STzAI(*qdYo^XFH557y+_x*JpKO5^1S9?c^6}{ zP=+&OVHtDUrGNmdKI;Vst0KHFj AM*si- diff --git a/media/lib/markitup/sets/sphinx/images/h3.png b/media/lib/markitup/sets/sphinx/images/h3.png deleted file mode 100644 index c7836cf09e4565cc76c13bd14c13971c9e093c40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 306 zcmV-20nPr2P)wEzGB diff --git a/media/lib/markitup/sets/sphinx/images/image.png b/media/lib/markitup/sets/sphinx/images/image.png deleted file mode 100644 index fc3c393caa3bc4371d12d0c67ffd6d333ecf1d8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 516 zcmV+f0{i`mP)0oSgT$J*kO*Aq9I~CW*s{G*(t$KS{OS+#aO%?udUme<*TTEO`Fr@r_QT zk=#}u-n~>Vm!+9S1PE{@3<)G~CPb<$Za;W?3+O}|+q)?*Pn355=}S(XIZmEANjZci zf5 zj<%@MX^bD1^BwlS^+AD|$dm-1wial0hwPI;CDM?Y9SXW#@w-UF0SQ8OgplRTleOB2 zUjkDS|0U9pI|lSN*EvXUa~*UIclJdZ#)Npbwh9>YT?Z;=B8|l&^t~P~om?<5Lre$+ z;%`P>SL7`djY#8Y9$wv9dv|3p)A?80v9Z^YZA8as&YaOiG2qAVzYLj+o?N|k`)kPFX7%epMT)pIgD?z$ zz0k7x#eWfQHil2%e>0rE^YzTbTVLW%P1UySD{rve8ZZphV4}^gtsg#oV8j^<1D2Tp2_^}JGDwbz00000NkvXXu0mjfU=gFa diff --git a/media/lib/markitup/sets/sphinx/images/italic.png b/media/lib/markitup/sets/sphinx/images/italic.png deleted file mode 100644 index 8482ac8cb1eb8bc8edbf64085108f0fbd204fadb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-$B^mK6y(Kw&{<9vg>Q9!g~ne(gm zmj4swoA@7?D86%i^8WzK9JM17E&sp&Z#dpHfz$E-U9ks&4?Z9Gyg!%0k2Q{M-Tz#> z2OnD>vrPZ*#{EHKLq)>Jcx{H|Ovdb&|4aQZWSipI{El%e^Cxx{^9vSw28s;a3IDB= TS1%U=TF&6<>gTe~DWM4fm>N^1 diff --git a/media/lib/markitup/sets/sphinx/images/link.png b/media/lib/markitup/sets/sphinx/images/link.png deleted file mode 100644 index 25eacb7c2524142262d68bf729c5e2b61adfd6d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 343 zcmV-d0jU0oP)$`dXYaZs9=SbAto%g@>T~?_bH&lTUn@`uo|1bXE{eSR(AO)ESb=V4`uk}mK|39Px&03WLbv~pzk+s7D@lK^ zn+aB+sp)&Y_x-B3>;6ywU--WQNUr<8>TU0P-|L#1U&;A)67w(+> pDf@fM7q9#F25QXo3rUI;002ro52U44e~JJA002ovPDHLkV1l;_q@Mr) diff --git a/media/lib/markitup/sets/sphinx/images/link_go.png b/media/lib/markitup/sets/sphinx/images/link_go.png deleted file mode 100644 index ae8cae806e830b35ca5211758454911215fa9824..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 655 zcmV;A0&x9_P)+WKzZym|j?YHA+l_EP7bFIf1E~S2MKQq0 z$cW9y$ER!J#EJi3ym;~d?%lip4<0=Dzp=6LUUhZ#p_?~v{s4&`IdbGbNDW9WNDtfq zLqkKq;^N{DSFc`u7ZDM$&D-1iPikuF|4EZ3{jaR7{10M-#6WT@R;+jkQVY_9?1HYQ zrl#+cCr?iI_xIVNnQjsGCEAU$vcG=ad^ z*Y|pFZ}0n6t5&^Tw{G44{H3=4a~E0sPhVj2KWVPv|C;ro|5u%!_`hVe|9{s$iGP~f z8d`7z)YR0NfzCGY^76W$l9KWzJ3IS(_G0t@8_rGpzxM1Du*MaqC;XqVr{w>_<6ZwV zmb(2nZD;?j+sw#_Gk%kS{sn37+m-*nb4T|7)@^D38#X8YZ`zvvf5xHa|1k?}{;SqA z{KRQM^lZ)lD^E@Mzw|`!|Aoi8{?9ww0W>7*|MWvm|I?Ow{8y}HxGr7Ez=_j4b?z7aYu(NNH*UVw|7iys{wFPV`!8S1a8a_7ft{qJtliA`I)0(^fB9;LGeFI3 pB$Rr>${ diff --git a/media/lib/markitup/sets/sphinx/images/list-bullet.png b/media/lib/markitup/sets/sphinx/images/list-bullet.png deleted file mode 100644 index 4a8672bde48f806d3d4d37db192588a9aa3eac10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 344 zcmV-e0jK_nP)PbXFR5;6H z`2YVu10|S&DhA}te_Swi*Xsu$nk)lAnzx?+_#Z@r_~qs0*+Bfiq@?73K|#U)?Ck9S zsi~>|6A}{sM@B~e4-O9gPhA%bd?2RGd{of6>E(lvp1b6Ep>6&12TPB<{a?EDDL4@0 z;^ML+A|n0=1_u83^78uc?CkvC#>VEqiHXU7U0vP(YHDhzff&$ntDt1@;|H#l*M@2! z+U8#>h@W=vfpy*`^1J}j+`sMRe-I7g8yOj8Yin!&S5Z;VicFNp}SURRVGD{CSNFe~ni^^#wyl5uzj4je z|23%2?k#{x(*%mqe9M%mih+W%ElRQ}7!$^91> z7ymCLB=nz$hvz>#JNtiTW@gkt1Zf0eyP_){bPq%T_kY#2Z7&xs00000NkvXXu0mjf DNYA0= diff --git a/media/lib/markitup/sets/sphinx/images/picture.png b/media/lib/markitup/sets/sphinx/images/picture.png deleted file mode 100644 index 4a158fef7e0da8fd19525f574f2c4966443866cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 606 zcmV-k0-^nhP)Q2rnAt>LM%-F zK|rtwgcU)}7x~z1Hrcs5bH*ZO$!>xO8K#?==bZPQ_ecnV>#P`H`QzGaRhd62G_&rC zTLU$c7_x*nFP_dW#Q+*);mMHE?j)HexK784D4x9l_tfpz2$@1y}9rkF+ zI+J5NMWeZyObc!d+rUc=>D+uOdAOg#%+Ej6h+wn5^xPmVVH*Eu446Y0A_@ zo$rlds-+sL10DbHs{AQG2a)rMyf zFQK~pm1x3+7!nu%-M`k}``c>^00{o_1pjWJUTfl8mg=3qGEl8H@}^@w`VUx0_$uy4 z2FhRqKX}xI*?Tv1DJd8z#F#0c%*~rM30HE1@2o5m~}ZyoWhqv>ql{V z1ZGE0lgcoK^lx+eqc*rAX1Ky;Xx3U%u#zG!m-;eD1Qsn@kf3|F9qz~|95=&g3(7!X zB}JAT>RU;a%vaNOGnJ%e1=K6eAh43c(QN8RQ6~GP%O}Jju$~Ld*%`mO1p?P)vCi#|P&Xm-dkucwL z3)87{8iWe96huvPHfK`KOdC2Z({T6vJ9pwDx$D4>d(Pqff6w7Lmj{5i6;ZyPPpPN; zroaW=6d#@oL2Fa53F~$Su10(RG%K0p3VTuP3?Z=nBA8z$uq+XLUL^QrC74`bU|!e| zr>hK{)%Q!vdmIO5Z3JIvaOyjOX`X@c8-ua03`Q&)f&%p*{(A$q`ZTTjk%q_T7>v^J zu!R-a9fFLScYlKkNBP_Cob=9m9JLVoC-?c{)eOtMnh7qNN{ejy2sM{pS^mgFHJm@(buuM4>=<5Vr$&Kzw{B?uPr; z(1Yf=#g)zADkWnx=MR%ykl| z3Ui42k+O2{bCn)01-s5Sxp|z{G2di&KT(_M6;$EI zDL57JFf}cw4bP1P$pgTRKH$0@h|~aA>j`qZ2*kU5t2EVD5#~@VNhqx{vz8ethDD-=+1vnemftUBA zF;N!Q%PBB5B=KLB#QO(CHe?;R+-C8M?ppDW>R$5`cCPq@YpusFRTaH1i9Kv;l<>I( Ze*oTy+;kdDB`N>_002ovPDHLkV1l3CM+g7_ diff --git a/media/lib/markitup/sets/sphinx/images/stroke.png b/media/lib/markitup/sets/sphinx/images/stroke.png deleted file mode 100644 index 612058a78eba4e3ca259aa13417fd60cd6cf2fbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-%c@9E+gqH#X?$N2_%qkv$?&V++! z-fX$@sb%KG-5a$|R8J4(Tcmu7`G0cYgxS-++3#dN^zA^J(=P8r|6lx9G_LLaZ+v5S z!d9iC@)!RP{FnQmdw#}3Ee(C$|NPA#|L6YmR@fBO9w|C7oMMQ$vc`Tu(RETvC<`(>OPJ!ieM-fH~m>7>j%B z4k5JA6H*_)|9AiQzW3Js*8A3ach){ulrhW#MW~qG4g_>g;H3WoPkF(azP{%h}c5?V)7-rwQ*X)WR>W28Q0*2e9hf zA;G5aEfmcsAz_ntwAa(U;(@8L*MeeVuhsf&qV-&)n~2|N z$5FOi>**%-;S&x8o#gv_f8zD{;XULxD6;5`26s}uz0n{qVvm8o#LK*K64LLCJz-X5 zuf&+ss!BU5D=W$3%p?wbD@I2@m1{@?+2VRV+e@V@e`$@o*}{;GnEPrB|j z{b0XAX`@BX?u@yvv2S#FuO^DM`m}oeLo2O7>~ZCk%IO=H7<=s<@67FpR|-^~yV^VD z≀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 P{l&>kD@#>M7zX_>Y$iK| diff --git a/media/lib/markitup/skins/markitup/images/bg-editor-bbcode.png b/media/lib/markitup/skins/markitup/images/bg-editor-bbcode.png deleted file mode 100644 index 39cdbd832bfc3ab8d3dc1d00ef45298ed6b06c25..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1642 zcmeAS@N?(olHy`uVBq!ia0y~yV15B)pWt8ul3!Y5B!Coiv6E*A2M5RPhyD+MT+RZI z$YKTtZXpn6ymYtj4^U9P#5JNMI6tkVJh3R1!8b9vC_gtfB{NaMEwd=KJijQrSixdz z#-$3NQZbNH=c3falFa-(g^b+fH8Q=U1+?g}A&6w0wS4*Vjo*Q$h(N5^ zdlu+0hQlj?dfvUuyS4i3*RTJ~fFgg+tl$BfHKRP_*b-hKmpOK^(e~}zC(BDqOMhO& z$iVO{C4>#=Iu1}cDBNLWP;j_U;` zkknkTvA2hW?*VXFWLV#ejgP4;k3yjVM z&Oo=D*31DWU|29spFSNqn7}bna#yRku+Z@5#=U!O&r2~dB>07HKlNoRFc@a^21>%h z0pi;

          ?i$Qwcb98o&x3poNUX)t=u!e^wUuN&|Pa}YFDaLwi*~qJjcOt^+Iau&n>%mTmLMqswC=M+$Y0jvU?IH6(pkMZ)!lb#(0i|Ni}ZvVZa7#hL!V zr2P;nX@iqUKbP0l+XkKOrq?L diff --git a/media/lib/markitup/skins/markitup/images/bg-editor-dotclear.png b/media/lib/markitup/skins/markitup/images/bg-editor-dotclear.png deleted file mode 100644 index b3188dcd5625c7c0a137ee1315a0e6ccf755fb20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1682 zcmd^<>rdNd6vt1C8{LIVw#m(Lc{5zdfNn#_Hc}|1796rFWe7!A2wlNh+flH!P}(qs zY$R4kx-bOGrjZQ|mkjBaIAGKSk<@|UFq_p?KoM3JV9h490!i@dx;Ii#$C~ z0kCZc^`d=mt#;yJP&xP2a!#4Ju)I|ER+OMrDhB4^_ydXY%tP%tnMRBVp(3(nr^=Ou zWny3#%ZkKNFO-&vm9nzaisRQKvj8?d%1C1iRLyp4|FQWuLxyY(oXxk{@|;~S@7^tV z82Rwzr>!+L$${Kpwy&=*TV0!4>zJ5+M>^gdUog4r9{=M-v!&&;BP^C{6M*ynoWWqY zdwPxcXf*c!^@dbxPj)0wz7&!iyiaE+0T}$AslL8G)=iaK z-Bgh9%mGU-Uead%M1v@u+!u5pb;pbk)?%uC7tT?c_o@?D9#wwTy9Egj6Ky0<6m=tI zWoc>2s?_WCGs!*O-TU>+SS`Eph7Y6w(RS~I7(k~@8*}3snA?SYl`7R<_hpO4awz~$ zG9^QlTat0KH)g!#uBd4yw0=K8S2{PK&85-v@@XLY@QZIzr6(n^+ciZw_fkDbr4e*? zcK)JKYPBa_9HCISoEQMWk9>*K;6D$MfYbbYM!$^3mn!E5(TwL55%NK1AuE+5; z)z$u<%4EVyDic?n&Z@HR{{H?C2+vD|_|0271U9QDL0+Bc)f!5hTUsi9R>kIbc+J-afssPY*1n$st${y!gT;kx+@J=)ZSqYjY4%}VP?71jI$B!UcS diff --git a/media/lib/markitup/skins/markitup/images/bg-editor-html.png b/media/lib/markitup/skins/markitup/images/bg-editor-html.png deleted file mode 100644 index 11bff456808bf9f846ae0af5b4b0a7c3cfc020fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1534 zcmeAS@N?(olHy`uVBq!ia0y~yV15B)pWt8ul3!Y5B!Coiv6E*A2M5RPhyD+MT+RZI z$YKTtZXpn6ymYtj4^U9P#5JNMI6tkVJh3R1!8b9vC_gtfB{NaMEwd=KJijQrSixdz z#-$3NQZbNH=c3falFa-(g^6968`{@d_u)A# zSPitA#bPQWLqo&EmoGElNir}r2%3S6*sx6+Xk0>Z*xt}*|Nhne;(z=8eSI}BViGKu z8-c7Sod8nx3h0J|2M@L#2O1Yvs0H*b;~|h|)#jeMbN6m<-Em7^28Nuz_F$l|4y**( z=3_P0(#Gb_7a5?ZxxiK_fZUmI>F~!JO4Z;h68)l_J*dN0=l;0ERqYrVFV768D9!sef|3NMR{L;|8+xt28Im~ zQ+#gi@P9aUB9L#n`XBQ$eRXy9+4F!th&Tv#C?YrwUOo(g*aQyJgo?__nP{%LdiClT z`CmUjKi}TY$iOgdb0ILm8$9!;&O9_b9Tbdh*RNlHd4J!YJ%9cbR8{SoSqXHl>YP&y z3=ZJ9X|Uf@Sbh;0KlPIlQCR>EPUKLiuKvA#e{4*Q&;Ny+H*YRI19Ys;$9D5~`-{H< z_0E1A0t_Oiw(sA+?*v-P;C2I)jF93!yBZYV8!QnbEH;^DfgaO!ANCNrs z&?%fm4C$FzJKp;2$bK@)N9Saz`{|^z`zkv z9`dZexw(120WcUph)RRR1Q5EfNPagw4>WOhGT8P*vJ4DNEeOqhl`met%=|F(@ZrPq z{LBmtYs_A)HA=4d%)`Kt)3?|N=!gv!m6bEWZfgKr>QirTJ4UYieZvySlr( z+sgsn9&t8M5@`1aD-R$k@s)o@Uw{ApUoRd$Ok5Snz|gSXLJMdGMi7zAv|6=zsH#eU>59p7Gu=>(i63~ojP zEoeBqu@E(|=YaVLvmdMg1`rF@cmewv$r<283UTr2l~_UzVfll#p!9?usuqX<2OD(& z9GV-@90*RbI(Bw;$XN*yH3&d{w^BkBf O89ZJ6T-G@yGywn>7PO22 diff --git a/media/lib/markitup/skins/markitup/images/bg-editor-markdown.png b/media/lib/markitup/skins/markitup/images/bg-editor-markdown.png deleted file mode 100644 index c1997152233017b54827cc41e07d0a2870c3ddba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1783 zcmds1`%hD682)Gxk;zK7F_25kE+ojZ70Wh?a;ZpB!d=R6p$r-=f(#0!P}maMm@RTC zb0(`(Afp*k3L$z*w?BU_bQhIp2A|_kG^y zdEPHSJoLDwg`EXL$TIMR|4D?%26*l=C&9Y(E!P(Q$Qgct9CLH?kw;-Vc-@zF;`0oI zUV8)kne>n4uEQox#6Bg86eNhmJRu*2@Jl6F4A@pr5 z^q7#(6D0{!oj6G;eB|ayXE5n*9#v7nWeAyt1o|K4WS7p21qC^Tyk(}V^$p-QT8*B| zv&qwa`2LG{$)$pZyaEruPd}>bdiM)fkKYwGV<7fU@JP!uuNw(f*FC#`Y_FU;mz+H9 zi;ym5IwUMi97{&1SK;CAK9FgN5R2?6M##Lkq_}uWZHAEIs6Z&Jo3=wpYNpB0&#y@a zpmyupOcRK8|J@NGlKCt`R*LATK~=p#+ahmG%*x7gScWjNp^=PO2oHKtba$zzr$^&= z5TQ1=!`Km4+Fm3@=Z_#{>QbCe{}XWhdc1Qh@!WV3cRxaIr}}O( zoJYOj$jl*ESWT)*N=gW9cv0yuJy09XR5nLFF&fqD>^W^KtqC-XcPnQ=?Y7MCG0>@; zgxuVg`OWC)Xuazmgls#Mkloa3)C4)P#+0%{a3cFXhtNF$G=Pur&3m_R`{_67bb4nr zhUCh3SOYIlJbF-ASh!&0Sqiq9=}X`0PuU{b9N$52xcK5)oMUJ#m+OFoQmJG3FA8Fy zg2MY%onUQ$f4}P5;^N}GHMFw-y8d{DZ7sRWCS_D45-lyL z)at`eZ7}L^TPYGdG;{ZR0!B=b&YB|@iyt>rD3mzr(9qCuC6KFxu_AaNk;F1Q;T8@wQUd;8Xz z$xXN>WMhA{luo6&g0DMqE|m82$+gvaeRuo#__%@g`a( z_^(Y!IeWHZon7WDp%N2uAriAs!~x7%9GbAKk`R4@y(h9!8U1}Jt#%JW^>#KPSF2e@SaCzIwtUhJ%on=Nx z(k`Y_aTD*jM*g)ixVV_{@DnI$xm(`dsCQg6IFSEn@c$GljZ1o-Pw9SYp$C#sAUo8* I#xMT--?jQjjsO4v diff --git a/media/lib/markitup/skins/markitup/images/bg-editor-textile.png b/media/lib/markitup/skins/markitup/images/bg-editor-textile.png deleted file mode 100644 index 3ab1e9f6e21ebbedd072bef63d352d26720801df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1659 zcmeHGe^8Tk7=M70`2+I2+!?UgU#6%Hu^$7HEgdK-8_LGf4Tw2klCv=yQ$(BYOkG_V zSEPr8wZl6hV?cH0&O308+!WXmDCcmSFtxQNEUyJP&q2@o-F2?I{_dat*t>n-J>Tc~ z{CYmf7jBAMkgxy%;&L|&b^ye9@%L3mG(LYnR=fZIjOInmu&k2;OU`U!RzAv&67^is(B?zR`*+<=P;Rlr*;V5 z{~>YulY62S+s&3E$GW;6tUlLXxz4(NrtxR#%?nMQ=QH|6tz+pULqkJ60Mneb+i2uY zCje;Ur-p}z?R#)~hW(vb(8842Y!07q1OfqhXB2=pf6!(-(LE19-+Nik!CLQfXB4ot zRrH0u5(zIf{qUjvwbdNXOc1NQ*FMSwcxtg9V6k2y_Bh&mu**5Ql?4#Zr~zQ)&-w1_ zbUKfWqA2YZY}k;Oez){DyxX|+Y#LtU8)JYE?s$Nxqjawomn5Fq*`7cgKx%V~l-gpH zVDWLe7@yH%kw_EEfF#VTn|F zzZ+vx_RV)v>d+Mf@=8r2?DPj}Yo9xaT==o1i+-}oXS3x6x_WwMUm!qNWi`l(YS&(izVk*qTnd8FI!izm21M(_O47gIqGyK9Y87g3;#`2 z%Zas!s>3%mwKq(lt`Ez@!rv-)c6M|$=?n%#))QT@<4dXOc@wOJ8}$;c)P} zQQYH^{=SqFupLF@buE(_SDDvCOK}P-%>Bin_s*S`TKni|@E6+7zX%x$g<8k9cw_?u z7}I2Qy}XbfeSIx4?tFcH{nt0~tPTr;2nPoTKhwEfu74mj#^V}Bhcite-?;qf(Zoc1 zt=-{BEJN0&UHfQnO`oD-x3TB9JD=o}xX#D?w6?aMQR14opJfTxxT{hC7FmfSZCN~? zwG`9zoKV&b3M3e{iLCCV`a#W@uGxiJJzBe6?yvG3i?tStXy z&-l20W+zU%MjX(#Y(KrkQh^t_*=N&mRW^2FyWKL9_lRH~B=KaCoziGD;U#^KoFkG; m21eW>d;9-OTDAXHr3cCP;w#&V1Vs`IAmnBX1sxm8j{E@>bO@OM diff --git a/media/lib/markitup/skins/markitup/images/bg-editor-wiki.png b/media/lib/markitup/skins/markitup/images/bg-editor-wiki.png deleted file mode 100644 index 7887181cc73d3c653ed7c3e92e2307accacfb502..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1488 zcmeAS@N?(olHy`uVBq!ia0y~yV15B)pWt8ul3!Y5B!Coiv6E*A2M5RPhyD+MT+RZI z$YKTtZXpn6ymYtj4^U9P#5JNMI6tkVJh3R1!8b9vC_gtfB{NaMEwd=KJijQrSixdz z#-$3NQZbNH=c3falFa-(g^=1J_Eyp z|J!cdzd!#s4+F!2mZJv`9=wwdv{h}!4rT_214;S$`R|N@d||QOyLT7QXJlZQvEjze zn=>KG?-$DhvB-TU|d|4~pm-Fx@e{aY}3@?@wJLnVQ(`|)hmnfp5DL1y#l>+3_j zn-I!|?9iP%BmX)sU%otBj+KES;@IhxAcMh5+OA)}z7wdK!N;Hw=q84Td<+bX($$ut z3=B8sZG5e;e*OCJ`U^L2-n`Wg@>m+e+@7_k)@=Iw$^W$p(CY7ykUy3;wa}WEfg$Jo zja6r^UcK5s7w9F4L=;VP=Fj*4x4%>h7{-ioeyl({R~rGHV_;Uef6tznzm94^UvIDl zkpc>!C`zcPuAU8!ITm41Y}~j}Isr8xA&x!-kD47|`+VT>3l41tYj9{j0{IWDbj>LS z28RYjEF*j(YfHmFG0(yuM;W%*mX^;iE3n~1gTe~DWM4fEfK1( diff --git a/media/lib/markitup/skins/markitup/images/bg-editor-xml.png b/media/lib/markitup/skins/markitup/images/bg-editor-xml.png deleted file mode 100644 index 33b1c5d83a4dde90e6b7f6312d4d046bf5532e22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1495 zcmeAS@N?(olHy`uVBq!ia0y~yV15B)pWt8ul3!Y5B!Coiv6E*A2M5RPhyD+MT+RZI z$YKTtZXpn6ymYtj4^U9P#5JNMI6tkVJh3R1!8b9vC_gtfB{NaMEwd=KJijQrSixdz z#-$3NQZbNH=c3falFa-(g^x7mgDH6kK3elg8cN?3f7=a|Lw=B=v~B@f5f<$UWo{PgKlc?O0D z|F_+^e}DdO9tMU39Y+ryJa{J^Xsz3f9n1_42a@vh^WPZ*`O0FuckeEq&&a?avGK;u zn=>KG_ZI^VV362;N-P^Y`!HFY;DaR=0i_0KIbk&+`zFsaimljIYB| z?PTQT^MA_#WuzvDrLH*$Wb9dUiUH`yC80Bce!E!h=jUf;1B}`YT?or&d?|SK^5si? z8CC{{h@%Mme5zKTdHeS53)^d%3=9d?K41r5I=nLY$NN=46KoHE{`?sdjuBHCVcvdy zPpi1Nc=H|$YwO!j29C_p}^Q>xSbpd z3{Xfo`9w|qncxiMrWw9`c;&oJ7tpo)Pp$&S9E;Da9r3ZTy83#0dSSJ|)R@zc@PtHM ze0+GVd8+)eb3mnkn1n&W4f2`)U0~qUod59co7s0s28ISfaKt!(V!ojO9$S;|fx__2 zX@u{w#@7L`JHW{XNpl$}WYD8p03OK)qKQcg*o{5}Nkt7t hst_2Y0~0)dn0tRZOT~)rWdUX_22WQ%mvv4FO#ntjreOd8 diff --git a/media/lib/markitup/skins/markitup/images/bg-editor.png b/media/lib/markitup/skins/markitup/images/bg-editor.png deleted file mode 100644 index ab7cde4850e081e787aef81f3893cc55ead0470b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1745 zcmdT^YfMuI6h5WuYI$Y>VI5S0KV;pbh%lHaREC`h0)v)`P@$oQnC<_5^!E1Tob#RYec$PK zQ4wF*GFeOjunpZA5)D8f!}r?^D}27lO>n_4x*|AKz+f=?9!C!1&$a10;}iha?-C!{ zJyZ4q2G=Wh>`}(Z4k$Ckaw+THZY4J3mD(&5+4c74H7^$@elbbsdrVxm+q% zrpOMu3sTag;Pn~T+n?*@S1k-L2UxQ)G-SIVvux7TuzS+Utga%OrcPG z?1-IhVh_9R&owS$vG&#_8-P`pSf@Ye=OQgFz_34y*3h=f>3Rz+b0tF<`{>DhAhQhhlr(*5Y5MgKl+wr|CKoG1JInTB} zwY7znYy_Zip&5Ger0Ojv6f~CMnJL4_6-nt{&$@XE$tbr^O-&8zLBSSIEKk6je)Vea zuTMutMrOonwfZ3!msME=uo$Dja4P&Z1~-yH-u-P;PW*XiWQes=8b_H-*7iqXQBi4A zvP2?reTnv_Ycu^{2DA%lP_c~^hc~^r_~@`LHnd%?*X;Yf*Jw1>RdsZ9a8-sxl=ABP z)3GJbm*iJajBD-x*f=dMO&#dUW@mrvc?Pp)EtkgMJmsX){z8XlZn6(&#xy%Sn>m5# z92e3e8ww3)PoP%@E)El3Uqv~n;bFO09 z&Te{(>xTS#v)Me#?KPRqhc=;WlPD)Ctn{vu+x+1A{U#TryD4;~Af)Fhw?Ucc!oYL; z_z#2h-A5z6X>UqVO%SLF3SRD3@zvGQShU*Q28v>sw(C|BKt()dq5{73Tmn~8MjUD7 zG7E!5HKXD`0#PsK&6Gbi%FS53_3x|v|5NAe)%v^%v6qu4dI>^zM1<4^Cms14pj9C; diff --git a/media/lib/markitup/skins/markitup/images/handle.png b/media/lib/markitup/skins/markitup/images/handle.png deleted file mode 100644 index 3993b20337e33a36c9125d139f1f53a279a4c128..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 258 zcmeAS@N?(olHy`uVBq!ia0vp^qCm{X#0(?@t!)i}6mzkYX9x!e$L)vy4}e^r0G|-o z4LkP#|NsB{_wSo_?oZ!X{TC?CQWE4B{GZ|f|H~VSrU3bz1s;*b3=G^tAk28_ZrvZC zpje4(M2T}zYGO%dex5=|W^O8jfw{hsp}v86ds2l5P=!25MR0yvNqJ&XDuZuga#4P6 zYD#9Jf?H-$YI%N9cCmuR){ILPK&1wrE{-7_Gm{H=1WS1m6Eb=Pa(faIBBVrjnVf1= soMNglKFuA6ghUcX`bbD&-ZPgg&ebxsLQ0Hz~TmH+?% diff --git a/media/lib/markitup/skins/markitup/images/menu.png b/media/lib/markitup/skins/markitup/images/menu.png deleted file mode 100644 index 44a07afd30f499cdba30847094a1e92f13e1320e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27151 zcmb@uby!=^voH>&K#@Wz#kHjZ#i7NeKyfI=U0STTJ0Vbtw8dQ$C`DS_-AZu@9z1yP z;DID0FQ0qw_ul(^|9Ic`xzBH(J!dvMJ9~C!&(6-AIVWG=zf-U&MM|6AsRp$5n7ToocSJk_Bn}YAzMBn}yzS-~r2X-X~Pg_4XPbV*SvHDMw{Bi(&-4O^6FCut;Y6b0D#;nkADCyhU-M0NFxfj4cv3?psgw0C*dj%d|)lI1h@ztu& zMbd4Jii?xH5^7}#dt1KyuNMDP$n{e=9}ka((#1(n_jZitrhbb`Nqsi!b4j-I-@Jr^ z#yXC3q+8EY$X)LaDr-M_)|>J-A%z#-OMI6ko7#A2C(Ymg3h0OHHP9D*lQ)5fAKf^Y z;QTteue|d&_IFDQqg04~C!45bP(iiGE+$xr(bTosz++@EzzM=qn%r3C?=|h-pCuwL zwWmElk7(KWCbR1eQF?DK8%ox6F6_`~g4_sX!X6x6y7mo4P8u?A@P5C}J zF(^2Vx$nrAucR9ix{!EE%D|z$Y){E+7RJ0uNgOgVdPP_7$yAf_}8@Rh8|OF>H8i3%)Vc8iqyV)?{~@s zsxp55an_BT7fRG-i;ijGv;leAP^37GXTVY@-}{x4Q&$Tzi1gfb*5eY1qyD3$InG!- zR3&&m5?GK)&YInAE$siB9P~20SYo#U7}k3JVwsPBu{hLZK9VJvgC$gwxl4MBv}Kv5 z>s~HJi}mpUdxrZ5d0qY&`3}WzbjRzSz9Q7Dg_k4<(Dv^iRD7NiVGA9>-aLh@)2X2p`N|irxPxg2^#m_a?>_EPu)0B7b%fktFm5jpgyng&B z`TZm`C9JNw;9UNjPB_YhP2)q2NICaA)RM=nLbsGcFRcGfIsMPcq0$C=A%#%OroCeE;fwSw0n;NO&Z76$e@5N>elO-UTt| zJPXs+GY+o9@WD5ZuPF*wv>2tnzqezQffMOg77}=6hc^?G`pI?wLWVT0C67C4bIJa> zO!Z7<&RbhH5Z000&vLXwG}@*% zde0v5W*WyN(|q{TR_}x@!X5jaVh*X7cN2{5@Eibgjcq&NApy@MiI=~7otK};ldsx% z6ueQZ$IJWCvgJ43#!^R657^5~|LRyYvt4R`#=^&^1nF3#Z^t)v=Tj-dabB3|PEtkYAI}!h)?46{X9+Tm9_)iJGG*iL zSwhd05|%Pd*In3aM)*%eBr+d|FjHjMhNV0Ajhx*5Sr;d ze-wlnpKQh$74HrNrUr4n;#B>bmOngRLvKQ>F#ORxlZxH-+&rJVAa4Q9d_R zDJ;*SANeshUxm*EPw^t3GmBiY=%Wt3$GZm})70)fX99Rl`aExSHdH)&Yn!%>?U*yL zBRRxH-0@Pq+_v#WQ7l_fo_4WRgQ7FgmZNGe!+js%5k{FP5>-WP^Wu|3#^F~(t@y{; zDL=xfd8K1!RPXda^L{?t%5b}%y8ntao6xFUN`pEnu~pvdl(l@|QSkEjfxoTsgL5oN zOxUp24Yq-s=CrZKwR!8t-p#bYmeUMh%QbUzff?pU+R zRhul|dnFnco@880?Yr{TZxdrI!0;LWk~~tB{c%KGh9z&rR8){dYNHwoHOkq6j)dC?rME_pTeglmw`TOAM-vNp)VTPA-{@w^W`*e zJo1&#Y<#OG@&4vu5L50{s7@)l(_?~H(tW!`pg?^_nICHt%v6_sxsh~|FN=wdjyxD@ zJYE!z_C1@m3m5!8yyxla)3daEz5JKq2@&z9o9g~1^kWIoW=0){_k)3z zy{&G6k8*6RT?Zt}1!jJ$RqISGvaT<38UVa}S4SH+K4 zL9Hq+_EhbQE3w3L%qOt36s;_Mq`u!qKGDJ8DJ^|CydLzNZ=9Xn7GJa3@2}u%n+ys4 zX7S3CYWrB?NGDn*<;020b?1v;RLFH#`2$YYzrQN4`9mk3YjGJ%4+q#+3mZM!rXo}- zVzBe<3QGF@;>hjvMzaAHl~m>v!L(00^`25kXIx=h%y$34jRaz||FB{F*EXx}u3b|j zvhbJhXE0YipNDIZS&FpO_hJ1+%wR@vjd18*68QzoeP5{;*dU5^C(k*Sp&uRj`T+Wc zzlCp~Wv%r}-E5MmIE=)NrWfZ@3)vCt<_Lh3_#fRb%*gD^U5aLsf>Epe$%ujle2UP1 z3ICkXsG7xcd|vuNS+?K}t4A2U8b^PQ?K4eJo2+}ks4m5O81Dl_MHd3~AGS!?ywj!4 z5h)f6`^K68yABfisPi4n2c8bs$kx0QH@)tpkm)m-MmnE{&t3y3hd{^)d^X_#55U#K>3@gz5oOl@nJktS8^la$#7rz+*o!YhQ%NBiF)mI zfGAMg{wEUjnXKt1p9&1__ivm3nn}>|yJyT4mvhIKqNOPzkTDhRYAbNiH%-H6#3d{{ zI8;;)!MyLIiRG2WJC;K58r#DgvCjtI85RaW=rc&!E9^<=`yF__#9Ak`uX*k^65PYe zY1coDh!e6_X?A2V5V#V{sIyQWp}-ry~k}x|`EG>z?_FfnBrcn`Y7bQNW$@ zd57`GxfG?6HofAs$#(9K`dOp-uX?Gnk5#&}YUi?ov z5+HP&PFg#9?B6CjuxuH=H%0i+jD|z;FoUeES5(eybtm_EG%vr=q=q~XdpTOVj?xeF6eI6yyxB0iHH&Y< z{E4?ubA@bj@zVCGOItHG)tFP5NQS#^W55T~^r(UiAY-B?q#ZNc%_0c9NYGwXgw)YYi$ zGo;VTSf-5(@HAX+@!t^0=9a6_$psQP!7&7O;ko?DrAFy2q?m}J)u&NF6n3xw)2Rb!o% z03A`&{y*u4BWd5%&5tX9W5!Pc!(5wl}b&-!fI+`R=1TEM%KWzZf%Wiht>A zs8dUXuK9&x^Y&7DQuRA$J}7HA^$mLdQl;{jZ!@j^$HIzrf{NOg32o!qZ0^}aYj#Y|6M(NW`V!%}+Y+TjJL=Jz zGM_ki6niu5siR{x?XF&d44+f#^#*wza~wu|ZyA*O+=(9TyYcU2$bd3G98pdgjN#b5 zbpeV+a{|vkDgec!%a`6=E-s@ztlijfZBNn`4b4pIV(pIZ5m`6`mZO0Rs@90t%ondk z!>p|(~oNw+>erc4p9Q-j{HJ_#v$U61H-Gg`2}FYxXYyUiuw1` zvc*4ABD^lwep}t&>BXQq@XLh^C3kxl7&a+x@k9-6oj*}|-Ibw?SVdglk zY_EN_#?!Fy{O6P|YSmua084i4*S!4&(W>dR4}^zv91w;NTr;_MFkZcWWY~3@&?Iq9 z>bh#!_D8qn520vW4V*HEH)pMJSd2jcceTC?wr1bsm{xUcoCdc13}~#*s@~v@+*G#ccP#VYjszCXRrYe=C{!?{ z5ZF^L@{opE}Xbc~JUM>gf@;%dn>H7B^ zYfN$b1B{Ej6wGd zp&^}F?)TDGce)PRj(@8jn|ZQNYi925(>*h2cH@##dVTVWtg?##7w=rF6+*GL(W1() zdxbE_{v$$jY^C!(KZdXZ&5F|Qo+UKp&nh4NTu#=&Hz#3e_OxsEpWfTuD?~^u_?lW) z9Z3w;y;0vsU{jTD9puKgcmBn+e=diHm4E*S zk~NIc(Ov&_r>l6$-k+=n!aT))Pmuz_`FjF7PB88W~BBrOQp5H@mN4;hF{!v!BRd*ep zPfH=}1Wr%=%R6$XzC6o#aa?CVqT|_K_OlVDN&{F!a|dC0!cMl#8e>$V<>mxL+Is#0 zN~O*IrP6a;Tgb1uIDK@XV#g_Xf`8^qhxt|E33)rg#Q~RWl12JX8*KaU3`-MjKs#96 zaQ`0x-wK9G!AQukz&9ltKf|K+j-f22YVF%YYgnWo75%Uap@Db$H+uPZ*}B_lf1fdZ zPAj_8`J5Rs&rHy8EU9pkDScR(lale?>SD#YzA zTY>i_REtS%63NmI7k&< zQyG5pD!C&}qWGQ63k-jW`C|*ckiW2K-?7=M4jqC6maFgBtptotaxjTjj{xl#)K=0; zwMDFQ!Sg4zRpp&TUoTWqhHda=4T|HSMaqSC^htmdWoOb3FZc5)Kw$I8<$B*!Pfg69q5umo zGSDRY<8Xill4~9;DIXkSm}`w2`U#U12<&RW5QtGq?@CTmw^7y{1fK&|_gg!BQCODT zwfXp`kN%)gVNRi%nL`7aje-VV#0l{h!lRk|1FY3l!bnn`+(trsv+-&fHqwPBY^LRE z#GO&C7Rn|l%896~WD$uD5l5%uSfH-S6;1xnc*8IJs739kkq>j19+QETEkVhkyOrSW zGJS_((e4X8@wyLqNxb1opUnQqj?=s1tz^>km!T{e90}r%h>k6vnVUq4NRiZ?M?Nv$ z55*Dfl!zV;AgI=^2LEyrJswpWXJj`@Q<1a$^+;sxEPCPlJTp)wa7ARbEBJZT(NLcX zA_M$r5&j1ryecgkJZq_H*h{q$in??el9VQ624ne{-p6wWf9YJms81

          +35?Hj$O) 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 diff --git a/media/lib/markitup/skins/markitup/style.css b/media/lib/markitup/skins/markitup/style.css deleted file mode 100644 index 6f3a3c797e2..00000000000 --- a/media/lib/markitup/skins/markitup/style.css +++ /dev/null @@ -1,148 +0,0 @@ -/* ------------------------------------------------------------------- -// markItUp! Universal MarkUp Engine, JQuery plugin -// By Jay Salvat - http://markitup.jaysalvat.com/ -// ------------------------------------------------------------------*/ -.markItUp * { - margin:0px; padding:0px; - outline:none; -} -.markItUp a:link, -.markItUp a:visited { - color:#000; - text-decoration:none; -} -.markItUp { - width:700px; - margin:5px 0 5px 0; - border:5px solid #F5F5F5; -} -.markItUpContainer { - border:1px solid #3C769D; - background:#FFF url(images/bg-container.png) repeat-x top left; - padding:5px 5px 2px 5px; - font:11px Verdana, Arial, Helvetica, sans-serif; -} -.markItUpEditor { - font:12px 'Courier New', Courier, monospace; - padding:5px 5px 5px 35px; - border:3px solid #3C769D; - width:643px; - height:320px; - background-image:url(images/bg-editor.png); - background-repeat:no-repeat; - clear:both; display:block; - line-height:18px; - overflow:auto; -} -.markItUpPreviewFrame { - overflow:auto; - background-color:#FFFFFF; - border:1px solid #3C769D; - width:99.9%; - height:300px; - margin:5px 0; -} -.markItUpFooter { - width:100%; - cursor:n-resize; -} -.markItUpResizeHandle { - overflow:hidden; - width:22px; height:5px; - margin-left:auto; - margin-right:auto; - background-image:url(images/handle.png); - cursor:n-resize; -} -/***************************************************************************************/ -/* first row of buttons */ -.markItUpHeader ul li { - list-style:none; - float:left; - position:relative; -} -.markItUpHeader ul li ul{ - display:none; -} -.markItUpHeader ul li:hover > ul{ - display:block; -} -.markItUpHeader ul .markItUpDropMenu { - background:transparent url(images/menu.png) no-repeat 115% 50%; - margin-right:5px; -} -.markItUpHeader ul .markItUpDropMenu li { - margin-right:0px; -} -.markItUpHeader ul .markItUpSeparator { - margin:0 10px; - width:1px; - height:16px; - overflow:hidden; - background-color:#CCC; -} -.markItUpHeader ul ul .markItUpSeparator { - width:auto; height:1px; - margin:0px; -} -/* next rows of buttons */ -.markItUpHeader ul ul { - display:none; - position:absolute; - top:18px; left:0px; - background:#F5F5F5; - border:1px solid #3C769D; - height:inherit; -} -.markItUpHeader ul ul li { - float:none; - border-bottom:1px solid #3C769D; -} -.markItUpHeader ul ul .markItUpDropMenu { - background:#F5F5F5 url(images/submenu.png) no-repeat 100% 50%; -} -/* next rows of buttons */ -.markItUpHeader ul ul ul { - position:absolute; - top:-1px; left:150px; -} -.markItUpHeader ul ul ul li { - float:none; -} -.markItUpHeader ul a { - display:block; - width:16px; height:16px; - text-indent:-10000px; - background-repeat:no-repeat; - padding:3px; - margin:0px; -} -.markItUpHeader ul ul a { - display:block; - padding-left:0px; - text-indent:0; - width:120px; - padding:5px 5px 5px 25px; - background-position:2px 50%; -} -.markItUpHeader ul ul a:hover { - color:#FFF; - background-color:#3C769D; -} -/***************************************************************************************/ -.html .markItUpEditor { - background-image:url(images/bg-editor-html.png); -} -.markdown .markItUpEditor { - background-image:url(images/bg-editor-markdown.png); -} -.textile .markItUpEditor { - background-image:url(images/bg-editor-textile.png); -} -.bbcode .markItUpEditor { - background-image:url(images/bg-editor-bbcode.png); -} -.wiki .markItUpEditor, -.dotclear .markItUpEditor { - background-image:url(images/bg-editor-wiki.png); -} \ No newline at end of file diff --git a/media/lib/markitup/skins/simple/images/handle.png b/media/lib/markitup/skins/simple/images/handle.png deleted file mode 100644 index 3993b20337e33a36c9125d139f1f53a279a4c128..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 258 zcmeAS@N?(olHy`uVBq!ia0vp^qCm{X#0(?@t!)i}6mzkYX9x!e$L)vy4}e^r0G|-o z4LkP#|NsB{_wSo_?oZ!X{TC?CQWE4B{GZ|f|H~VSrU3bz1s;*b3=G^tAk28_ZrvZC zpje4(M2T}zYGO%dex5=|W^O8jfw{hsp}v86ds2l5P=!25MR0yvNqJ&XDuZuga#4P6 zYD#9Jf?H-$YI%N9cCmuR){ILPK&1wrE{-7_Gm{H=1WS1m6Eb=Pa(faIBBVrjnVf1= soMNglKFuA6ghUcX`bbD&-ZPgg&ebxsLQ0Hz~TmH+?% diff --git a/media/lib/markitup/skins/simple/images/menu.png b/media/lib/markitup/skins/simple/images/menu.png deleted file mode 100644 index 44a07afd30f499cdba30847094a1e92f13e1320e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27151 zcmb@uby!=^voH>&K#@Wz#kHjZ#i7NeKyfI=U0STTJ0Vbtw8dQ$C`DS_-AZu@9z1yP z;DID0FQ0qw_ul(^|9Ic`xzBH(J!dvMJ9~C!&(6-AIVWG=zf-U&MM|6AsRp$5n7ToocSJk_Bn}YAzMBn}yzS-~r2X-X~Pg_4XPbV*SvHDMw{Bi(&-4O^6FCut;Y6b0D#;nkADCyhU-M0NFxfj4cv3?psgw0C*dj%d|)lI1h@ztu& zMbd4Jii?xH5^7}#dt1KyuNMDP$n{e=9}ka((#1(n_jZitrhbb`Nqsi!b4j-I-@Jr^ z#yXC3q+8EY$X)LaDr-M_)|>J-A%z#-OMI6ko7#A2C(Ymg3h0OHHP9D*lQ)5fAKf^Y z;QTteue|d&_IFDQqg04~C!45bP(iiGE+$xr(bTosz++@EzzM=qn%r3C?=|h-pCuwL zwWmElk7(KWCbR1eQF?DK8%ox6F6_`~g4_sX!X6x6y7mo4P8u?A@P5C}J zF(^2Vx$nrAucR9ix{!EE%D|z$Y){E+7RJ0uNgOgVdPP_7$yAf_}8@Rh8|OF>H8i3%)Vc8iqyV)?{~@s zsxp55an_BT7fRG-i;ijGv;leAP^37GXTVY@-}{x4Q&$Tzi1gfb*5eY1qyD3$InG!- zR3&&m5?GK)&YInAE$siB9P~20SYo#U7}k3JVwsPBu{hLZK9VJvgC$gwxl4MBv}Kv5 z>s~HJi}mpUdxrZ5d0qY&`3}WzbjRzSz9Q7Dg_k4<(Dv^iRD7NiVGA9>-aLh@)2X2p`N|irxPxg2^#m_a?>_EPu)0B7b%fktFm5jpgyng&B z`TZm`C9JNw;9UNjPB_YhP2)q2NICaA)RM=nLbsGcFRcGfIsMPcq0$C=A%#%OroCeE;fwSw0n;NO&Z76$e@5N>elO-UTt| zJPXs+GY+o9@WD5ZuPF*wv>2tnzqezQffMOg77}=6hc^?G`pI?wLWVT0C67C4bIJa> zO!Z7<&RbhH5Z000&vLXwG}@*% zde0v5W*WyN(|q{TR_}x@!X5jaVh*X7cN2{5@Eibgjcq&NApy@MiI=~7otK};ldsx% z6ueQZ$IJWCvgJ43#!^R657^5~|LRyYvt4R`#=^&^1nF3#Z^t)v=Tj-dabB3|PEtkYAI}!h)?46{X9+Tm9_)iJGG*iL zSwhd05|%Pd*In3aM)*%eBr+d|FjHjMhNV0Ajhx*5Sr;d ze-wlnpKQh$74HrNrUr4n;#B>bmOngRLvKQ>F#ORxlZxH-+&rJVAa4Q9d_R zDJ;*SANeshUxm*EPw^t3GmBiY=%Wt3$GZm})70)fX99Rl`aExSHdH)&Yn!%>?U*yL zBRRxH-0@Pq+_v#WQ7l_fo_4WRgQ7FgmZNGe!+js%5k{FP5>-WP^Wu|3#^F~(t@y{; zDL=xfd8K1!RPXda^L{?t%5b}%y8ntao6xFUN`pEnu~pvdl(l@|QSkEjfxoTsgL5oN zOxUp24Yq-s=CrZKwR!8t-p#bYmeUMh%QbUzff?pU+R zRhul|dnFnco@880?Yr{TZxdrI!0;LWk~~tB{c%KGh9z&rR8){dYNHwoHOkq6j)dC?rME_pTeglmw`TOAM-vNp)VTPA-{@w^W`*e zJo1&#Y<#OG@&4vu5L50{s7@)l(_?~H(tW!`pg?^_nICHt%v6_sxsh~|FN=wdjyxD@ zJYE!z_C1@m3m5!8yyxla)3daEz5JKq2@&z9o9g~1^kWIoW=0){_k)3z zy{&G6k8*6RT?Zt}1!jJ$RqISGvaT<38UVa}S4SH+K4 zL9Hq+_EhbQE3w3L%qOt36s;_Mq`u!qKGDJ8DJ^|CydLzNZ=9Xn7GJa3@2}u%n+ys4 zX7S3CYWrB?NGDn*<;020b?1v;RLFH#`2$YYzrQN4`9mk3YjGJ%4+q#+3mZM!rXo}- zVzBe<3QGF@;>hjvMzaAHl~m>v!L(00^`25kXIx=h%y$34jRaz||FB{F*EXx}u3b|j zvhbJhXE0YipNDIZS&FpO_hJ1+%wR@vjd18*68QzoeP5{;*dU5^C(k*Sp&uRj`T+Wc zzlCp~Wv%r}-E5MmIE=)NrWfZ@3)vCt<_Lh3_#fRb%*gD^U5aLsf>Epe$%ujle2UP1 z3ICkXsG7xcd|vuNS+?K}t4A2U8b^PQ?K4eJo2+}ks4m5O81Dl_MHd3~AGS!?ywj!4 z5h)f6`^K68yABfisPi4n2c8bs$kx0QH@)tpkm)m-MmnE{&t3y3hd{^)d^X_#55U#K>3@gz5oOl@nJktS8^la$#7rz+*o!YhQ%NBiF)mI zfGAMg{wEUjnXKt1p9&1__ivm3nn}>|yJyT4mvhIKqNOPzkTDhRYAbNiH%-H6#3d{{ zI8;;)!MyLIiRG2WJC;K58r#DgvCjtI85RaW=rc&!E9^<=`yF__#9Ak`uX*k^65PYe zY1coDh!e6_X?A2V5V#V{sIyQWp}-ry~k}x|`EG>z?_FfnBrcn`Y7bQNW$@ zd57`GxfG?6HofAs$#(9K`dOp-uX?Gnk5#&}YUi?ov z5+HP&PFg#9?B6CjuxuH=H%0i+jD|z;FoUeES5(eybtm_EG%vr=q=q~XdpTOVj?xeF6eI6yyxB0iHH&Y< z{E4?ubA@bj@zVCGOItHG)tFP5NQS#^W55T~^r(UiAY-B?q#ZNc%_0c9NYGwXgw)YYi$ zGo;VTSf-5(@HAX+@!t^0=9a6_$psQP!7&7O;ko?DrAFy2q?m}J)u&NF6n3xw)2Rb!o% z03A`&{y*u4BWd5%&5tX9W5!Pc!(5wl}b&-!fI+`R=1TEM%KWzZf%Wiht>A zs8dUXuK9&x^Y&7DQuRA$J}7HA^$mLdQl;{jZ!@j^$HIzrf{NOg32o!qZ0^}aYj#Y|6M(NW`V!%}+Y+TjJL=Jz zGM_ki6niu5siR{x?XF&d44+f#^#*wza~wu|ZyA*O+=(9TyYcU2$bd3G98pdgjN#b5 zbpeV+a{|vkDgec!%a`6=E-s@ztlijfZBNn`4b4pIV(pIZ5m`6`mZO0Rs@90t%ondk z!>p|(~oNw+>erc4p9Q-j{HJ_#v$U61H-Gg`2}FYxXYyUiuw1` zvc*4ABD^lwep}t&>BXQq@XLh^C3kxl7&a+x@k9-6oj*}|-Ibw?SVdglk zY_EN_#?!Fy{O6P|YSmua084i4*S!4&(W>dR4}^zv91w;NTr;_MFkZcWWY~3@&?Iq9 z>bh#!_D8qn520vW4V*HEH)pMJSd2jcceTC?wr1bsm{xUcoCdc13}~#*s@~v@+*G#ccP#VYjszCXRrYe=C{!?{ z5ZF^L@{opE}Xbc~JUM>gf@;%dn>H7B^ zYfN$b1B{Ej6wGd zp&^}F?)TDGce)PRj(@8jn|ZQNYi925(>*h2cH@##dVTVWtg?##7w=rF6+*GL(W1() zdxbE_{v$$jY^C!(KZdXZ&5F|Qo+UKp&nh4NTu#=&Hz#3e_OxsEpWfTuD?~^u_?lW) z9Z3w;y;0vsU{jTD9puKgcmBn+e=diHm4E*S zk~NIc(Ov&_r>l6$-k+=n!aT))Pmuz_`FjF7PB88W~BBrOQp5H@mN4;hF{!v!BRd*ep zPfH=}1Wr%=%R6$XzC6o#aa?CVqT|_K_OlVDN&{F!a|dC0!cMl#8e>$V<>mxL+Is#0 zN~O*IrP6a;Tgb1uIDK@XV#g_Xf`8^qhxt|E33)rg#Q~RWl12JX8*KaU3`-MjKs#96 zaQ`0x-wK9G!AQukz&9ltKf|K+j-f22YVF%YYgnWo75%Uap@Db$H+uPZ*}B_lf1fdZ zPAj_8`J5Rs&rHy8EU9pkDScR(lale?>SD#YzA zTY>i_REtS%63NmI7k&< zQyG5pD!C&}qWGQ63k-jW`C|*ckiW2K-?7=M4jqC6maFgBtptotaxjTjj{xl#)K=0; zwMDFQ!Sg4zRpp&TUoTWqhHda=4T|HSMaqSC^htmdWoOb3FZc5)Kw$I8<$B*!Pfg69q5umo zGSDRY<8Xill4~9;DIXkSm}`w2`U#U12<&RW5QtGq?@CTmw^7y{1fK&|_gg!BQCODT zwfXp`kN%)gVNRi%nL`7aje-VV#0l{h!lRk|1FY3l!bnn`+(trsv+-&fHqwPBY^LRE z#GO&C7Rn|l%896~WD$uD5l5%uSfH-S6;1xnc*8IJs739kkq>j19+QETEkVhkyOrSW zGJS_((e4X8@wyLqNxb1opUnQqj?=s1tz^>km!T{e90}r%h>k6vnVUq4NRiZ?M?Nv$ z55*Dfl!zV;AgI=^2LEyrJswpWXJj`@Q<1a$^+;sxEPCPlJTp)wa7ARbEBJZT(NLcX zA_M$r5&j1ryecgkJZq_H*h{q$in??el9VQ624ne{-p6wWf9YJms81

          +35?Hj$O) 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 diff --git a/media/lib/markitup/skins/simple/style.css b/media/lib/markitup/skins/simple/style.css deleted file mode 100644 index f26f135d7fc..00000000000 --- a/media/lib/markitup/skins/simple/style.css +++ /dev/null @@ -1,118 +0,0 @@ -/* ------------------------------------------------------------------- -// markItUp! Universal MarkUp Engine, JQuery plugin -// By Jay Salvat - http://markitup.jaysalvat.com/ -// ------------------------------------------------------------------*/ -.markItUp * { - margin:0px; padding:0px; - outline:none; -} -.markItUp a:link, -.markItUp a:visited { - color:#000; - text-decoration:none; -} -.markItUp { - width:500px; - margin:5px 0 5px 0; -} -.markItUpContainer { - font:11px Verdana, Arial, Helvetica, sans-serif; -} -.markItUpEditor { - font:12px 'Courier New', Courier, monospace; - padding:5px; - width:490px; - height:320px; - clear:both; display:block; - line-height:18px; - overflow:auto; -} -.markItUpPreviewFrame { - overflow:auto; - background-color:#FFF; - width:99.9%; - height:300px; - margin:5px 0; -} -.markItUpFooter { - width:100%; -} -.markItUpResizeHandle { - overflow:hidden; - width:22px; height:5px; - margin-left:auto; - margin-right:auto; - background-image:url(images/handle.png); - cursor:n-resize; -} -/***************************************************************************************/ -/* first row of buttons */ -.markItUpHeader ul li { - list-style:none; - float:left; - position:relative; -} -.markItUpHeader ul li:hover > ul{ - display:block; -} -.markItUpHeader ul .markItUpDropMenu { - background:transparent url(images/menu.png) no-repeat 115% 50%; - margin-right:5px; -} -.markItUpHeader ul .markItUpDropMenu li { - margin-right:0px; -} -/* next rows of buttons */ -.markItUpHeader ul ul { - display:none; - position:absolute; - top:18px; left:0px; - background:#FFF; - border:1px solid #000; -} -.markItUpHeader ul ul li { - float:none; - border-bottom:1px solid #000; -} -.markItUpHeader ul ul .markItUpDropMenu { - background:#FFF url(images/submenu.png) no-repeat 100% 50%; -} -.markItUpHeader ul .markItUpSeparator { - margin:0 10px; - width:1px; - height:16px; - overflow:hidden; - background-color:#CCC; -} -.markItUpHeader ul ul .markItUpSeparator { - width:auto; height:1px; - margin:0px; -} -/* next rows of buttons */ -.markItUpHeader ul ul ul { - position:absolute; - top:-1px; left:150px; -} -.markItUpHeader ul ul ul li { - float:none; -} -.markItUpHeader ul a { - display:block; - width:16px; height:16px; - text-indent:-10000px; - background-repeat:no-repeat; - padding:3px; - margin:0px; -} -.markItUpHeader ul ul a { - display:block; - padding-left:0px; - text-indent:0; - width:120px; - padding:5px 5px 5px 25px; - background-position:2px 50%; -} -.markItUpHeader ul ul a:hover { - color:#FFF; - background-color:#000; -} diff --git a/media/lib/markitup/templates/preview.css b/media/lib/markitup/templates/preview.css deleted file mode 100644 index ad91a871c7e..00000000000 --- a/media/lib/markitup/templates/preview.css +++ /dev/null @@ -1,5 +0,0 @@ -/* preview style examples */ -body { - background-color:#EFEFEF; - font:70% Verdana, Arial, Helvetica, sans-serif; -} \ No newline at end of file diff --git a/media/lib/markitup/templates/preview.html b/media/lib/markitup/templates/preview.html deleted file mode 100644 index b8b3702ebea..00000000000 --- a/media/lib/markitup/templates/preview.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - -markItUp! preview template - - - - - - diff --git a/readthedocs/templates/projects/import_extra.html b/readthedocs/templates/projects/import_extra.html index c1ff668747d..b52d4ad338c 100644 --- a/readthedocs/templates/projects/import_extra.html +++ b/readthedocs/templates/projects/import_extra.html @@ -1,21 +1,6 @@ {% extends "projects/import_base.html" %} {% load i18n %} -{% block extra_links %} - - -{% endblock %} - -{% block extra_scripts %} - - - -{% endblock %} - {% block content %}

          {% trans "Project Extra Details" %}

          diff --git a/readthedocs/templates/projects/project_advanced.html b/readthedocs/templates/projects/project_advanced.html index f8356712350..2372e023d5d 100644 --- a/readthedocs/templates/projects/project_advanced.html +++ b/readthedocs/templates/projects/project_advanced.html @@ -4,21 +4,6 @@ {% block project-advanced-active %}active{% endblock %} {% block nav-dashboard %} class="active"{% endblock %} -{% block extra_links %} - - -{% endblock %} - -{% block extra_scripts %} - - - -{% endblock %} - {% block title %}{% trans "Edit Advanced Project Settings" %}{% endblock %} {% block editing-option-edit-proj %}class="active"{% endblock %} diff --git a/readthedocs/templates/projects/project_create.html b/readthedocs/templates/projects/project_create.html index 563cd39965e..b0eaa2f0d46 100644 --- a/readthedocs/templates/projects/project_create.html +++ b/readthedocs/templates/projects/project_create.html @@ -1,23 +1,6 @@ {% extends "dashboard/base_dashboard.html" %} {% load i18n %} -{% block extra_links %} - - -{% endblock %} - -{% block dash-nav-create %}active{% endblock %} - -{% block extra_scripts %} - - - -{% endblock %} - {% block title %}{% trans "Create a new project" %}{% endblock %} {% block content-header %} diff --git a/readthedocs/templates/projects/project_edit.html b/readthedocs/templates/projects/project_edit.html index 785d4d373dc..e541ec1aff9 100644 --- a/readthedocs/templates/projects/project_edit.html +++ b/readthedocs/templates/projects/project_edit.html @@ -4,20 +4,6 @@ {% block project-edit-active %}active{% endblock %} {% block nav-dashboard %} class="active"{% endblock %} -{% block extra_links %} - - -{% endblock %} - -{% block extra_scripts %} - - - -{% endblock %} {% block title %}{% trans "Edit Project" %}{% endblock %} From e7dbb2b8acd19dca9bee23c7f75eac93b22a98a6 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 02:19:42 -0500 Subject: [PATCH 017/190] Check for submodules (#3661) Add check for git submodules during build. Don't do submodule operations if no submodules are configured. --- readthedocs/rtd_tests/tests/test_backend.py | 10 ++++++++++ readthedocs/rtd_tests/utils.py | 7 +++++++ readthedocs/vcs_support/backends/git.py | 11 ++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/readthedocs/rtd_tests/tests/test_backend.py b/readthedocs/rtd_tests/tests/test_backend.py index 976ff5685ee..724c2d56b29 100644 --- a/readthedocs/rtd_tests/tests/test_backend.py +++ b/readthedocs/rtd_tests/tests/test_backend.py @@ -78,6 +78,16 @@ def test_parse_git_tags(self): self.project.vcs_repo().parse_tags(data)] self.assertEqual(expected_tags, given_ids) + def test_check_for_submodules(self): + repo = self.project.vcs_repo() + + repo.checkout() + self.assertFalse(repo.submodules_exists()) + + # The submodule branch contains one submodule + repo.checkout('submodule') + self.assertTrue(repo.submodules_exists()) + class TestHgBackend(RTDTestCase): def setUp(self): diff --git a/readthedocs/rtd_tests/utils.py b/readthedocs/rtd_tests/utils.py index 5d4fc616f31..9223837eccb 100644 --- a/readthedocs/rtd_tests/utils.py +++ b/readthedocs/rtd_tests/utils.py @@ -34,6 +34,13 @@ def make_test_git(): log.info(check_output(['git', 'init'] + [directory], env=env)) log.info(check_output(['git', 'add', '.'], env=env)) log.info(check_output(['git', 'commit', '-m"init"'], env=env)) + # Add repo itself as submodule + log.info(check_output(['git', 'checkout', '-b', 'submodule'], env=env)) + log.info(check_output(['git', 'submodule', 'add', '-b', 'master', './', 'submodule'], env=env)) + log.info(check_output(['git', 'add', '.'], env=env)) + log.info(check_output(['git', 'commit', '-m"Add submodule"'], env=env)) + # Checkout to master branch again + log.info(check_output(['git', 'checkout', 'master'], env=env)) chdir(path) return directory diff --git a/readthedocs/vcs_support/backends/git.py b/readthedocs/vcs_support/backends/git.py index d2e623de1c6..77673907ec5 100644 --- a/readthedocs/vcs_support/backends/git.py +++ b/readthedocs/vcs_support/backends/git.py @@ -55,6 +55,10 @@ def repo_exists(self): code, _, _ = self.run('git', 'status', record=False) return code == 0 + def submodules_exists(self): + code, out, _ = self.run('git', 'submodule', 'status', record=False) + return code == 0 and bool(out) + def fetch(self): code, _, _ = self.run('git', 'fetch', '--tags', '--prune') if code != 0: @@ -187,9 +191,10 @@ def checkout(self, identifier=None): self.run('git', 'clean', '-d', '-f', '-f') # Update submodules - self.run('git', 'submodule', 'sync') - self.run('git', 'submodule', 'update', - '--init', '--recursive', '--force') + if self.submodules_exists(): + self.run('git', 'submodule', 'sync') + self.run('git', 'submodule', 'update', + '--init', '--recursive', '--force') return code, out, err From 09f8282be35c20dcca42c85d3f845bba8b784cfe Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Tue, 27 Feb 2018 02:37:35 -0500 Subject: [PATCH 018/190] Upgrade django-taggit to 0.22.2 (#3667) Upgrade this package to be more prepared for Python3 and Django 2.0 --- requirements/pip.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/pip.txt b/requirements/pip.txt index e94471cf34b..e388316cbd2 100644 --- a/requirements/pip.txt +++ b/requirements/pip.txt @@ -56,6 +56,7 @@ django-textclassifier==1.0 django-annoying==0.10.1 django-messages-extends==0.5 djangorestframework-jsonp==1.0.2 +django-taggit==0.22.2 # Docs sphinxcontrib-httpdomain==1.4.0 @@ -71,4 +72,3 @@ nilsimsa==0.3.7 # Pegged git requirements git+https://github.com/zyga/django-pagination.git@86caf15#egg=django_pagination-dev -git+https://github.com/alex/django-taggit.git#egg=django_taggit-dev From d903e40a3e6ecbb48f35e90d6923fb43597b95e5 Mon Sep 17 00:00:00 2001 From: aasis21 Date: Tue, 27 Feb 2018 20:22:56 +0530 Subject: [PATCH 019/190] futher suggested changes --- docs/guides/build-notifications.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/guides/build-notifications.rst b/docs/guides/build-notifications.rst index 4881f8d750c..6cd203be4be 100644 --- a/docs/guides/build-notifications.rst +++ b/docs/guides/build-notifications.rst @@ -9,28 +9,28 @@ This makes sure you know when your builds have failed. Take these steps to enable build notifications using email: -* Going to **Admin > Notifications** in your project. +* Go to **Admin > Notifications** in your project. * Fill in the **Email** field under the **New Email Notifications** heading * Submit the form -You should now get notified on your email when your builds fail! +You should now get notified by email when your builds fail! Using webhook ------------- -Read the Docs also allows webhooks configuration to receive notification regarding builds fails. +Read the Docs can also send webhooks when builds fail. -Take these steps to enable build notifications using webhook: +Take these steps to enable build notifications using a webhook: -* Going to **Admin > Notifications** in your project. -* Fill in the **Url** field under the **New Webhook Notifications** heading +* Go to **Admin > Notifications** in your project. +* Fill in the **URL** field under the **New Webhook Notifications** heading * Submit the form -The project name, slug and its build instance that failed will be sent as POST request to your webhook url: +The project name, slug and its details for the build that failed will be sent as POST request to your webhook URL: .. code-block:: json - - { + + { "name": "Read the Docs", "slug": "rtd", "build": { From 1330fd32a4263b505c1f7b67738b3ca43d771723 Mon Sep 17 00:00:00 2001 From: aasis21 Date: Tue, 27 Feb 2018 20:39:45 +0530 Subject: [PATCH 020/190] revert back description field removal and added suggested changes --- readthedocs/templates/projects/project_create.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readthedocs/templates/projects/project_create.html b/readthedocs/templates/projects/project_create.html index b0eaa2f0d46..4d4441a5ce5 100644 --- a/readthedocs/templates/projects/project_create.html +++ b/readthedocs/templates/projects/project_create.html @@ -1,6 +1,8 @@ {% extends "dashboard/base_dashboard.html" %} {% load i18n %} +{% block dash-nav-create %}active{% endblock %} + {% block title %}{% trans "Create a new project" %}{% endblock %} {% block content-header %} From 40b203918a026f6dff5612fcb4de56d3b37f9938 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 20:21:15 -0500 Subject: [PATCH 021/190] Add tests for translations --- readthedocs/rtd_tests/tests/test_project.py | 48 +++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/readthedocs/rtd_tests/tests/test_project.py b/readthedocs/rtd_tests/tests/test_project.py index 38e7943634d..3a2786a7715 100644 --- a/readthedocs/rtd_tests/tests/test_project.py +++ b/readthedocs/rtd_tests/tests/test_project.py @@ -5,6 +5,7 @@ import datetime import json +from django.contrib.auth.models import User from django.test import TestCase from django_dynamic_fixture import get from mock import patch @@ -82,6 +83,53 @@ def test_translation_delete(self): self.assertIsNone( Project.objects.get(pk=project_keep.pk).main_language_project) + def test_user_can_add_own_project_as_translation(self): + user_a = get(User) + user_a.set_password('test') + user_a.save() + project_a = get( + Project, users=[user_a], + language='en', main_language_project=None + ) + project_b = get( + Project, users=[user_a], + language='es', main_language_project=None + ) + + self.client.login(username=user_a.username, password='test') + self.client.post( + reverse('projects_translations', args=[project_a.slug]), + data={'project': project_b.slug} + ) + + self.assertEqual(project_a.translations.first(), project_b) + # this test don't pass, but on the site it's ok. + # self.assertEqual(project_b.main_language_project, project_a) + + def test_user_can_not_add_other_user_project_as_translation(self): + # Two users, two projects with different language + user_a = get(User) + user_a.set_password('test') + user_a.save() + project_a = get(Project, users=[user_a], language='es') + project_a.slug = 'project-a' + project_a.save() + + user_b = get(User) + project_b = get(Project, users=[user_b], language='en') + project_b.slug = 'project-b' + project_b.save() + + # User A try to add project B as translation of project A + self.client.login(username=user_a.username, password='test') + self.client.post( + reverse('projects_translations', args=[project_a.slug]), + data={'project': project_b.slug} + ) + + self.assertEqual(project_a.translations.count(), 0) + self.assertIsNone(project_b.main_language_project) + def test_token(self): r = self.client.get('/api/v2/project/6/token/', {}) resp = json.loads(r.content) From 3332b6d0288285aec65a09baa1f654d28340d946 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 20:25:15 -0500 Subject: [PATCH 022/190] Add test for more than one owner --- readthedocs/rtd_tests/tests/test_project.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/readthedocs/rtd_tests/tests/test_project.py b/readthedocs/rtd_tests/tests/test_project.py index 3a2786a7715..50d72f459f1 100644 --- a/readthedocs/rtd_tests/tests/test_project.py +++ b/readthedocs/rtd_tests/tests/test_project.py @@ -106,6 +106,25 @@ def test_user_can_add_own_project_as_translation(self): # this test don't pass, but on the site it's ok. # self.assertEqual(project_b.main_language_project, project_a) + def test_user_can_add_project_as_translation_if_is_owner(self): + # Two users, two projects with different language + user_a = get(User) + user_a.set_password('test') + user_a.save() + project_a = get(Project, users=[user_a], language='es') + + user_b = get(User) + # User A and B are owners of project B + project_b = get(Project, users=[user_b, user_a], language='en') + + self.client.login(username=user_a.username, password='test') + self.client.post( + reverse('projects_translations', args=[project_a.slug]), + data={'project': project_b.slug} + ) + + self.assertEqual(project_a.translations.first(), project_b) + def test_user_can_not_add_other_user_project_as_translation(self): # Two users, two projects with different language user_a = get(User) From 8afa88a4b56f51a7fa042dabf3bb2d5f8318394b Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 21:07:41 -0500 Subject: [PATCH 023/190] Add test for TranslationForm --- .../rtd_tests/tests/test_project_forms.py | 123 +++++++++++++++++- 1 file changed, 119 insertions(+), 4 deletions(-) diff --git a/readthedocs/rtd_tests/tests/test_project_forms.py b/readthedocs/rtd_tests/tests/test_project_forms.py index 2b3ca253709..d8db20e7aec 100644 --- a/readthedocs/rtd_tests/tests/test_project_forms.py +++ b/readthedocs/rtd_tests/tests/test_project_forms.py @@ -1,11 +1,15 @@ -from __future__ import absolute_import -import mock +from __future__ import ( + absolute_import, division, print_function, unicode_literals) -from django.test import TestCase, override_settings +import mock +from django.contrib.auth.models import User +from django.test import TestCase +from django_dynamic_fixture import get from textclassifier.validators import ClassifierValidator from readthedocs.projects.exceptions import ProjectSpamError -from readthedocs.projects.forms import ProjectExtraForm +from readthedocs.projects.forms import ProjectExtraForm, TranslationForm +from readthedocs.projects.models import Project class TestProjectForms(TestCase): @@ -23,3 +27,114 @@ def test_form_spam(self, mocked_validator): form = ProjectExtraForm(data) with self.assertRaises(ProjectSpamError): form.is_valid() + + def test_form_translation_list_only_owner_projects(self): + user = get(User) + project_a = get(Project, users=[user], language='es') + project_b = get(Project, users=[user], language='en') + project_c = get(Project, users=[user], language='br') + user_b = get(User) + project_d = get(Project, users=[user_b], language='ar') + + form = TranslationForm( + {'parent': project_a.pk}, + project=project_b, + user=user, + ) + self.assertTrue(form.is_valid()) + self.assertEqual( + {proj_id for proj_id, _ in form.fields['project'].choices}, + {project_b.id, project_c.id} + ) + + def test_form_translation_list_all_projects_where_is_owner(self): + user = get(User) + project_a = get(Project, users=[user], language='es') + project_b = get(Project, users=[user], language='en') + project_c = get(Project, users=[user], language='br') + user_b = get(User) + project_d = get(Project, users=[user_b, user], language='ar') + + form = TranslationForm( + {'parent': project_a.pk}, + project=project_b, + user=user, + ) + self.assertTrue(form.is_valid()) + self.assertEqual( + {proj_id for proj_id, _ in form.fields['project'].choices}, + {project_b.id, project_c.id, project_d.id} + ) + + def test_form_translation_list_only_projects_with_different_lang(self): + # This would be necessary? + # Probably confusing + pass + + def test_form_translation_excludes_existing_translations(self): + user = get(User) + project_a = get(Project, users=[user], language='es') + project_b = get(Project, users=[user], language='en') + project_c = get(Project, users=[user], language='br') + project_d = get(Project, users=[user], language='ar') + project_e = get(Project, users=[user], language='aa') + + project_a.translations.add(project_b) + project_a.translations.add(project_c) + project_a.save() + + form = TranslationForm( + {'parent': project_a.pk}, + project=project_d, + user=user, + ) + self.assertTrue(form.is_valid()) + self.assertEqual( + {proj_id for proj_id, _ in form.fields['project'].choices}, + {project_d.id, project_e.id} + ) + + def test_form_translation_user_cant_add_other_user_project(self): + user = get(User) + project_a = get(Project, users=[user], language='es') + user_b = get(User) + project_b = get(Project, users=[user_b], language='en') + + form = TranslationForm( + {'parent': project_a.pk}, + project=project_b, + user=user, + ) + self.assertFalse(form.is_valid()) + self.assertNotIn( + project_b.id, + [proj_id for proj_id, _ in form.fields['project'].choices] + ) + + def test_form_translation_user_cant_add_project_with_same_lang(self): + user = get(User) + project_a = get(Project, users=[user], language='es') + project_b = get(Project, users=[user], language='es') + + form = TranslationForm( + {'parent': project_a.pk}, + project=project_b, + user=user, + ) + self.assertFalse(form.is_valid()) + + def test_form_translation_user_cant_add_project_with_same_lang_of_other_translation(self): + user = get(User) + project_a = get(Project, users=[user], language='es') + project_b = get(Project, users=[user], language='en') + project_c = get(Project, users=[user], language='en') + + project_a.translations.add(project_b) + project_a.save() + + form = TranslationForm( + {'parent': project_a.pk}, + project=project_c, + user=user, + ) + self.assertFalse(form.is_valid()) From 4a7cd3e301ae5766b6e50130fb329339f6ccc6b8 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 21:29:44 -0500 Subject: [PATCH 024/190] Fix tests --- .../rtd_tests/tests/test_project_forms.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/readthedocs/rtd_tests/tests/test_project_forms.py b/readthedocs/rtd_tests/tests/test_project_forms.py index d8db20e7aec..0e28a7db603 100644 --- a/readthedocs/rtd_tests/tests/test_project_forms.py +++ b/readthedocs/rtd_tests/tests/test_project_forms.py @@ -37,8 +37,8 @@ def test_form_translation_list_only_owner_projects(self): project_d = get(Project, users=[user_b], language='ar') form = TranslationForm( - {'parent': project_a.pk}, - project=project_b, + {'project': project_b.pk}, + parent=project_a, user=user, ) self.assertTrue(form.is_valid()) @@ -56,8 +56,8 @@ def test_form_translation_list_all_projects_where_is_owner(self): project_d = get(Project, users=[user_b, user], language='ar') form = TranslationForm( - {'parent': project_a.pk}, - project=project_b, + {'project': project_b.pk}, + parent=project_a, user=user, ) self.assertTrue(form.is_valid()) @@ -84,8 +84,8 @@ def test_form_translation_excludes_existing_translations(self): project_a.save() form = TranslationForm( - {'parent': project_a.pk}, - project=project_d, + {'project': project_d.pk}, + parent=project_a, user=user, ) self.assertTrue(form.is_valid()) @@ -101,8 +101,8 @@ def test_form_translation_user_cant_add_other_user_project(self): project_b = get(Project, users=[user_b], language='en') form = TranslationForm( - {'parent': project_a.pk}, - project=project_b, + {'project': project_b.pk}, + parent=project_a, user=user, ) self.assertFalse(form.is_valid()) @@ -117,8 +117,8 @@ def test_form_translation_user_cant_add_project_with_same_lang(self): project_b = get(Project, users=[user], language='es') form = TranslationForm( - {'parent': project_a.pk}, - project=project_b, + {'project': project_b.pk}, + parent=project_a, user=user, ) self.assertFalse(form.is_valid()) @@ -133,8 +133,8 @@ def test_form_translation_user_cant_add_project_with_same_lang_of_other_translat project_a.save() form = TranslationForm( - {'parent': project_a.pk}, - project=project_c, + {'project': project_c.pk}, + parent=project_a, user=user, ) self.assertFalse(form.is_valid()) From 4f77d9f4f6f42e3d61b757dd5cb63f0c346e31a7 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 21:35:23 -0500 Subject: [PATCH 025/190] Set project as ChoiceField --- readthedocs/projects/forms.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index caaeef9d0de..86e4d3bb079 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -496,11 +496,16 @@ class TranslationForm(forms.Form): """Project translation form.""" - project = forms.CharField() + project = forms.ChoiceField() def __init__(self, *args, **kwargs): self.parent = kwargs.pop('parent', None) + self.user = kwargs.pop('user') super(TranslationForm, self).__init__(*args, **kwargs) + self.fields['project'].choices = [ + (project.slug, project) + for project in self.get_translation_queryset().all() + ] def clean_project(self): translation_name = self.cleaned_data['project'] @@ -518,6 +523,13 @@ def clean_project(self): self.translation = translation_qs.first() return translation_name + def get_translation_queryset(self): + queryset = ( + Project.objects.for_admin_user(self.user) + .exclude(pk=self.parent.pk) + ) + return queryset + def save(self): project = self.parent.translations.add(self.translation) # Run symlinking and other sync logic to make sure we are in a good From 9d1246fcffd927000370abd8210247eb8c6691f5 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 21:35:49 -0500 Subject: [PATCH 026/190] Pass user to form --- readthedocs/projects/views/private.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/readthedocs/projects/views/private.py b/readthedocs/projects/views/private.py index 6db70fb6af5..ec6f393490c 100644 --- a/readthedocs/projects/views/private.py +++ b/readthedocs/projects/views/private.py @@ -575,7 +575,11 @@ def project_translations(request, project_slug): """Project translations view and form view.""" project = get_object_or_404( Project.objects.for_admin_user(request.user), slug=project_slug) - form = TranslationForm(data=request.POST or None, parent=project) + form = TranslationForm( + data=request.POST or None, + parent=project, + user=request.user, + ) if request.method == 'POST' and form.is_valid(): form.save() From 0206825b37e437afcb9b2b9a769f8a291e22e013 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 21:38:32 -0500 Subject: [PATCH 027/190] Set initial values to tests --- readthedocs/rtd_tests/tests/test_project.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/readthedocs/rtd_tests/tests/test_project.py b/readthedocs/rtd_tests/tests/test_project.py index 50d72f459f1..bdff1b1d651 100644 --- a/readthedocs/rtd_tests/tests/test_project.py +++ b/readthedocs/rtd_tests/tests/test_project.py @@ -130,12 +130,16 @@ def test_user_can_not_add_other_user_project_as_translation(self): user_a = get(User) user_a.set_password('test') user_a.save() - project_a = get(Project, users=[user_a], language='es') + project_a = get( + Project, users=[user_a], language='es', main_language_project=None + ) project_a.slug = 'project-a' project_a.save() user_b = get(User) - project_b = get(Project, users=[user_b], language='en') + project_b = get( + Project, users=[user_b], language='en', main_language_project=None + ) project_b.slug = 'project-b' project_b.save() From 7776b312cd3db41217079c5035bf281c05db4300 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 22:23:42 -0500 Subject: [PATCH 028/190] Validate by project id --- readthedocs/projects/forms.py | 21 +++++++++++---------- readthedocs/rtd_tests/tests/test_project.py | 6 +++--- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index 86e4d3bb079..fe9dc7aa5a2 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -503,25 +503,26 @@ def __init__(self, *args, **kwargs): self.user = kwargs.pop('user') super(TranslationForm, self).__init__(*args, **kwargs) self.fields['project'].choices = [ - (project.slug, project) + (project.id, project) for project in self.get_translation_queryset().all() ] def clean_project(self): - translation_name = self.cleaned_data['project'] - translation_qs = Project.objects.filter(slug=translation_name) - if not translation_qs.exists(): + project_id = self.cleaned_data['project'] + project_translation_qs = self.get_translation_queryset().filter( + pk=project_id + ) + if not project_translation_qs.exists(): raise forms.ValidationError( - (_('Project {name} does not exist').format( - name=translation_name))) - if translation_qs.first().language == self.parent.language: + (_('Project {id} does not exist').format( + id=project_id))) + self.translation = project_translation_qs.first() + if self.translation.language == self.parent.language: err = ('Both projects have a language of `{}`. ' 'Please choose one with another language'.format( self.parent.language)) raise forms.ValidationError(_(err)) - - self.translation = translation_qs.first() - return translation_name + return project_id def get_translation_queryset(self): queryset = ( diff --git a/readthedocs/rtd_tests/tests/test_project.py b/readthedocs/rtd_tests/tests/test_project.py index bdff1b1d651..dc8cc1c89bf 100644 --- a/readthedocs/rtd_tests/tests/test_project.py +++ b/readthedocs/rtd_tests/tests/test_project.py @@ -99,7 +99,7 @@ def test_user_can_add_own_project_as_translation(self): self.client.login(username=user_a.username, password='test') self.client.post( reverse('projects_translations', args=[project_a.slug]), - data={'project': project_b.slug} + data={'project': project_b.id} ) self.assertEqual(project_a.translations.first(), project_b) @@ -120,7 +120,7 @@ def test_user_can_add_project_as_translation_if_is_owner(self): self.client.login(username=user_a.username, password='test') self.client.post( reverse('projects_translations', args=[project_a.slug]), - data={'project': project_b.slug} + data={'project': project_b.id} ) self.assertEqual(project_a.translations.first(), project_b) @@ -147,7 +147,7 @@ def test_user_can_not_add_other_user_project_as_translation(self): self.client.login(username=user_a.username, password='test') self.client.post( reverse('projects_translations', args=[project_a.slug]), - data={'project': project_b.slug} + data={'project': project_b.id} ) self.assertEqual(project_a.translations.count(), 0) From 666bf4273286b263762d5e69f9d035866cc208c2 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 22:41:33 -0500 Subject: [PATCH 029/190] Validate for existen translations --- readthedocs/projects/forms.py | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index fe9dc7aa5a2..c3ecec58dae 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -513,15 +513,32 @@ def clean_project(self): pk=project_id ) if not project_translation_qs.exists(): + msg = 'Project {id} does not exist' raise forms.ValidationError( - (_('Project {id} does not exist').format( - id=project_id))) + (_(msg).format(id=project_id)) + ) self.translation = project_translation_qs.first() if self.translation.language == self.parent.language: - err = ('Both projects have a language of `{}`. ' - 'Please choose one with another language'.format( - self.parent.language)) - raise forms.ValidationError(_(err)) + msg = ( + 'Both projects have a language of `{}`. ' + 'Please choose one with another language.' + ) + raise forms.ValidationError( + _(msg).format(self.parent.language) + ) + exists_translation = ( + self.parent.translations + .filter(language=self.translation.language) + .exists() + ) + if exists_translation: + msg = ( + 'There is already a translation of language `{}`. ' + 'Please choose one with another language.' + ) + raise forms.ValidationError( + _(msg).format(self.parent.language) + ) return project_id def get_translation_queryset(self): From f4acc804ba4287398ad71cddb3aea19f12af3b4b Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 23:05:15 -0500 Subject: [PATCH 030/190] Set main language to None explicitly --- readthedocs/rtd_tests/tests/test_project.py | 16 ++- .../rtd_tests/tests/test_project_forms.py | 100 ++++++++++++++---- 2 files changed, 92 insertions(+), 24 deletions(-) diff --git a/readthedocs/rtd_tests/tests/test_project.py b/readthedocs/rtd_tests/tests/test_project.py index dc8cc1c89bf..6f73737d931 100644 --- a/readthedocs/rtd_tests/tests/test_project.py +++ b/readthedocs/rtd_tests/tests/test_project.py @@ -111,11 +111,17 @@ def test_user_can_add_project_as_translation_if_is_owner(self): user_a = get(User) user_a.set_password('test') user_a.save() - project_a = get(Project, users=[user_a], language='es') + project_a = get( + Project, users=[user_a], + language='es', main_language_project=None + ) user_b = get(User) # User A and B are owners of project B - project_b = get(Project, users=[user_b, user_a], language='en') + project_b = get( + Project, users=[user_b, user_a], + language='en', main_language_project=None + ) self.client.login(username=user_a.username, password='test') self.client.post( @@ -131,14 +137,16 @@ def test_user_can_not_add_other_user_project_as_translation(self): user_a.set_password('test') user_a.save() project_a = get( - Project, users=[user_a], language='es', main_language_project=None + Project, users=[user_a], + language='es', main_language_project=None ) project_a.slug = 'project-a' project_a.save() user_b = get(User) project_b = get( - Project, users=[user_b], language='en', main_language_project=None + Project, users=[user_b], + language='en', main_language_project=None ) project_b.slug = 'project-b' project_b.save() diff --git a/readthedocs/rtd_tests/tests/test_project_forms.py b/readthedocs/rtd_tests/tests/test_project_forms.py index 0e28a7db603..62912dc2d3f 100644 --- a/readthedocs/rtd_tests/tests/test_project_forms.py +++ b/readthedocs/rtd_tests/tests/test_project_forms.py @@ -30,11 +30,23 @@ def test_form_spam(self, mocked_validator): def test_form_translation_list_only_owner_projects(self): user = get(User) - project_a = get(Project, users=[user], language='es') - project_b = get(Project, users=[user], language='en') - project_c = get(Project, users=[user], language='br') + project_a = get( + Project, users=[user], + language='es', main_language_project=None + ) + project_b = get( + Project, users=[user], + language='en', main_language_project=None + ) + project_c = get( + Project, users=[user], + language='br', main_language_project=None + ) user_b = get(User) - project_d = get(Project, users=[user_b], language='ar') + project_d = get( + Project, users=[user_b], + language='ar', main_language_project=None + ) form = TranslationForm( {'project': project_b.pk}, @@ -49,11 +61,23 @@ def test_form_translation_list_only_owner_projects(self): def test_form_translation_list_all_projects_where_is_owner(self): user = get(User) - project_a = get(Project, users=[user], language='es') - project_b = get(Project, users=[user], language='en') - project_c = get(Project, users=[user], language='br') + project_a = get( + Project, users=[user], + language='es', main_language_project=None + ) + project_b = get( + Project, users=[user], + language='en', main_language_project=None + ) + project_c = get( + Project, users=[user], + language='br', main_language_project=None + ) user_b = get(User) - project_d = get(Project, users=[user_b, user], language='ar') + project_d = get( + Project, users=[user_b, user], + language='ar', main_language_project=None + ) form = TranslationForm( {'project': project_b.pk}, @@ -73,11 +97,26 @@ def test_form_translation_list_only_projects_with_different_lang(self): def test_form_translation_excludes_existing_translations(self): user = get(User) - project_a = get(Project, users=[user], language='es') - project_b = get(Project, users=[user], language='en') - project_c = get(Project, users=[user], language='br') - project_d = get(Project, users=[user], language='ar') - project_e = get(Project, users=[user], language='aa') + project_a = get( + Project, users=[user], + language='es', main_language_project=None + ) + project_b = get( + Project, users=[user], + language='en', main_language_project=None + ) + project_c = get( + Project, users=[user], + language='br', main_language_project=None + ) + project_d = get( + Project, users=[user], + language='ar', main_language_project=None + ) + project_e = get( + Project, users=[user], + language='aa', main_language_project=None + ) project_a.translations.add(project_b) project_a.translations.add(project_c) @@ -96,9 +135,15 @@ def test_form_translation_excludes_existing_translations(self): def test_form_translation_user_cant_add_other_user_project(self): user = get(User) - project_a = get(Project, users=[user], language='es') + project_a = get( + Project, users=[user], + language='es', main_language_project=None + ) user_b = get(User) - project_b = get(Project, users=[user_b], language='en') + project_b = get( + Project, users=[user_b], + language='en', main_language_project=None + ) form = TranslationForm( {'project': project_b.pk}, @@ -113,8 +158,14 @@ def test_form_translation_user_cant_add_other_user_project(self): def test_form_translation_user_cant_add_project_with_same_lang(self): user = get(User) - project_a = get(Project, users=[user], language='es') - project_b = get(Project, users=[user], language='es') + project_a = get( + Project, users=[user], + language='es', main_language_project=None + ) + project_b = get( + Project, users=[user], + language='es', main_language_project=None + ) form = TranslationForm( {'project': project_b.pk}, @@ -125,9 +176,18 @@ def test_form_translation_user_cant_add_project_with_same_lang(self): def test_form_translation_user_cant_add_project_with_same_lang_of_other_translation(self): user = get(User) - project_a = get(Project, users=[user], language='es') - project_b = get(Project, users=[user], language='en') - project_c = get(Project, users=[user], language='en') + project_a = get( + Project, users=[user], + language='es', main_language_project=None + ) + project_b = get( + Project, users=[user], + language='en', main_language_project=None + ) + project_c = get( + Project, users=[user], + language='en', main_language_project=None + ) project_a.translations.add(project_b) project_a.save() From 2866ab02340bf97cf42f213f05b3c1a2310b85e4 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 23:37:15 -0500 Subject: [PATCH 031/190] Filter projects that don't have translations --- readthedocs/projects/forms.py | 1 + 1 file changed, 1 insertion(+) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index c3ecec58dae..2156d56c6c2 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -544,6 +544,7 @@ def clean_project(self): def get_translation_queryset(self): queryset = ( Project.objects.for_admin_user(self.user) + .filter(main_language_project=None) .exclude(pk=self.parent.pk) ) return queryset From c37dff0eb3c8e3561e82ccc8a17c6b602250cd4b Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 23:44:00 -0500 Subject: [PATCH 032/190] Fix message --- readthedocs/projects/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index 2156d56c6c2..f7dfdd68fe4 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -537,7 +537,7 @@ def clean_project(self): 'Please choose one with another language.' ) raise forms.ValidationError( - _(msg).format(self.parent.language) + _(msg).format(self.translation.language) ) return project_id From 1e5657d18b930aebdb6482bebf7f8bf7180b91cb Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 23:52:30 -0500 Subject: [PATCH 033/190] Add tests for circular dependencies --- .../rtd_tests/tests/test_project_forms.py | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/readthedocs/rtd_tests/tests/test_project_forms.py b/readthedocs/rtd_tests/tests/test_project_forms.py index 62912dc2d3f..5957979f98c 100644 --- a/readthedocs/rtd_tests/tests/test_project_forms.py +++ b/readthedocs/rtd_tests/tests/test_project_forms.py @@ -198,3 +198,74 @@ def test_form_translation_user_cant_add_project_with_same_lang_of_other_translat user=user, ) self.assertFalse(form.is_valid()) + + def test_form_translation_no_nesting_translation(self): + user = get(User) + project_a = get( + Project, users=[user], + language='es', main_language_project=None + ) + project_b = get( + Project, users=[user], + language='en', main_language_project=None + ) + project_c = get( + Project, users=[user], + language='ar', main_language_project=None + ) + + project_a.translations.add(project_b) + project_a.save() + + form = TranslationForm( + {'project': project_b.pk}, + parent=project_c, + user=user, + ) + self.assertFalse(form.is_valid()) + + def test_form_translation_no_nesting_translation_case_2(self): + user = get(User) + project_a = get( + Project, users=[user], + language='es', main_language_project=None + ) + project_b = get( + Project, users=[user], + language='en', main_language_project=None + ) + project_c = get( + Project, users=[user], + language='ar', main_language_project=None + ) + + project_a.translations.add(project_b) + project_a.save() + + form = TranslationForm( + {'project': project_a.pk}, + parent=project_c, + user=user, + ) + self.assertFalse(form.is_valid()) + + def test_form_translation_no_circular_translations(self): + user = get(User) + project_a = get( + Project, users=[user], + language='es', main_language_project=None + ) + project_b = get( + Project, users=[user], + language='en', main_language_project=None + ) + + project_a.translations.add(project_b) + project_a.save() + + form = TranslationForm( + {'project': project_a.pk}, + parent=project_b, + user=user, + ) + self.assertFalse(form.is_valid()) From bd68928bbb835b186f5a216e3257bdba7a7d8ada Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 23:52:55 -0500 Subject: [PATCH 034/190] Check for circular translations --- readthedocs/projects/forms.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index f7dfdd68fe4..a8a6434a77d 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -539,6 +539,15 @@ def clean_project(self): raise forms.ValidationError( _(msg).format(self.translation.language) ) + is_parent = self.translation.translations.count() > 0 + if is_parent: + msg = ( + 'This project has translations. ' + 'Please choose one without translations.' + ) + raise forms.ValidationError( + _(msg).format(self.translation.language) + ) return project_id def get_translation_queryset(self): From 640960a57a661ed62ced800f8634f3e2739d73dd Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Tue, 27 Feb 2018 23:57:13 -0500 Subject: [PATCH 035/190] Improve template --- .../projects/project_translations.html | 57 ++++++++++++------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/readthedocs/templates/projects/project_translations.html b/readthedocs/templates/projects/project_translations.html index 8fc223cf6d2..e13f91e0d2d 100644 --- a/readthedocs/templates/projects/project_translations.html +++ b/readthedocs/templates/projects/project_translations.html @@ -13,29 +13,48 @@ {% block project_edit_content %}

          - {% trans "This allows you to add translations to your project. Select the project below that is a translation of your current project." %} + {% blocktrans trimmed %} + This allows you to add translations to your project. + Select the project below that is a translation of your current project. + {% endblocktrans %}

          -

          {% trans "Existing Translations" %}

          -

          -

          -

          - {% trans "Choose which project you would like to add as a translation." %} -

          -
          {% csrf_token %} - {{ form.as_p }} + {% if project.main_language_project %} +

          + {% blocktrans trimmed with language=project.language main_project=project.main_language_project %} + This project is already configured as {{ language }} translation of + {{ main_project }}. + Nested translations are not supported. + {% endblocktrans %} +

          + + + {% blocktrans trimmed with main_project=project.main_language_project %} + View translations of {{ main_project }} + {% endblocktrans %} + + {% else %} +

          +

          +

          - + {% trans "Choose which project you would like to add as a translation." %}

          -
          +
          {% csrf_token %} + {{ form.as_p }} +

          + +

          +
          + {% endif %} {% endblock %} From 5814aeff57184ee349f3725960799a3450e949c6 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 15:46:54 -0500 Subject: [PATCH 036/190] Changes on the template --- .../templates/projects/project_translations.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/readthedocs/templates/projects/project_translations.html b/readthedocs/templates/projects/project_translations.html index e13f91e0d2d..153b7374fd2 100644 --- a/readthedocs/templates/projects/project_translations.html +++ b/readthedocs/templates/projects/project_translations.html @@ -21,16 +21,16 @@ {% if project.main_language_project %}

          - {% blocktrans trimmed with language=project.language main_project=project.main_language_project %} + {% blocktrans trimmed with language=project.get_language_display main_project=project.main_language_project.name %} This project is already configured as {{ language }} translation of - {{ main_project }}. + "{{ main_project }}". Nested translations are not supported. {% endblocktrans %}

          - {% blocktrans trimmed with main_project=project.main_language_project %} - View translations of {{ main_project }} + {% blocktrans trimmed with main_project=project.main_language_project.name %} + View translations of "{{ main_project }}". {% endblocktrans %} {% else %} @@ -38,9 +38,9 @@ From 16f3527b7690345af0d028eb5bfb65eb95b5a4f0 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 15:47:22 -0500 Subject: [PATCH 037/190] Remove useless js --- .../templates/projects/project_translations.html | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/readthedocs/templates/projects/project_translations.html b/readthedocs/templates/projects/project_translations.html index 153b7374fd2..3ee191b1b1e 100644 --- a/readthedocs/templates/projects/project_translations.html +++ b/readthedocs/templates/projects/project_translations.html @@ -56,16 +56,3 @@ {% endif %} {% endblock %} - - -{% block footerjs %} - $('#id_project').autocomplete({ - source: '{% url "search_autocomplete" %}', - minLength: 2, - open: function(event, ui) { - ac_top = $('.ui-autocomplete').css('top'); - $('.ui-autocomplete').css({'width': '233px', 'top': ac_top + 10 }); - } - }); - -{% endblock %} From 8d6efefa3259acd685b042f26323e6a92bdf4470 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 15:55:40 -0500 Subject: [PATCH 038/190] Better error messages --- readthedocs/projects/forms.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index a8a6434a77d..81a29446723 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -508,23 +508,23 @@ def __init__(self, *args, **kwargs): ] def clean_project(self): - project_id = self.cleaned_data['project'] + translation_project_slug = self.cleaned_data['project'] project_translation_qs = self.get_translation_queryset().filter( - pk=project_id + pk=translation_project_slug ) if not project_translation_qs.exists(): - msg = 'Project {id} does not exist' + msg = 'Project "{}" does not exist.' raise forms.ValidationError( - (_(msg).format(id=project_id)) + (_(msg).format(translation_project_slug)) ) self.translation = project_translation_qs.first() if self.translation.language == self.parent.language: msg = ( - 'Both projects have a language of `{}`. ' + 'Both projects have a language of "{}". ' 'Please choose one with another language.' ) raise forms.ValidationError( - _(msg).format(self.parent.language) + _(msg).format(self.parent.get_language_display) ) exists_translation = ( self.parent.translations @@ -533,13 +533,13 @@ def clean_project(self): ) if exists_translation: msg = ( - 'There is already a translation of language `{}`. ' + 'There is already a translation of language "{}". ' 'Please choose one with another language.' ) raise forms.ValidationError( - _(msg).format(self.translation.language) + _(msg).format(self.translation.get_language_display) ) - is_parent = self.translation.translations.count() > 0 + is_parent = self.translation.translations.exists() if is_parent: msg = ( 'This project has translations. ' @@ -548,7 +548,7 @@ def clean_project(self): raise forms.ValidationError( _(msg).format(self.translation.language) ) - return project_id + return translation_project_slug def get_translation_queryset(self): queryset = ( From 062bff68cfc35145f90432361eece7edcff01a25 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 15:55:59 -0500 Subject: [PATCH 039/190] Use project slug as identifier --- readthedocs/projects/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index 81a29446723..e1ef6ea32bc 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -503,7 +503,7 @@ def __init__(self, *args, **kwargs): self.user = kwargs.pop('user') super(TranslationForm, self).__init__(*args, **kwargs) self.fields['project'].choices = [ - (project.id, project) + (project.slug, project) for project in self.get_translation_queryset().all() ] From e527b35d660c1f3369f12f51d83f2a563cea197f Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 16:33:00 -0500 Subject: [PATCH 040/190] Update tests --- readthedocs/projects/forms.py | 2 +- readthedocs/rtd_tests/tests/test_project.py | 16 ++++---- .../rtd_tests/tests/test_project_forms.py | 39 ++++++++----------- 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index e1ef6ea32bc..7be998abf28 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -510,7 +510,7 @@ def __init__(self, *args, **kwargs): def clean_project(self): translation_project_slug = self.cleaned_data['project'] project_translation_qs = self.get_translation_queryset().filter( - pk=translation_project_slug + slug=translation_project_slug ) if not project_translation_qs.exists(): msg = 'Project "{}" does not exist.' diff --git a/readthedocs/rtd_tests/tests/test_project.py b/readthedocs/rtd_tests/tests/test_project.py index 6f73737d931..3068a1bd578 100644 --- a/readthedocs/rtd_tests/tests/test_project.py +++ b/readthedocs/rtd_tests/tests/test_project.py @@ -99,18 +99,19 @@ def test_user_can_add_own_project_as_translation(self): self.client.login(username=user_a.username, password='test') self.client.post( reverse('projects_translations', args=[project_a.slug]), - data={'project': project_b.id} + data={'project': project_b.slug} ) self.assertEqual(project_a.translations.first(), project_b) - # this test don't pass, but on the site it's ok. - # self.assertEqual(project_b.main_language_project, project_a) + project_b.refresh_from_db() + self.assertEqual(project_b.main_language_project, project_a) def test_user_can_add_project_as_translation_if_is_owner(self): # Two users, two projects with different language user_a = get(User) user_a.set_password('test') user_a.save() + project_a = get( Project, users=[user_a], language='es', main_language_project=None @@ -126,7 +127,7 @@ def test_user_can_add_project_as_translation_if_is_owner(self): self.client.login(username=user_a.username, password='test') self.client.post( reverse('projects_translations', args=[project_a.slug]), - data={'project': project_b.id} + data={'project': project_b.slug} ) self.assertEqual(project_a.translations.first(), project_b) @@ -140,25 +141,22 @@ def test_user_can_not_add_other_user_project_as_translation(self): Project, users=[user_a], language='es', main_language_project=None ) - project_a.slug = 'project-a' - project_a.save() user_b = get(User) project_b = get( Project, users=[user_b], language='en', main_language_project=None ) - project_b.slug = 'project-b' - project_b.save() # User A try to add project B as translation of project A self.client.login(username=user_a.username, password='test') self.client.post( reverse('projects_translations', args=[project_a.slug]), - data={'project': project_b.id} + data={'project': project_b.slug} ) self.assertEqual(project_a.translations.count(), 0) + project_b.refresh_from_db() self.assertIsNone(project_b.main_language_project) def test_token(self): diff --git a/readthedocs/rtd_tests/tests/test_project_forms.py b/readthedocs/rtd_tests/tests/test_project_forms.py index 5957979f98c..5a3fa0983ca 100644 --- a/readthedocs/rtd_tests/tests/test_project_forms.py +++ b/readthedocs/rtd_tests/tests/test_project_forms.py @@ -49,14 +49,14 @@ def test_form_translation_list_only_owner_projects(self): ) form = TranslationForm( - {'project': project_b.pk}, + {'project': project_b.slug}, parent=project_a, user=user, ) self.assertTrue(form.is_valid()) self.assertEqual( - {proj_id for proj_id, _ in form.fields['project'].choices}, - {project_b.id, project_c.id} + {proj_slug for proj_slug, _ in form.fields['project'].choices}, + {project_b.slug, project_c.slug} ) def test_form_translation_list_all_projects_where_is_owner(self): @@ -80,21 +80,16 @@ def test_form_translation_list_all_projects_where_is_owner(self): ) form = TranslationForm( - {'project': project_b.pk}, + {'project': project_b.slug}, parent=project_a, user=user, ) self.assertTrue(form.is_valid()) self.assertEqual( - {proj_id for proj_id, _ in form.fields['project'].choices}, - {project_b.id, project_c.id, project_d.id} + {proj_slug for proj_slug, _ in form.fields['project'].choices}, + {project_b.slug, project_c.slug, project_d.slug} ) - def test_form_translation_list_only_projects_with_different_lang(self): - # This would be necessary? - # Probably confusing - pass - def test_form_translation_excludes_existing_translations(self): user = get(User) project_a = get( @@ -123,14 +118,14 @@ def test_form_translation_excludes_existing_translations(self): project_a.save() form = TranslationForm( - {'project': project_d.pk}, + {'project': project_d.slug}, parent=project_a, user=user, ) self.assertTrue(form.is_valid()) self.assertEqual( - {proj_id for proj_id, _ in form.fields['project'].choices}, - {project_d.id, project_e.id} + {proj_slug for proj_slug, _ in form.fields['project'].choices}, + {project_d.slug, project_e.slug} ) def test_form_translation_user_cant_add_other_user_project(self): @@ -146,14 +141,14 @@ def test_form_translation_user_cant_add_other_user_project(self): ) form = TranslationForm( - {'project': project_b.pk}, + {'project': project_b.slug}, parent=project_a, user=user, ) self.assertFalse(form.is_valid()) self.assertNotIn( - project_b.id, - [proj_id for proj_id, _ in form.fields['project'].choices] + project_b.slug, + [proj_slug for proj_slug, _ in form.fields['project'].choices] ) def test_form_translation_user_cant_add_project_with_same_lang(self): @@ -168,7 +163,7 @@ def test_form_translation_user_cant_add_project_with_same_lang(self): ) form = TranslationForm( - {'project': project_b.pk}, + {'project': project_b.slug}, parent=project_a, user=user, ) @@ -193,7 +188,7 @@ def test_form_translation_user_cant_add_project_with_same_lang_of_other_translat project_a.save() form = TranslationForm( - {'project': project_c.pk}, + {'project': project_c.slug}, parent=project_a, user=user, ) @@ -218,7 +213,7 @@ def test_form_translation_no_nesting_translation(self): project_a.save() form = TranslationForm( - {'project': project_b.pk}, + {'project': project_b.slug}, parent=project_c, user=user, ) @@ -243,7 +238,7 @@ def test_form_translation_no_nesting_translation_case_2(self): project_a.save() form = TranslationForm( - {'project': project_a.pk}, + {'project': project_a.slug}, parent=project_c, user=user, ) @@ -264,7 +259,7 @@ def test_form_translation_no_circular_translations(self): project_a.save() form = TranslationForm( - {'project': project_a.pk}, + {'project': project_a.slug}, parent=project_b, user=user, ) From 775b19fe905f2e2ad1cc4d792ececf7027999768 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 16:49:18 -0500 Subject: [PATCH 041/190] Use fixure users --- readthedocs/rtd_tests/tests/test_project.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/readthedocs/rtd_tests/tests/test_project.py b/readthedocs/rtd_tests/tests/test_project.py index 3068a1bd578..6b026e79d25 100644 --- a/readthedocs/rtd_tests/tests/test_project.py +++ b/readthedocs/rtd_tests/tests/test_project.py @@ -84,9 +84,7 @@ def test_translation_delete(self): Project.objects.get(pk=project_keep.pk).main_language_project) def test_user_can_add_own_project_as_translation(self): - user_a = get(User) - user_a.set_password('test') - user_a.save() + user_a = User.objects.get(username='eric') project_a = get( Project, users=[user_a], language='en', main_language_project=None @@ -108,16 +106,13 @@ def test_user_can_add_own_project_as_translation(self): def test_user_can_add_project_as_translation_if_is_owner(self): # Two users, two projects with different language - user_a = get(User) - user_a.set_password('test') - user_a.save() - + user_a = User.objects.get(username='eric') project_a = get( Project, users=[user_a], language='es', main_language_project=None ) - user_b = get(User) + user_b = User.objects.get(username='tester') # User A and B are owners of project B project_b = get( Project, users=[user_b, user_a], @@ -134,15 +129,13 @@ def test_user_can_add_project_as_translation_if_is_owner(self): def test_user_can_not_add_other_user_project_as_translation(self): # Two users, two projects with different language - user_a = get(User) - user_a.set_password('test') - user_a.save() + user_a = User.objects.get(username='eric') project_a = get( Project, users=[user_a], language='es', main_language_project=None ) - user_b = get(User) + user_b = User.objects.get(username='tester') project_b = get( Project, users=[user_b], language='en', main_language_project=None From ffd60dab8c6e562e7cdffc543f8308b1a4c00e0e Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 17:03:54 -0500 Subject: [PATCH 042/190] Check for error message --- readthedocs/rtd_tests/tests/test_project.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readthedocs/rtd_tests/tests/test_project.py b/readthedocs/rtd_tests/tests/test_project.py index 6b026e79d25..c7d911283a5 100644 --- a/readthedocs/rtd_tests/tests/test_project.py +++ b/readthedocs/rtd_tests/tests/test_project.py @@ -143,11 +143,12 @@ def test_user_can_not_add_other_user_project_as_translation(self): # User A try to add project B as translation of project A self.client.login(username=user_a.username, password='test') - self.client.post( + resp = self.client.post( reverse('projects_translations', args=[project_a.slug]), data={'project': project_b.slug} ) + self.assertIn('Select a valid choice', resp.content.decode('utf-8')) self.assertEqual(project_a.translations.count(), 0) project_b.refresh_from_db() self.assertIsNone(project_b.main_language_project) From 62a261d78ebde4bc7d1a01d777af59ceff619970 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 17:34:28 -0500 Subject: [PATCH 043/190] Refactor tests --- .../rtd_tests/tests/test_project_forms.py | 152 +++++------------- 1 file changed, 40 insertions(+), 112 deletions(-) diff --git a/readthedocs/rtd_tests/tests/test_project_forms.py b/readthedocs/rtd_tests/tests/test_project_forms.py index 5a3fa0983ca..ed204a8c48f 100644 --- a/readthedocs/rtd_tests/tests/test_project_forms.py +++ b/readthedocs/rtd_tests/tests/test_project_forms.py @@ -28,25 +28,23 @@ def test_form_spam(self, mocked_validator): with self.assertRaises(ProjectSpamError): form.is_valid() + +class TestTranslationForm(TestCase): + + def get_project(self, lang, users, **kwargs): + return get( + Project, language=lang, users=users, + main_language_project=None, **kwargs + ) + def test_form_translation_list_only_owner_projects(self): user = get(User) - project_a = get( - Project, users=[user], - language='es', main_language_project=None - ) - project_b = get( - Project, users=[user], - language='en', main_language_project=None - ) - project_c = get( - Project, users=[user], - language='br', main_language_project=None - ) + project_a = self.get_project(lang='es', users=[user]) + project_b = self.get_project(lang='en', users=[user]) + project_c = self.get_project(lang='br', users=[user]) + user_b = get(User) - project_d = get( - Project, users=[user_b], - language='ar', main_language_project=None - ) + project_d = self.get_project(lang='ar', users=[user_b]) form = TranslationForm( {'project': project_b.slug}, @@ -61,23 +59,12 @@ def test_form_translation_list_only_owner_projects(self): def test_form_translation_list_all_projects_where_is_owner(self): user = get(User) - project_a = get( - Project, users=[user], - language='es', main_language_project=None - ) - project_b = get( - Project, users=[user], - language='en', main_language_project=None - ) - project_c = get( - Project, users=[user], - language='br', main_language_project=None - ) + project_a = self.get_project(lang='es', users=[user]) + project_b = self.get_project(lang='en', users=[user]) + project_c = self.get_project(lang='br', users=[user]) + user_b = get(User) - project_d = get( - Project, users=[user_b, user], - language='ar', main_language_project=None - ) + project_d = self.get_project(lang='ar', users=[user_b, user]) form = TranslationForm( {'project': project_b.slug}, @@ -92,26 +79,11 @@ def test_form_translation_list_all_projects_where_is_owner(self): def test_form_translation_excludes_existing_translations(self): user = get(User) - project_a = get( - Project, users=[user], - language='es', main_language_project=None - ) - project_b = get( - Project, users=[user], - language='en', main_language_project=None - ) - project_c = get( - Project, users=[user], - language='br', main_language_project=None - ) - project_d = get( - Project, users=[user], - language='ar', main_language_project=None - ) - project_e = get( - Project, users=[user], - language='aa', main_language_project=None - ) + project_a = self.get_project(lang='es', users=[user]) + project_b = self.get_project(lang='en', users=[user]) + project_c = self.get_project(lang='br', users=[user]) + project_d = self.get_project(lang='ar', users=[user]) + project_e = self.get_project(lang='aa', users=[user]) project_a.translations.add(project_b) project_a.translations.add(project_c) @@ -130,15 +102,10 @@ def test_form_translation_excludes_existing_translations(self): def test_form_translation_user_cant_add_other_user_project(self): user = get(User) - project_a = get( - Project, users=[user], - language='es', main_language_project=None - ) + project_a = self.get_project(lang='es', users=[user]) + user_b = get(User) - project_b = get( - Project, users=[user_b], - language='en', main_language_project=None - ) + project_b = self.get_project(lang='en', users=[user_b]) form = TranslationForm( {'project': project_b.slug}, @@ -153,14 +120,8 @@ def test_form_translation_user_cant_add_other_user_project(self): def test_form_translation_user_cant_add_project_with_same_lang(self): user = get(User) - project_a = get( - Project, users=[user], - language='es', main_language_project=None - ) - project_b = get( - Project, users=[user], - language='es', main_language_project=None - ) + project_a = self.get_project(lang='es', users=[user]) + project_b = self.get_project(lang='es', users=[user]) form = TranslationForm( {'project': project_b.slug}, @@ -171,18 +132,9 @@ def test_form_translation_user_cant_add_project_with_same_lang(self): def test_form_translation_user_cant_add_project_with_same_lang_of_other_translation(self): user = get(User) - project_a = get( - Project, users=[user], - language='es', main_language_project=None - ) - project_b = get( - Project, users=[user], - language='en', main_language_project=None - ) - project_c = get( - Project, users=[user], - language='en', main_language_project=None - ) + project_a = self.get_project(lang='es', users=[user]) + project_b = self.get_project(lang='en', users=[user]) + project_c = self.get_project(lang='en', users=[user]) project_a.translations.add(project_b) project_a.save() @@ -196,18 +148,9 @@ def test_form_translation_user_cant_add_project_with_same_lang_of_other_translat def test_form_translation_no_nesting_translation(self): user = get(User) - project_a = get( - Project, users=[user], - language='es', main_language_project=None - ) - project_b = get( - Project, users=[user], - language='en', main_language_project=None - ) - project_c = get( - Project, users=[user], - language='ar', main_language_project=None - ) + project_a = self.get_project(lang='es', users=[user]) + project_b = self.get_project(lang='en', users=[user]) + project_c = self.get_project(lang='br', users=[user]) project_a.translations.add(project_b) project_a.save() @@ -221,18 +164,9 @@ def test_form_translation_no_nesting_translation(self): def test_form_translation_no_nesting_translation_case_2(self): user = get(User) - project_a = get( - Project, users=[user], - language='es', main_language_project=None - ) - project_b = get( - Project, users=[user], - language='en', main_language_project=None - ) - project_c = get( - Project, users=[user], - language='ar', main_language_project=None - ) + project_a = self.get_project(lang='es', users=[user]) + project_b = self.get_project(lang='en', users=[user]) + project_c = self.get_project(lang='br', users=[user]) project_a.translations.add(project_b) project_a.save() @@ -246,14 +180,8 @@ def test_form_translation_no_nesting_translation_case_2(self): def test_form_translation_no_circular_translations(self): user = get(User) - project_a = get( - Project, users=[user], - language='es', main_language_project=None - ) - project_b = get( - Project, users=[user], - language='en', main_language_project=None - ) + project_a = self.get_project(lang='es', users=[user]) + project_b = self.get_project(lang='en', users=[user]) project_a.translations.add(project_b) project_a.save() From c7b5638f859003cf0ef63a2d5895180f86214d81 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 17:44:44 -0500 Subject: [PATCH 044/190] Use same test --- .../rtd_tests/tests/test_project_forms.py | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/readthedocs/rtd_tests/tests/test_project_forms.py b/readthedocs/rtd_tests/tests/test_project_forms.py index ed204a8c48f..e8a1ed7cda4 100644 --- a/readthedocs/rtd_tests/tests/test_project_forms.py +++ b/readthedocs/rtd_tests/tests/test_project_forms.py @@ -45,6 +45,10 @@ def test_form_translation_list_only_owner_projects(self): user_b = get(User) project_d = self.get_project(lang='ar', users=[user_b]) + project_e = self.get_project(lang='ga', users=[user_b]) + + # shared project + project_s = self.get_project(lang='fr', users=[user_b, user]) form = TranslationForm( {'project': project_b.slug}, @@ -54,27 +58,18 @@ def test_form_translation_list_only_owner_projects(self): self.assertTrue(form.is_valid()) self.assertEqual( {proj_slug for proj_slug, _ in form.fields['project'].choices}, - {project_b.slug, project_c.slug} + {project_b.slug, project_c.slug, project_s.slug} ) - def test_form_translation_list_all_projects_where_is_owner(self): - user = get(User) - project_a = self.get_project(lang='es', users=[user]) - project_b = self.get_project(lang='en', users=[user]) - project_c = self.get_project(lang='br', users=[user]) - - user_b = get(User) - project_d = self.get_project(lang='ar', users=[user_b, user]) - form = TranslationForm( - {'project': project_b.slug}, - parent=project_a, - user=user, + {'project': project_e.slug}, + parent=project_d, + user=user_b, ) self.assertTrue(form.is_valid()) self.assertEqual( {proj_slug for proj_slug, _ in form.fields['project'].choices}, - {project_b.slug, project_c.slug, project_d.slug} + {project_e.slug, project_s.slug} ) def test_form_translation_excludes_existing_translations(self): From 28cc7b6a32eeae7143749877c3ccbfde65692559 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 18:31:07 -0500 Subject: [PATCH 045/190] Check error messages --- .../rtd_tests/tests/test_project_forms.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/readthedocs/rtd_tests/tests/test_project_forms.py b/readthedocs/rtd_tests/tests/test_project_forms.py index e8a1ed7cda4..8c0bf2fd47a 100644 --- a/readthedocs/rtd_tests/tests/test_project_forms.py +++ b/readthedocs/rtd_tests/tests/test_project_forms.py @@ -108,6 +108,10 @@ def test_form_translation_user_cant_add_other_user_project(self): user=user, ) self.assertFalse(form.is_valid()) + self.assertIn( + 'Select a valid choice', + ''.join(form.errors['project']) + ) self.assertNotIn( project_b.slug, [proj_slug for proj_slug, _ in form.fields['project'].choices] @@ -124,6 +128,10 @@ def test_form_translation_user_cant_add_project_with_same_lang(self): user=user, ) self.assertFalse(form.is_valid()) + self.assertIn( + 'Both projects have a language of "es"', + ''.join(form.errors['project']) + ) def test_form_translation_user_cant_add_project_with_same_lang_of_other_translation(self): user = get(User) @@ -140,6 +148,10 @@ def test_form_translation_user_cant_add_project_with_same_lang_of_other_translat user=user, ) self.assertFalse(form.is_valid()) + self.assertIn( + 'There is already a translation of language "en"', + ''.join(form.errors['project']) + ) def test_form_translation_no_nesting_translation(self): user = get(User) @@ -156,6 +168,10 @@ def test_form_translation_no_nesting_translation(self): user=user, ) self.assertFalse(form.is_valid()) + self.assertIn( + 'Select a valid choice', + ''.join(form.errors['project']) + ) def test_form_translation_no_nesting_translation_case_2(self): user = get(User) @@ -172,6 +188,10 @@ def test_form_translation_no_nesting_translation_case_2(self): user=user, ) self.assertFalse(form.is_valid()) + self.assertIn( + 'This project has translations', + ''.join(form.errors['project']) + ) def test_form_translation_no_circular_translations(self): user = get(User) @@ -187,3 +207,7 @@ def test_form_translation_no_circular_translations(self): user=user, ) self.assertFalse(form.is_valid()) + self.assertIn( + 'This project has translations', + ''.join(form.errors['project']) + ) From 68a056c2201e4971cc4ca25c3a4ba0cd14cbfb7a Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 18:35:53 -0500 Subject: [PATCH 046/190] Fix error messages --- readthedocs/projects/forms.py | 4 ++-- readthedocs/rtd_tests/tests/test_project_forms.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index 7be998abf28..b858b8d684c 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -524,7 +524,7 @@ def clean_project(self): 'Please choose one with another language.' ) raise forms.ValidationError( - _(msg).format(self.parent.get_language_display) + _(msg).format(self.parent.get_language_display()) ) exists_translation = ( self.parent.translations @@ -537,7 +537,7 @@ def clean_project(self): 'Please choose one with another language.' ) raise forms.ValidationError( - _(msg).format(self.translation.get_language_display) + _(msg).format(self.translation.get_language_display()) ) is_parent = self.translation.translations.exists() if is_parent: diff --git a/readthedocs/rtd_tests/tests/test_project_forms.py b/readthedocs/rtd_tests/tests/test_project_forms.py index 8c0bf2fd47a..db35f583153 100644 --- a/readthedocs/rtd_tests/tests/test_project_forms.py +++ b/readthedocs/rtd_tests/tests/test_project_forms.py @@ -129,7 +129,7 @@ def test_form_translation_user_cant_add_project_with_same_lang(self): ) self.assertFalse(form.is_valid()) self.assertIn( - 'Both projects have a language of "es"', + 'Both projects have a language of "Spanish"', ''.join(form.errors['project']) ) @@ -149,7 +149,7 @@ def test_form_translation_user_cant_add_project_with_same_lang_of_other_translat ) self.assertFalse(form.is_valid()) self.assertIn( - 'There is already a translation of language "en"', + 'There is already a translation of language "English"', ''.join(form.errors['project']) ) From 457ac621a371a1265bff231dd4be268124a946c4 Mon Sep 17 00:00:00 2001 From: Ajat Prabha Date: Thu, 1 Mar 2018 05:14:09 +0530 Subject: [PATCH 047/190] Fixed #3701: added closing tag for div element --- readthedocs/templates/projects/project_dashboard.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/templates/projects/project_dashboard.html b/readthedocs/templates/projects/project_dashboard.html index 82ec98a9226..d742cf7f9d4 100644 --- a/readthedocs/templates/projects/project_dashboard.html +++ b/readthedocs/templates/projects/project_dashboard.html @@ -24,7 +24,7 @@

          Thanks!

          Your support of Read the Docs helps make the site better each and every month.

          - + {% endif %} {% endblock %}} From 29674ee8922982177f9d864d8130dd3b5bc1884a Mon Sep 17 00:00:00 2001 From: David Fischer Date: Wed, 28 Feb 2018 17:04:39 -0800 Subject: [PATCH 048/190] Parent project can't already be a translation --- readthedocs/projects/forms.py | 8 ++++++++ readthedocs/rtd_tests/tests/test_project_forms.py | 7 ++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index b858b8d684c..fed480b4ced 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -509,6 +509,14 @@ def __init__(self, *args, **kwargs): def clean_project(self): translation_project_slug = self.cleaned_data['project'] + + # Ensure parent project isn't already itself a translation + if Project.objects.filter(translations__in=[self.parent]).exists(): + msg = 'Project "{}" is already a translation' + raise forms.ValidationError( + (_(msg).format(self.parent.slug)) + ) + project_translation_qs = self.get_translation_queryset().filter( slug=translation_project_slug ) diff --git a/readthedocs/rtd_tests/tests/test_project_forms.py b/readthedocs/rtd_tests/tests/test_project_forms.py index db35f583153..be250a6da5b 100644 --- a/readthedocs/rtd_tests/tests/test_project_forms.py +++ b/readthedocs/rtd_tests/tests/test_project_forms.py @@ -193,21 +193,22 @@ def test_form_translation_no_nesting_translation_case_2(self): ''.join(form.errors['project']) ) - def test_form_translation_no_circular_translations(self): + def test_not_already_translation(self): user = get(User) project_a = self.get_project(lang='es', users=[user]) project_b = self.get_project(lang='en', users=[user]) + project_c = self.get_project(lang='br', users=[user]) project_a.translations.add(project_b) project_a.save() form = TranslationForm( - {'project': project_a.slug}, + {'project': project_c.slug}, parent=project_b, user=user, ) self.assertFalse(form.is_valid()) self.assertIn( - 'This project has translations', + 'is already a translation', ''.join(form.errors['project']) ) From 5d549662cff382b4fc52ecc4fa9ef1999d2cf698 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 22:04:39 -0500 Subject: [PATCH 049/190] Show lang on choices --- readthedocs/projects/forms.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index b858b8d684c..161ecdcef83 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -502,8 +502,12 @@ def __init__(self, *args, **kwargs): self.parent = kwargs.pop('parent', None) self.user = kwargs.pop('user') super(TranslationForm, self).__init__(*args, **kwargs) - self.fields['project'].choices = [ - (project.slug, project) + self.fields['project'].choices = self.get_choices() + + def get_choices(self): + return [ + (project.slug, '{project} ({lang})'.format( + project=project.slug, lang=project.get_language_display())) for project in self.get_translation_queryset().all() ] From b277d9b39cc9dc679e16aeab0ad61c34cce2f666 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 22:21:09 -0500 Subject: [PATCH 050/190] Better error messages --- readthedocs/projects/forms.py | 10 ++++------ readthedocs/rtd_tests/tests/test_project_forms.py | 8 ++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index 161ecdcef83..0b393077669 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -524,8 +524,7 @@ def clean_project(self): self.translation = project_translation_qs.first() if self.translation.language == self.parent.language: msg = ( - 'Both projects have a language of "{}". ' - 'Please choose one with another language.' + 'Both projects can not have the same language ({}).' ) raise forms.ValidationError( _(msg).format(self.parent.get_language_display()) @@ -537,8 +536,7 @@ def clean_project(self): ) if exists_translation: msg = ( - 'There is already a translation of language "{}". ' - 'Please choose one with another language.' + 'This project already has a translation for {}.' ) raise forms.ValidationError( _(msg).format(self.translation.get_language_display()) @@ -546,8 +544,8 @@ def clean_project(self): is_parent = self.translation.translations.exists() if is_parent: msg = ( - 'This project has translations. ' - 'Please choose one without translations.' + 'A project with existing translations ' + 'can not be added as a project translation.' ) raise forms.ValidationError( _(msg).format(self.translation.language) diff --git a/readthedocs/rtd_tests/tests/test_project_forms.py b/readthedocs/rtd_tests/tests/test_project_forms.py index db35f583153..989b24a763b 100644 --- a/readthedocs/rtd_tests/tests/test_project_forms.py +++ b/readthedocs/rtd_tests/tests/test_project_forms.py @@ -129,7 +129,7 @@ def test_form_translation_user_cant_add_project_with_same_lang(self): ) self.assertFalse(form.is_valid()) self.assertIn( - 'Both projects have a language of "Spanish"', + 'Both projects can not have the same language (Spanish).', ''.join(form.errors['project']) ) @@ -149,7 +149,7 @@ def test_form_translation_user_cant_add_project_with_same_lang_of_other_translat ) self.assertFalse(form.is_valid()) self.assertIn( - 'There is already a translation of language "English"', + 'This project already has a translation for English.', ''.join(form.errors['project']) ) @@ -189,7 +189,7 @@ def test_form_translation_no_nesting_translation_case_2(self): ) self.assertFalse(form.is_valid()) self.assertIn( - 'This project has translations', + 'A project with existing translations can not', ''.join(form.errors['project']) ) @@ -208,6 +208,6 @@ def test_form_translation_no_circular_translations(self): ) self.assertFalse(form.is_valid()) self.assertIn( - 'This project has translations', + 'A project with existing translations can not', ''.join(form.errors['project']) ) From 5d3d153cc33eb8f9e87acfa64be596df8f43f460 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 22:27:10 -0500 Subject: [PATCH 051/190] Better help text --- readthedocs/templates/projects/project_translations.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/readthedocs/templates/projects/project_translations.html b/readthedocs/templates/projects/project_translations.html index 3ee191b1b1e..d3f2972f1bb 100644 --- a/readthedocs/templates/projects/project_translations.html +++ b/readthedocs/templates/projects/project_translations.html @@ -14,8 +14,7 @@ {% block project_edit_content %}

          {% blocktrans trimmed %} - This allows you to add translations to your project. - Select the project below that is a translation of your current project. + To add a translation to your project, select a project below. {% endblocktrans %}

          From 66419d2c95bc65618646f449b870979f35795996 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 22:27:28 -0500 Subject: [PATCH 052/190] Fix grammar --- readthedocs/templates/projects/project_translations.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/templates/projects/project_translations.html b/readthedocs/templates/projects/project_translations.html index d3f2972f1bb..0ccb89e2db4 100644 --- a/readthedocs/templates/projects/project_translations.html +++ b/readthedocs/templates/projects/project_translations.html @@ -21,7 +21,7 @@ {% if project.main_language_project %}

          {% blocktrans trimmed with language=project.get_language_display main_project=project.main_language_project.name %} - This project is already configured as {{ language }} translation of + This project is already configured as the {{ language }} translation of "{{ main_project }}". Nested translations are not supported. {% endblocktrans %} From 84ec88f609a9cb9400188abcca6c173470f4291b Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 28 Feb 2018 22:27:44 -0500 Subject: [PATCH 053/190] Remove p tag --- .../templates/projects/project_translations.html | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/readthedocs/templates/projects/project_translations.html b/readthedocs/templates/projects/project_translations.html index 0ccb89e2db4..a9e53c17b49 100644 --- a/readthedocs/templates/projects/project_translations.html +++ b/readthedocs/templates/projects/project_translations.html @@ -33,17 +33,15 @@ {% endblocktrans %} {% else %} -

          -

          {% trans "Choose which project you would like to add as a translation." %}

          From 902f63f596c59219fa2f959698eb2092651deff5 Mon Sep 17 00:00:00 2001 From: David Fischer Date: Wed, 28 Feb 2018 21:47:51 -0800 Subject: [PATCH 054/190] Much clearer query --- readthedocs/projects/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index fed480b4ced..7ec8fd7e69f 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -511,7 +511,7 @@ def clean_project(self): translation_project_slug = self.cleaned_data['project'] # Ensure parent project isn't already itself a translation - if Project.objects.filter(translations__in=[self.parent]).exists(): + if self.parent.main_language_project is not None: msg = 'Project "{}" is already a translation' raise forms.ValidationError( (_(msg).format(self.parent.slug)) From d0a240262e97d9a9456310b2c05f86e6f4340c74 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Thu, 1 Mar 2018 10:27:46 -0500 Subject: [PATCH 055/190] Use named formatting --- readthedocs/projects/forms.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index 0b393077669..6cdd8be00b3 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -517,17 +517,17 @@ def clean_project(self): slug=translation_project_slug ) if not project_translation_qs.exists(): - msg = 'Project "{}" does not exist.' + msg = 'Project "{project}" does not exist.' raise forms.ValidationError( - (_(msg).format(translation_project_slug)) + (_(msg).format(project=translation_project_slug)) ) self.translation = project_translation_qs.first() if self.translation.language == self.parent.language: msg = ( - 'Both projects can not have the same language ({}).' + 'Both projects can not have the same language ({lang}).' ) raise forms.ValidationError( - _(msg).format(self.parent.get_language_display()) + _(msg).format(lang=self.parent.get_language_display()) ) exists_translation = ( self.parent.translations @@ -536,10 +536,10 @@ def clean_project(self): ) if exists_translation: msg = ( - 'This project already has a translation for {}.' + 'This project already has a translation for {lang}.' ) raise forms.ValidationError( - _(msg).format(self.translation.get_language_display()) + _(msg).format(lang=self.translation.get_language_display()) ) is_parent = self.translation.translations.exists() if is_parent: @@ -547,9 +547,7 @@ def clean_project(self): 'A project with existing translations ' 'can not be added as a project translation.' ) - raise forms.ValidationError( - _(msg).format(self.translation.language) - ) + raise forms.ValidationError(_(msg)) return translation_project_slug def get_translation_queryset(self): From 4aef5023b59b2f4d8bf27e7b6faca72873074e35 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Thu, 1 Mar 2018 10:29:09 -0500 Subject: [PATCH 056/190] Use assertContains --- readthedocs/rtd_tests/tests/test_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/rtd_tests/tests/test_project.py b/readthedocs/rtd_tests/tests/test_project.py index c7d911283a5..962042a0ae7 100644 --- a/readthedocs/rtd_tests/tests/test_project.py +++ b/readthedocs/rtd_tests/tests/test_project.py @@ -148,7 +148,7 @@ def test_user_can_not_add_other_user_project_as_translation(self): data={'project': project_b.slug} ) - self.assertIn('Select a valid choice', resp.content.decode('utf-8')) + self.assertContains(resp, 'Select a valid choice') self.assertEqual(project_a.translations.count(), 0) project_b.refresh_from_db() self.assertIsNone(project_b.main_language_project) From 4b00f3ff2f1cfe89819d2dc3f0689f2fad53f4e3 Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 2 Mar 2018 10:27:12 -0700 Subject: [PATCH 057/190] Add argument to skip errorlist through knockout on common form (#3704) Update common knockout form field template to add argument to skip errorlist display through knockout observables. --- readthedocs/core/templates/core/ko_form_field.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/core/templates/core/ko_form_field.html b/readthedocs/core/templates/core/ko_form_field.html index 111545dc3aa..5402f69b9b1 100644 --- a/readthedocs/core/templates/core/ko_form_field.html +++ b/readthedocs/core/templates/core/ko_form_field.html @@ -3,7 +3,7 @@ {% else %} {{ field.errors }} - {% if 'data-bind' in field.field.widget.attrs %} + {% if not skip_errorlist and 'data-bind' in field.field.widget.attrs %}
          From f3c0c0aa33c6017951b900e540d61ef36ea71d4e Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Fri, 23 Mar 2018 14:21:39 -0500 Subject: [PATCH 126/190] Fix regex for public bitbucket repo (#3533) * Add regex for public bitbucket repositories * Simplify regex * Update tests for public repositories --- readthedocs/projects/constants.py | 4 ++-- readthedocs/rtd_tests/tests/test_repo_parsing.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/readthedocs/projects/constants.py b/readthedocs/projects/constants.py index 8837f13b086..576f613c21d 100644 --- a/readthedocs/projects/constants.py +++ b/readthedocs/projects/constants.py @@ -297,9 +297,9 @@ re.compile('github.com:(.+)/(.+)\.git$'), ] BITBUCKET_REGEXS = [ + re.compile('bitbucket.org/(.+)/(.+)\.git$'), re.compile('@bitbucket.org/(.+)/(.+)\.git$'), - re.compile('bitbucket.org/(.+)/(.+)/'), - re.compile('bitbucket.org/(.+)/(.+)'), + re.compile('bitbucket.org/(.+)/(.+)/?'), re.compile('bitbucket.org:(.+)/(.+)\.git$'), ] GITLAB_REGEXS = [ diff --git a/readthedocs/rtd_tests/tests/test_repo_parsing.py b/readthedocs/rtd_tests/tests/test_repo_parsing.py index 43231d68036..f946db61e53 100644 --- a/readthedocs/rtd_tests/tests/test_repo_parsing.py +++ b/readthedocs/rtd_tests/tests/test_repo_parsing.py @@ -87,13 +87,13 @@ def test_bitbucket(self): self.assertEqual(self.version.get_bitbucket_url(docroot='/foo/bar/', filename='file'), 'https://bitbucket.org/user/repo.gitbucket.io/src/master/foo/bar/file.rst') self.pip.repo = 'https://bitbucket.org/user/repo.git' - self.assertEqual(self.version.get_bitbucket_url(docroot='/foo/bar/', filename='file'), 'https://bitbucket.org/user/repo.git/src/master/foo/bar/file.rst') + self.assertEqual(self.version.get_bitbucket_url(docroot='/foo/bar/', filename='file'), 'https://bitbucket.org/user/repo/src/master/foo/bar/file.rst') self.pip.repo = 'https://bitbucket.org/user/repo.gitbucket.io.git' - self.assertEqual(self.version.get_bitbucket_url(docroot='/foo/bar/', filename='file'), 'https://bitbucket.org/user/repo.gitbucket.io.git/src/master/foo/bar/file.rst') + self.assertEqual(self.version.get_bitbucket_url(docroot='/foo/bar/', filename='file'), 'https://bitbucket.org/user/repo.gitbucket.io/src/master/foo/bar/file.rst') self.pip.repo = 'https://bitbucket.org/user/repo.git.git' - self.assertEqual(self.version.get_bitbucket_url(docroot='/foo/bar/', filename='file'), 'https://bitbucket.org/user/repo.git.git/src/master/foo/bar/file.rst') + self.assertEqual(self.version.get_bitbucket_url(docroot='/foo/bar/', filename='file'), 'https://bitbucket.org/user/repo.git/src/master/foo/bar/file.rst') def test_bitbucket_https(self): self.pip.repo = 'https://user@bitbucket.org/user/repo.git' From d6a51a487b879cb624673b5557d2f7f801e13af3 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Fri, 23 Mar 2018 09:08:06 -0500 Subject: [PATCH 127/190] Check submodule URLs integrity using gitpython Use the same RepositoryURLValidator class for all the submodule URLs before performing the sync/update/checkout of them. --- readthedocs/projects/exceptions.py | 4 +++ readthedocs/rtd_tests/tests/test_backend.py | 9 +++++ readthedocs/rtd_tests/utils.py | 22 +++++++++--- readthedocs/vcs_support/backends/git.py | 39 +++++++++++++++------ requirements/pip.txt | 3 +- 5 files changed, 62 insertions(+), 15 deletions(-) diff --git a/readthedocs/projects/exceptions.py b/readthedocs/projects/exceptions.py index 5376db4ad8e..6acec396812 100644 --- a/readthedocs/projects/exceptions.py +++ b/readthedocs/projects/exceptions.py @@ -39,6 +39,10 @@ class RepositoryError(BuildEnvironmentError): 'Private repositories are not supported.' ) + INVALID_SUBMODULES = _( + 'One or more submodule URLs are not valid.' + ) + def get_default_message(self): if settings.ALLOW_PRIVATE_REPOS: return self.PRIVATE_ALLOWED diff --git a/readthedocs/rtd_tests/tests/test_backend.py b/readthedocs/rtd_tests/tests/test_backend.py index 4c020b2d78a..abcd6cb44d1 100644 --- a/readthedocs/rtd_tests/tests/test_backend.py +++ b/readthedocs/rtd_tests/tests/test_backend.py @@ -4,6 +4,7 @@ from django.contrib.auth.models import User import django_dynamic_fixture as fixture +from readthedocs.projects.exceptions import RepositoryError from readthedocs.projects.models import Project, Feature from readthedocs.rtd_tests.base import RTDTestCase @@ -101,6 +102,14 @@ def test_skip_submodule_checkout(self): self.assertTrue(self.project.has_feature(Feature.SKIP_SUBMODULES)) self.assertFalse(repo.are_submodules_available()) + def test_check_submodule_urls(self): + repo = self.project.vcs_repo() + repo.checkout('submodule') + self.assertTrue(repo.are_submodules_valid()) + + with self.assertRaises(RepositoryError) as e: + repo.checkout('invalidsubmodule') + self.assertEqual(e.msg, RepositoryError.INVALID_SUBMODULES) class TestHgBackend(RTDTestCase): def setUp(self): diff --git a/readthedocs/rtd_tests/utils.py b/readthedocs/rtd_tests/utils.py index d788faa4c74..8ee73f2361f 100644 --- a/readthedocs/rtd_tests/utils.py +++ b/readthedocs/rtd_tests/utils.py @@ -4,7 +4,7 @@ import logging import subprocess -from os import chdir, environ, getcwd +from os import chdir, environ, getcwd, mkdir from os.path import abspath, join as pjoin from shutil import copytree from tempfile import mkdtemp @@ -49,11 +49,25 @@ def make_test_git(): # Set up the actual repository log.info(check_output(['git', 'add', '.'], env=env)) log.info(check_output(['git', 'commit', '-m"init"'], env=env)) - # Add repo itself as submodule - log.info(check_output(['git', 'checkout', '-b', 'submodule'], env=env)) - log.info(check_output(['git', 'submodule', 'add', '-b', 'master', './', 'submodule'], env=env)) + + # Add fake repo as submodule. We need to fake this here because local path + # URL are not allowed and using a real URL will require Internet to clone + # the repo + log.info(check_output(['git', 'checkout', '-b', 'submodule', 'master'], env=env)) + # https://stackoverflow.com/a/37378302/2187091 + mkdir(pjoin(directory, 'foobar')) + gitmodules_path = pjoin(directory, '.gitmodules') + with open(gitmodules_path, 'w') as fh: + fh.write('''[submodule "foobar"]\n\tpath = foobar\n\turl = https://foobar.com/git\n''') + log.info(check_output(['git', 'update-index', '--add', '--cacheinfo', '160000', '233febf4846d7a0aeb95b6c28962e06e21d13688', 'foobar'], env=env)) log.info(check_output(['git', 'add', '.'], env=env)) log.info(check_output(['git', 'commit', '-m"Add submodule"'], env=env)) + + # Add an invalid submodule URL in the invalidsubmodule branch + log.info(check_output(['git', 'checkout', '-b', 'invalidsubmodule', 'master'], env=env)) + log.info(check_output(['git', 'submodule', 'add', '-b', 'master', './', 'invalidsubmodule'], env=env)) + log.info(check_output(['git', 'add', '.'], env=env)) + log.info(check_output(['git', 'commit', '-m"Add invalid submodule"'], env=env)) # Checkout to master branch again log.info(check_output(['git', 'checkout', 'master'], env=env)) chdir(path) diff --git a/readthedocs/vcs_support/backends/git.py b/readthedocs/vcs_support/backends/git.py index 7e3ba4ac32c..79f0d34791a 100644 --- a/readthedocs/vcs_support/backends/git.py +++ b/readthedocs/vcs_support/backends/git.py @@ -9,8 +9,11 @@ import os import re +from django.core.exceptions import ValidationError +import git from six import PY2, StringIO +from readthedocs.core.validators import validate_repository_url from readthedocs.projects.exceptions import RepositoryError from readthedocs.vcs_support.base import BaseVCS, VCSVersion @@ -71,6 +74,16 @@ def are_submodules_available(self): code, out, _ = self.run('git', 'submodule', 'status', record=False) return code == 0 and bool(out) + def are_submodules_valid(self): + """Test that all submodule URLs are valid.""" + repo = git.Repo(self.working_dir) + for submodule in repo.submodules: + try: + validate_repository_url(submodule.url) + except ValidationError: + return False + return True + def fetch(self): code, _, _ = self.run('git', 'fetch', '--tags', '--prune') if code != 0: @@ -230,18 +243,24 @@ def checkout(self, identifier=None): # Update submodules, temporarily allow for skipping submodule checkout # step for projects need more submodule configuration. if self.are_submodules_available(): - self.run('git', 'submodule', 'sync') - self.run( - 'git', - 'submodule', - 'update', - '--init', - '--recursive', - '--force', - ) - + if self.are_submodules_valid(): + self.checkout_submodules() + else: + raise RepositoryError(RepositoryError.INVALID_SUBMODULES) return code, out, err + def checkout_submodules(self): + """Checkout all repository submodules recursively.""" + self.run('git', 'submodule', 'sync') + self.run( + 'git', + 'submodule', + 'update', + '--init', + '--recursive', + '--force', + ) + def find_ref(self, ref): # Check if ref starts with 'origin/' if ref.startswith('origin/'): diff --git a/requirements/pip.txt b/requirements/pip.txt index 1fdbdff8e5e..5031f320f5d 100644 --- a/requirements/pip.txt +++ b/requirements/pip.txt @@ -1,5 +1,5 @@ # Base packages -pip==9.0.1 +pip==9.0.3 appdirs==1.4.3 virtualenv==15.1.0 docutils==0.14 @@ -47,6 +47,7 @@ dnspython==1.15.0 # VCS httplib2==0.10.3 +gitpython==2.1.8 # Search elasticsearch==1.5.0 From 7b8efe3309306a80d00798a737a862de404d7c50 Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Sat, 24 Mar 2018 02:14:23 -0500 Subject: [PATCH 128/190] Fix linting issues (#3838) * Fix linting issues * Small lint fix --- readthedocs/core/validators.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readthedocs/core/validators.py b/readthedocs/core/validators.py index f5afb676cc7..3117119841a 100644 --- a/readthedocs/core/validators.py +++ b/readthedocs/core/validators.py @@ -61,14 +61,14 @@ def __call__(self, value): valid_schemes += private_schemes url = urlparse(value) if ( - ( - url.scheme not in valid_schemes and \ - '@' not in value and \ + ( # pylint: disable=too-many-boolean-expressions + url.scheme not in valid_schemes and + '@' not in value and not value.startswith('lp:') - ) or \ + ) or ( - value.startswith('/') or \ - value.startswith('file://') or \ + value.startswith('/') or + value.startswith('file://') or value.startswith('.') ) ): From 267583935f3ba6a83d8f5c9f685c2c79164afbd2 Mon Sep 17 00:00:00 2001 From: ze Date: Sat, 24 Mar 2018 22:39:41 -0400 Subject: [PATCH 129/190] Update quickstart from README --- README.rst | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index 0f994c27b4c..224078424ca 100644 --- a/README.rst +++ b/README.rst @@ -42,19 +42,15 @@ when you push to GitHub. #. Create an account on `Read the Docs`_. You will get an email verifying your email address which you should accept within 7 days. -#. Log in and click on "Import". +#. Log in and click on "Import a Project". -#. Give your project a name, add the HTTPS link for your GitHub project, and - select Git as your repository type. +#. Click "Connect to GitHub" in order to connect your account's repositories to GitHub. -#. Fill in the rest of the form as needed and click "Create". +#. When prompted on GitHub, give access to your account. -#. On GitHub, navigate to your repository and click on "Settings". +#. Click "Import a Repository" and select any desired repository. -#. In the sidebar, click on "Web Hooks & Services", then find and click on the - "ReadTheDocs" service. - -#. Check the "Active" setting and click "Update Settings". +#. Change any information if desired and click "Next". #. All done. Commit away and your project will auto-update. From 6d32b25920a067cb2f562374b8521adb836b7a82 Mon Sep 17 00:00:00 2001 From: David Fischer Date: Mon, 26 Mar 2018 10:54:02 -0700 Subject: [PATCH 130/190] Fix linting errors in tests --- readthedocs/rtd_tests/utils.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/readthedocs/rtd_tests/utils.py b/readthedocs/rtd_tests/utils.py index 8ee73f2361f..c227778c180 100644 --- a/readthedocs/rtd_tests/utils.py +++ b/readthedocs/rtd_tests/utils.py @@ -59,13 +59,22 @@ def make_test_git(): gitmodules_path = pjoin(directory, '.gitmodules') with open(gitmodules_path, 'w') as fh: fh.write('''[submodule "foobar"]\n\tpath = foobar\n\turl = https://foobar.com/git\n''') - log.info(check_output(['git', 'update-index', '--add', '--cacheinfo', '160000', '233febf4846d7a0aeb95b6c28962e06e21d13688', 'foobar'], env=env)) + log.info(check_output( + [ + 'git', 'update-index', '--add', '--cacheinfo', '160000', + '233febf4846d7a0aeb95b6c28962e06e21d13688', 'foobar', + ], + env=env, + )) log.info(check_output(['git', 'add', '.'], env=env)) log.info(check_output(['git', 'commit', '-m"Add submodule"'], env=env)) # Add an invalid submodule URL in the invalidsubmodule branch log.info(check_output(['git', 'checkout', '-b', 'invalidsubmodule', 'master'], env=env)) - log.info(check_output(['git', 'submodule', 'add', '-b', 'master', './', 'invalidsubmodule'], env=env)) + log.info(check_output( + ['git', 'submodule', 'add', '-b', 'master', './', 'invalidsubmodule'], + env=env, + )) log.info(check_output(['git', 'add', '.'], env=env)) log.info(check_output(['git', 'commit', '-m"Add invalid submodule"'], env=env)) # Checkout to master branch again From 00639f6d880039b7df18669d4cbd030459c8f363 Mon Sep 17 00:00:00 2001 From: Tahzib Mashrik Date: Fri, 26 Jan 2018 02:21:04 +0600 Subject: [PATCH 131/190] [#2967] Scheduled tasks for cleaning up messages --- readthedocs/core/tasks.py | 10 ++++++++++ readthedocs/core/utils/__init__.py | 3 ++- readthedocs/settings/base.py | 10 ++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/readthedocs/core/tasks.py b/readthedocs/core/tasks.py index 53c16d8f982..8ed81f1bb1e 100644 --- a/readthedocs/core/tasks.py +++ b/readthedocs/core/tasks.py @@ -7,6 +7,8 @@ from django.core.mail import EmailMultiAlternatives from django.template.loader import get_template from django.template import TemplateDoesNotExist +from django.utils import timezone +from messages_extends.models import Message as PersistentMessage from readthedocs.worker import app @@ -54,3 +56,11 @@ def send_email_task(recipient, subject, template, template_html, pass msg.send() log.info('Sent email to recipient: %s', recipient) + + +@app.task(queue='web') +def clear_persistent_messages(): + # Delete all expired message_extend's messages + log.info("Deleting all expired message_extend's messages") + expired_messages = PersistentMessage.objects.filter(expires__lt=timezone.now()) + expired_messages.delete() diff --git a/readthedocs/core/utils/__init__.py b/readthedocs/core/utils/__init__.py index e2f4df11a2f..196131992d9 100644 --- a/readthedocs/core/utils/__init__.py +++ b/readthedocs/core/utils/__init__.py @@ -16,7 +16,6 @@ from future.backports.urllib.parse import urlparse from celery import group, chord -from ..tasks import send_email_task from readthedocs.builds.constants import LATEST from readthedocs.doc_builder.constants import DOCKER_LIMITS @@ -144,6 +143,8 @@ def send_email(recipient, subject, template, template_html, context=None, Task :py:func:`readthedocs.core.tasks.send_email_task` Task that handles templating and sending email message """ + from ..tasks import send_email_task + if context is None: context = {} context['uri'] = '{scheme}://{host}'.format( diff --git a/readthedocs/settings/base.py b/readthedocs/settings/base.py index e0c1b933d84..ce75090b1bd 100644 --- a/readthedocs/settings/base.py +++ b/readthedocs/settings/base.py @@ -6,6 +6,8 @@ import os +from celery.schedules import crontab + from readthedocs.core.settings import Settings from celery.schedules import crontab @@ -258,6 +260,14 @@ def USE_PROMOS(self): # noqa }, } + CELERYBEAT_SCHEDULE = { + 'weekly-clear-persistent-messages': { + 'task': 'readthedocs.core.tasks.clear_persistent_messages', + 'schedule': crontab(hour=23, minute=59, day_of_week=7), + 'options': {'queue': 'web'}, + }, + } + # Docker DOCKER_ENABLE = False DOCKER_IMAGE = 'readthedocs/build:2.0' From 588b1520bcd29e855cb746a4963b25d2e587f6a7 Mon Sep 17 00:00:00 2001 From: tm Date: Thu, 1 Mar 2018 18:44:05 +0600 Subject: [PATCH 132/190] set day of week for crontab --- readthedocs/settings/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/settings/base.py b/readthedocs/settings/base.py index ce75090b1bd..cdce54df93a 100644 --- a/readthedocs/settings/base.py +++ b/readthedocs/settings/base.py @@ -263,7 +263,7 @@ def USE_PROMOS(self): # noqa CELERYBEAT_SCHEDULE = { 'weekly-clear-persistent-messages': { 'task': 'readthedocs.core.tasks.clear_persistent_messages', - 'schedule': crontab(hour=23, minute=59, day_of_week=7), + 'schedule': crontab(hour=23, minute=59, day_of_week=6), 'options': {'queue': 'web'}, }, } From bf88c3930cc41a5e3648dd6fd29d5682ef0615e9 Mon Sep 17 00:00:00 2001 From: Tahzib Mashrik Date: Mon, 19 Mar 2018 00:25:52 +0600 Subject: [PATCH 133/190] make clear persistent message every three hours --- readthedocs/settings/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readthedocs/settings/base.py b/readthedocs/settings/base.py index cdce54df93a..bef73ab92f8 100644 --- a/readthedocs/settings/base.py +++ b/readthedocs/settings/base.py @@ -261,9 +261,9 @@ def USE_PROMOS(self): # noqa } CELERYBEAT_SCHEDULE = { - 'weekly-clear-persistent-messages': { + 'every-three-hour-clear-persistent-messages': { 'task': 'readthedocs.core.tasks.clear_persistent_messages', - 'schedule': crontab(hour=23, minute=59, day_of_week=6), + 'schedule': crontab(minute=0, hour='*/3'), 'options': {'queue': 'web'}, }, } From b3a133017a05bb4d68eb00905e9ffa188d8b2e77 Mon Sep 17 00:00:00 2001 From: Tahzib Mashrik Date: Sat, 24 Mar 2018 18:15:53 +0600 Subject: [PATCH 134/190] rebase and other fix --- readthedocs/settings/base.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/readthedocs/settings/base.py b/readthedocs/settings/base.py index bef73ab92f8..7fa70762451 100644 --- a/readthedocs/settings/base.py +++ b/readthedocs/settings/base.py @@ -258,9 +258,6 @@ def USE_PROMOS(self): # noqa 'schedule': crontab(minute='*/15'), 'options': {'queue': 'web'}, }, - } - - CELERYBEAT_SCHEDULE = { 'every-three-hour-clear-persistent-messages': { 'task': 'readthedocs.core.tasks.clear_persistent_messages', 'schedule': crontab(minute=0, hour='*/3'), From 235febffe97606ed9faa4e8f5e834dc034b633a5 Mon Sep 17 00:00:00 2001 From: Tahzib Mashrik Date: Sat, 24 Mar 2018 19:58:21 +0600 Subject: [PATCH 135/190] bug fix --- readthedocs/settings/base.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/readthedocs/settings/base.py b/readthedocs/settings/base.py index 7fa70762451..88c3fbb4512 100644 --- a/readthedocs/settings/base.py +++ b/readthedocs/settings/base.py @@ -10,8 +10,6 @@ from readthedocs.core.settings import Settings -from celery.schedules import crontab - try: import readthedocsext # noqa From bc6331ba4dd8a39803e22f45db18369fffd3ae17 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Sat, 10 Feb 2018 20:09:23 -0500 Subject: [PATCH 136/190] Show URLS for exact redirect Fix #2431 --- readthedocs/redirects/models.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/readthedocs/redirects/models.py b/readthedocs/redirects/models.py index ceefb2b833a..10159e86261 100644 --- a/readthedocs/redirects/models.py +++ b/readthedocs/redirects/models.py @@ -78,13 +78,29 @@ class Meta(object): ordering = ('-update_dt',) def __str__(self): + redirect_text = '{type}: {from_url} -> {to_url}' if self.redirect_type == 'prefix': - return ugettext('Prefix Redirect:') + ' %s ->' % self.from_url + return redirect_text.format( + type=ugettext('Prefix Redirect'), + from_url=self.from_url, + to_url='' + ) elif self.redirect_type == 'page': - return ugettext('Page Redirect:') + ' %s -> %s' % ( - self.from_url, - self.to_url) - return ugettext('Redirect: %s' % self.get_redirect_type_display()) + return redirect_text.format( + type=ugettext('Page Redirect'), + from_url=self.from_url, + to_url=self.to_url + ) + elif self.redirect_type == 'exact': + return redirect_text.format( + type=ugettext('Exact Redirect'), + from_url=self.from_url, + to_url=self.to_url + ) + else: + return ugettext('Redirect: {}'.format( + self.get_redirect_type_display()) + ) def get_full_path(self, filename, language=None, version_slug=None): """ From b0056cf0800de31dfd89301b8d84ad8d67163739 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Sat, 10 Feb 2018 20:21:35 -0500 Subject: [PATCH 137/190] Linter --- readthedocs/redirects/models.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/readthedocs/redirects/models.py b/readthedocs/redirects/models.py index 10159e86261..a3158a2b467 100644 --- a/readthedocs/redirects/models.py +++ b/readthedocs/redirects/models.py @@ -97,10 +97,9 @@ def __str__(self): from_url=self.from_url, to_url=self.to_url ) - else: - return ugettext('Redirect: {}'.format( - self.get_redirect_type_display()) - ) + return ugettext('Redirect: {}'.format( + self.get_redirect_type_display()) + ) def get_full_path(self, filename, language=None, version_slug=None): """ From ae80fe9f6d7f4cd1944ec00c649e524459eb808e Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Thu, 15 Feb 2018 16:17:35 -0500 Subject: [PATCH 138/190] Add to_url for prefix redirect --- readthedocs/redirects/models.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readthedocs/redirects/models.py b/readthedocs/redirects/models.py index a3158a2b467..eb8244bdce5 100644 --- a/readthedocs/redirects/models.py +++ b/readthedocs/redirects/models.py @@ -83,7 +83,10 @@ def __str__(self): return redirect_text.format( type=ugettext('Prefix Redirect'), from_url=self.from_url, - to_url='' + to_url='{lang}/{version}/'.format( + lang=self.project.language, + version=self.project.default_version + ) ) elif self.redirect_type == 'page': return redirect_text.format( From 0e3f18ed399ea6c4fbf5b4fb4dc5f389e12d8126 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Thu, 15 Feb 2018 16:19:33 -0500 Subject: [PATCH 139/190] Add trailing / --- readthedocs/redirects/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/redirects/models.py b/readthedocs/redirects/models.py index eb8244bdce5..aab43c61c0d 100644 --- a/readthedocs/redirects/models.py +++ b/readthedocs/redirects/models.py @@ -83,7 +83,7 @@ def __str__(self): return redirect_text.format( type=ugettext('Prefix Redirect'), from_url=self.from_url, - to_url='{lang}/{version}/'.format( + to_url='/{lang}/{version}/'.format( lang=self.project.language, version=self.project.default_version ) From a0790e446ab4bf82689ff973f7506a0bde7afe90 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Mon, 26 Mar 2018 14:02:13 -0500 Subject: [PATCH 140/190] Show redirects on separate lines --- readthedocs/redirects/models.py | 39 +++++++++---------- .../templates/projects/project_redirects.html | 11 ++++-- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/readthedocs/redirects/models.py b/readthedocs/redirects/models.py index aab43c61c0d..f0b3558f8c7 100644 --- a/readthedocs/redirects/models.py +++ b/readthedocs/redirects/models.py @@ -78,32 +78,31 @@ class Meta(object): ordering = ('-update_dt',) def __str__(self): - redirect_text = '{type}: {from_url} -> {to_url}' - if self.redirect_type == 'prefix': + redirect_text = '{type}: {from_to_url}' + if self.redirect_type in ['prefix', 'page', 'exact']: return redirect_text.format( - type=ugettext('Prefix Redirect'), - from_url=self.from_url, - to_url='/{lang}/{version}/'.format( - lang=self.project.language, - version=self.project.default_version - ) - ) - elif self.redirect_type == 'page': - return redirect_text.format( - type=ugettext('Page Redirect'), - from_url=self.from_url, - to_url=self.to_url - ) - elif self.redirect_type == 'exact': - return redirect_text.format( - type=ugettext('Exact Redirect'), - from_url=self.from_url, - to_url=self.to_url + type=self.get_redirect_type_display(), + from_to_url=self.get_from_to_url_display() ) return ugettext('Redirect: {}'.format( self.get_redirect_type_display()) ) + def get_from_to_url_display(self): + if self.redirect_type in ['prefix', 'page', 'exact']: + from_url = self.from_url + to_url = self.to_url + if self.redirect_type == 'prefix': + to_url = '/{lang}/{version}/'.format( + lang=self.project.language, + version=self.project.default_version + ) + return '{from_url} -> {to_url}'.format( + from_url=from_url, + to_url=to_url + ) + return '' + def get_full_path(self, filename, language=None, version_slug=None): """ Return a full path for a given filename. diff --git a/readthedocs/templates/projects/project_redirects.html b/readthedocs/templates/projects/project_redirects.html index eb3ac75d191..553cbced00d 100644 --- a/readthedocs/templates/projects/project_redirects.html +++ b/readthedocs/templates/projects/project_redirects.html @@ -82,9 +82,14 @@

          {% trans "Redirects" %}

          "),t(".wy-menu-vertical ul").not(".simple").siblings("a").each(function(){var r=t(this);expand=t(''),expand.on("click",function(t){return e.toggleCurrent(r),t.stopPropagation(),!1}),r.prepend(expand)})},t.reset=function(){var t=encodeURI(window.location.hash);if(t)try{var e=$(".wy-menu-vertical").find('[href="'+t+'"]');if(0===e.length){var r=$('.document a[href="'+t+'"]'),i=r.closest("div.section");e=$(".wy-menu-vertical").find('[href="#'+i.attr("id")+'"]')}$(".wy-menu-vertical li.toctree-l1 li.current").removeClass("current"),e.closest("li.toctree-l2").addClass("current"),e.closest("li.toctree-l3").addClass("current"),e.closest("li.toctree-l4").addClass("current")}catch(n){console.log("Error expanding nav for anchor",n)}},t.onScroll=function(){this.winScroll=!1;var t=this.win.scrollTop(),e=t+this.winHeight,r=this.navBar.scrollTop(),i=r+(t-this.winPosition);t<0||e>this.docHeight||(this.navBar.scrollTop(i),this.winPosition=t)},t.onResize=function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},t.hashChange=function(){this.linkScroll=!0,this.win.one("hashchange",function(){this.linkScroll=!1})},t.toggleCurrent=function(t){var e=t.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")},t}var n="undefined"!=typeof window?window.jQuery:t("jquery");e.exports.ThemeNav=i(),"undefined"!=typeof window&&(window.SphinxRtdTheme={StickyNav:e.exports.ThemeNav})},{jquery:"jquery"}],2:[function(t,e,r){function i(){return{a:["target","href","title"],abbr:["title"],address:[],area:["shape","coords","href","alt"],article:[],aside:[],audio:["autoplay","controls","loop","preload","src"],b:[],bdi:["dir"],bdo:["dir"],big:[],blockquote:["cite"],br:[],caption:[],center:[],cite:[],code:[],col:["align","valign","span","width"],colgroup:["align","valign","span","width"],dd:[],del:["datetime"],details:["open"],div:[],dl:[],dt:[],em:[],font:["color","size","face"],footer:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],header:[],hr:[],i:[],img:["src","alt","title","width","height"],ins:["datetime"],li:[],mark:[],nav:[],ol:[],p:[],pre:[],s:[],section:[],small:[],span:[],sub:[],sup:[],strong:[],table:["width","border","align","valign"],tbody:["align","valign"],td:["width","rowspan","colspan","align","valign"],tfoot:["align","valign"],th:["width","rowspan","colspan","align","valign"],thead:["align","valign"],tr:["rowspan","align","valign"],tt:[],u:[],ul:[],video:["autoplay","controls","loop","preload","src","height","width"]}}function n(t,e,r){}function o(t,e,r){}function a(t,e,r){}function s(t,e,r){}function l(t){return t.replace(E,"<").replace(S,">")}function c(t,e,r,i){if(r=g(r),"href"===e||"src"===e){if(r=T.trim(r),"#"===r)return"#";if("http://"!==r.substr(0,7)&&"https://"!==r.substr(0,8)&&"mailto:"!==r.substr(0,7)&&"#"!==r[0]&&"/"!==r[0])return""}else if("background"===e){if($.lastIndex=0,$.test(r))return""}else if("style"===e){if(I.lastIndex=0,I.test(r))return"";if(H.lastIndex=0,H.test(r)&&($.lastIndex=0,$.test(r)))return"";i!==!1&&(i=i||k,r=i.process(r))}return r=m(r)}function u(t){return t.replace(A,""")}function d(t){return t.replace(C,'"')}function f(t){return t.replace(R,function(t,e){return"x"===e[0]||"X"===e[0]?String.fromCharCode(parseInt(e.substr(1),16)):String.fromCharCode(parseInt(e,10))})}function p(t){return t.replace(O,":").replace(j," ")}function h(t){for(var e="",r=0,i=t.length;r/g,A=/"/g,C=/"/g,R=/&#([a-zA-Z0-9]*);?/gim,O=/:?/gim,j=/&newline;?/gim,$=/((j\s*a\s*v\s*a|v\s*b|l\s*i\s*v\s*e)\s*s\s*c\s*r\s*i\s*p\s*t\s*|m\s*o\s*c\s*h\s*a)\:/gi,I=/e\s*x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n\s*\(.*/gi,H=/u\s*r\s*l\s*\(.*/gi,L=//g;r.whiteList=i(),r.getDefaultWhiteList=i,r.onTag=n,r.onIgnoreTag=o,r.onTagAttr=a,r.onIgnoreTagAttr=s,r.safeAttrValue=c,r.escapeHtml=l,r.escapeQuote=u,r.unescapeQuote=d,r.escapeHtmlEntities=f,r.escapeDangerHtml5Entities=p,r.clearNonPrintableCharacter=h,r.friendlyAttrValue=g,r.escapeAttrValue=m,r.onIgnoreTagStripAll=v,r.StripTagBody=b,r.stripCommentTag=w,r.stripBlankChar=y,r.cssFilter=k,r.getDefaultCSSWhiteList=_},{"./util":5,cssfilter:9}],3:[function(t,e,r){function i(t,e){var r=new a(e);return r.process(t)}var n=t("./default"),o=t("./parser"),a=t("./xss");r=e.exports=i,r.FilterXSS=a;for(var s in n)r[s]=n[s];for(var s in o)r[s]=o[s];"undefined"!=typeof window&&(window.filterXSS=e.exports)},{"./default":2,"./parser":4,"./xss":6}],4:[function(t,e,r){function i(t){var e=t.indexOf(" ");if(e===-1)var r=t.slice(1,-1);else var r=t.slice(1,e+1);return r=d.trim(r).toLowerCase(),"/"===r.slice(0,1)&&(r=r.slice(1)),"/"===r.slice(-1)&&(r=r.slice(0,-1)),r}function n(t){return""===p){o+=r(t.slice(a,s)),d=t.slice(s,c+1),f=i(d),o+=e(s,o.length,f,d,n(d)),a=c+1,s=!1;continue}if(('"'===p||"'"===p)&&"="===t.charAt(c-1)){l=p;continue}}else if(p===l){l=!1;continue}}return a0;e--){var r=t[e];if(" "!==r)return"="===r?e:-1}}function c(t){return'"'===t[0]&&'"'===t[t.length-1]||"'"===t[0]&&"'"===t[t.length-1]}function u(t){return c(t)?t.substr(1,t.length-2):t}var d=t("./util"),f=/[^a-zA-Z0-9_:\.\-]/gim;r.parseTag=o,r.parseAttr=a},{"./util":5}],5:[function(t,e,r){e.exports={indexOf:function(t,e){var r,i;if(Array.prototype.indexOf)return t.indexOf(e);for(r=0,i=t.length;r";var w=n(l),y=o[r],x=d(w.html,function(t,e){var n=f.indexOf(y,t)!==-1,o=c(r,t,e,n);if(!i(o))return o;if(n)return e=h(r,t,e,m),e?t+'="'+e+'"':t;var o=p(r,t,e,n);return i(o)?void 0:o}),l="<"+r;return x&&(l+=" "+x),w.closing&&(l+=" /"),l+=">"}var b=s(r,l,v);return i(b)?g(l):b},g);return v&&(b=v.remove(b)),b},e.exports=a},{"./default":2,"./parser":4,"./util":5,cssfilter:9}],7:[function(t,e,r){function i(t){return void 0===t||null===t}function n(t){t=t||{},t.whiteList=t.whiteList||o.whiteList,t.onAttr=t.onAttr||o.onAttr,t.onIgnoreAttr=t.onIgnoreAttr||o.onIgnoreAttr,this.options=t}var o=t("./default"),a=t("./parser");t("./util");n.prototype.process=function(t){if(t=t||"",t=t.toString(),!t)return"";var e=this,r=e.options,n=r.whiteList,o=r.onAttr,s=r.onIgnoreAttr,l=a(t,function(t,e,r,a,l){var c=n[r],u=!1;c===!0?u=c:"function"==typeof c?u=c(a):c instanceof RegExp&&(u=c.test(a)),u!==!0&&(u=!1);var d={position:e,sourcePosition:t,source:l,isWhite:u};if(u){var f=o(r,a,d);return i(f)?r+":"+a:f}var f=s(r,a,d);if(!i(f))return f});return l},e.exports=n},{"./default":8,"./parser":10,"./util":11}],8:[function(t,e,r){function i(){var t={};return t["align-content"]=!1,t["align-items"]=!1,t["align-self"]=!1,t["alignment-adjust"]=!1,t["alignment-baseline"]=!1,t.all=!1,t["anchor-point"]=!1,t.animation=!1,t["animation-delay"]=!1,t["animation-direction"]=!1,t["animation-duration"]=!1,t["animation-fill-mode"]=!1,t["animation-iteration-count"]=!1,t["animation-name"]=!1,t["animation-play-state"]=!1,t["animation-timing-function"]=!1,t.azimuth=!1,t["backface-visibility"]=!1,t.background=!0,t["background-attachment"]=!0,t["background-clip"]=!0,t["background-color"]=!0,t["background-image"]=!0,t["background-origin"]=!0,t["background-position"]=!0,t["background-repeat"]=!0,t["background-size"]=!0,t["baseline-shift"]=!1,t.binding=!1,t.bleed=!1,t["bookmark-label"]=!1,t["bookmark-level"]=!1,t["bookmark-state"]=!1,t.border=!0,t["border-bottom"]=!0,t["border-bottom-color"]=!0,t["border-bottom-left-radius"]=!0,t["border-bottom-right-radius"]=!0,t["border-bottom-style"]=!0,t["border-bottom-width"]=!0,t["border-collapse"]=!0,t["border-color"]=!0,t["border-image"]=!0,t["border-image-outset"]=!0,t["border-image-repeat"]=!0,t["border-image-slice"]=!0,t["border-image-source"]=!0,t["border-image-width"]=!0,t["border-left"]=!0,t["border-left-color"]=!0,t["border-left-style"]=!0,t["border-left-width"]=!0,t["border-radius"]=!0,t["border-right"]=!0,t["border-right-color"]=!0,t["border-right-style"]=!0,t["border-right-width"]=!0,t["border-spacing"]=!0,t["border-style"]=!0,t["border-top"]=!0,t["border-top-color"]=!0,t["border-top-left-radius"]=!0,t["border-top-right-radius"]=!0,t["border-top-style"]=!0,t["border-top-width"]=!0,t["border-width"]=!0,t.bottom=!1,t["box-decoration-break"]=!0,t["box-shadow"]=!0,t["box-sizing"]=!0,t["box-snap"]=!0,t["box-suppress"]=!0,t["break-after"]=!0,t["break-before"]=!0,t["break-inside"]=!0,t["caption-side"]=!1,t.chains=!1,t.clear=!0,t.clip=!1,t["clip-path"]=!1,t["clip-rule"]=!1,t.color=!0,t["color-interpolation-filters"]=!0,t["column-count"]=!1,t["column-fill"]=!1,t["column-gap"]=!1,t["column-rule"]=!1,t["column-rule-color"]=!1,t["column-rule-style"]=!1,t["column-rule-width"]=!1,t["column-span"]=!1,t["column-width"]=!1,t.columns=!1,t.contain=!1,t.content=!1,t["counter-increment"]=!1,t["counter-reset"]=!1,t["counter-set"]=!1,t.crop=!1,t.cue=!1,t["cue-after"]=!1,t["cue-before"]=!1,t.cursor=!1,t.direction=!1,t.display=!0,t["display-inside"]=!0,t["display-list"]=!0,t["display-outside"]=!0,t["dominant-baseline"]=!1,t.elevation=!1,t["empty-cells"]=!1,t.filter=!1,t.flex=!1,t["flex-basis"]=!1,t["flex-direction"]=!1,t["flex-flow"]=!1,t["flex-grow"]=!1,t["flex-shrink"]=!1,t["flex-wrap"]=!1,t["float"]=!1,t["float-offset"]=!1,t["flood-color"]=!1,t["flood-opacity"]=!1,t["flow-from"]=!1,t["flow-into"]=!1,t.font=!0,t["font-family"]=!0,t["font-feature-settings"]=!0,t["font-kerning"]=!0,t["font-language-override"]=!0,t["font-size"]=!0,t["font-size-adjust"]=!0,t["font-stretch"]=!0,t["font-style"]=!0,t["font-synthesis"]=!0,t["font-variant"]=!0,t["font-variant-alternates"]=!0,t["font-variant-caps"]=!0,t["font-variant-east-asian"]=!0,t["font-variant-ligatures"]=!0,t["font-variant-numeric"]=!0,t["font-variant-position"]=!0,t["font-weight"]=!0,t.grid=!1,t["grid-area"]=!1,t["grid-auto-columns"]=!1,t["grid-auto-flow"]=!1,t["grid-auto-rows"]=!1,t["grid-column"]=!1,t["grid-column-end"]=!1,t["grid-column-start"]=!1,t["grid-row"]=!1,t["grid-row-end"]=!1,t["grid-row-start"]=!1,t["grid-template"]=!1,t["grid-template-areas"]=!1,t["grid-template-columns"]=!1,t["grid-template-rows"]=!1,t["hanging-punctuation"]=!1,t.height=!0,t.hyphens=!1,t.icon=!1,t["image-orientation"]=!1,t["image-resolution"]=!1,t["ime-mode"]=!1,t["initial-letters"]=!1,t["inline-box-align"]=!1,t["justify-content"]=!1,t["justify-items"]=!1,t["justify-self"]=!1,t.left=!1,t["letter-spacing"]=!0,t["lighting-color"]=!0,t["line-box-contain"]=!1,t["line-break"]=!1,t["line-grid"]=!1,t["line-height"]=!1,t["line-snap"]=!1,t["line-stacking"]=!1,t["line-stacking-ruby"]=!1,t["line-stacking-shift"]=!1,t["line-stacking-strategy"]=!1,t["list-style"]=!0,t["list-style-image"]=!0,t["list-style-position"]=!0,t["list-style-type"]=!0,t.margin=!0,t["margin-bottom"]=!0,t["margin-left"]=!0,t["margin-right"]=!0,t["margin-top"]=!0,t["marker-offset"]=!1,t["marker-side"]=!1,t.marks=!1,t.mask=!1,t["mask-box"]=!1,t["mask-box-outset"]=!1,t["mask-box-repeat"]=!1,t["mask-box-slice"]=!1,t["mask-box-source"]=!1,t["mask-box-width"]=!1,t["mask-clip"]=!1,t["mask-image"]=!1,t["mask-origin"]=!1,t["mask-position"]=!1,t["mask-repeat"]=!1,t["mask-size"]=!1,t["mask-source-type"]=!1,t["mask-type"]=!1,t["max-height"]=!0,t["max-lines"]=!1,t["max-width"]=!0,t["min-height"]=!0,t["min-width"]=!0,t["move-to"]=!1,t["nav-down"]=!1,t["nav-index"]=!1,t["nav-left"]=!1,t["nav-right"]=!1,t["nav-up"]=!1,t["object-fit"]=!1,t["object-position"]=!1,t.opacity=!1,t.order=!1,t.orphans=!1,t.outline=!1,t["outline-color"]=!1,t["outline-offset"]=!1,t["outline-style"]=!1,t["outline-width"]=!1,t.overflow=!1,t["overflow-wrap"]=!1,t["overflow-x"]=!1,t["overflow-y"]=!1,t.padding=!0,t["padding-bottom"]=!0,t["padding-left"]=!0,t["padding-right"]=!0,t["padding-top"]=!0,t.page=!1,t["page-break-after"]=!1,t["page-break-before"]=!1,t["page-break-inside"]=!1,t["page-policy"]=!1,t.pause=!1,t["pause-after"]=!1,t["pause-before"]=!1,t.perspective=!1,t["perspective-origin"]=!1,t.pitch=!1,t["pitch-range"]=!1,t["play-during"]=!1,t.position=!1,t["presentation-level"]=!1,t.quotes=!1,t["region-fragment"]=!1,t.resize=!1,t.rest=!1,t["rest-after"]=!1,t["rest-before"]=!1,t.richness=!1,t.right=!1,t.rotation=!1,t["rotation-point"]=!1,t["ruby-align"]=!1,t["ruby-merge"]=!1,t["ruby-position"]=!1,t["shape-image-threshold"]=!1,t["shape-outside"]=!1,t["shape-margin"]=!1,t.size=!1,t.speak=!1,t["speak-as"]=!1,t["speak-header"]=!1,t["speak-numeral"]=!1,t["speak-punctuation"]=!1,t["speech-rate"]=!1,t.stress=!1,t["string-set"]=!1,t["tab-size"]=!1,t["table-layout"]=!1,t["text-align"]=!0,t["text-align-last"]=!0,t["text-combine-upright"]=!0,t["text-decoration"]=!0,t["text-decoration-color"]=!0,t["text-decoration-line"]=!0,t["text-decoration-skip"]=!0,t["text-decoration-style"]=!0,t["text-emphasis"]=!0,t["text-emphasis-color"]=!0,t["text-emphasis-position"]=!0,t["text-emphasis-style"]=!0,t["text-height"]=!0,t["text-indent"]=!0,t["text-justify"]=!0,t["text-orientation"]=!0,t["text-overflow"]=!0,t["text-shadow"]=!0,t["text-space-collapse"]=!0,t["text-transform"]=!0,t["text-underline-position"]=!0,t["text-wrap"]=!0,t.top=!1,t.transform=!1,t["transform-origin"]=!1,t["transform-style"]=!1,t.transition=!1,t["transition-delay"]=!1,t["transition-duration"]=!1,t["transition-property"]=!1,t["transition-timing-function"]=!1,t["unicode-bidi"]=!1,t["vertical-align"]=!1,t.visibility=!1,t["voice-balance"]=!1,t["voice-duration"]=!1,t["voice-family"]=!1,t["voice-pitch"]=!1,t["voice-range"]=!1,t["voice-rate"]=!1,t["voice-stress"]=!1,t["voice-volume"]=!1,t.volume=!1,t["white-space"]=!1,t.widows=!1,t.width=!0,t["will-change"]=!1,t["word-break"]=!0,t["word-spacing"]=!0,t["word-wrap"]=!0,t["wrap-flow"]=!1,t["wrap-through"]=!1,t["writing-mode"]=!1,t["z-index"]=!1,t}function n(t,e,r){}function o(t,e,r){}r.whiteList=i(),r.getDefaultWhiteList=i,r.onAttr=n,r.onIgnoreAttr=o},{}],9:[function(t,e,r){function i(t,e){var r=new o(e);return r.process(t)}var n=t("./default"),o=t("./css");r=e.exports=i,r.FilterCSS=o;for(var a in n)r[a]=n[a];"undefined"!=typeof window&&(window.filterCSS=e.exports)},{"./css":7,"./default":8}],10:[function(t,e,r){function i(t,e){function r(){if(!o){var r=n.trim(t.slice(a,s)),i=r.indexOf(":");if(i!==-1){var c=n.trim(r.slice(0,i)),u=n.trim(r.slice(i+1));if(c){var d=e(a,l.length,c,u,r);d&&(l+=d+"; ")}}}a=s+1}t=n.trimRight(t),";"!==t[t.length-1]&&(t+=";");for(var i=t.length,o=!1,a=0,s=0,l="";s-1},is_sphinx_builder:function(){return!("builder"in this)||"mkdocs"!==this.builder},get_theme_name:function(){return this.theme!==n.THEME_RTD&&1===$("div.rst-other-versions").length?n.THEME_RTD:this.theme},show_promo:function(){return"https://readthedocs.com"!==this.api_host&&this.is_sphinx_builder()&&this.theme_supports_promo()}};e.exports={get:i}},{"./constants":12}],15:[function(t,e,r){function i(t){var e=t.project,r=t.version,i=t.language||"en",n=t.api_host,o=function(t){var o=$.Deferred(),s=document.createElement("a");s.href=n,s.pathname="/api/v2/docsearch/",s.search="?q="+$.urlencode(t)+"&project="+e+"&version="+r+"&language="+i,o.then(function(r){var i=r.hits||{},n=i.hits||[];if(n.length)for(var o in n){var s=n[o],l=s.fields||{},c=$('
        • '),u=document.createElement("a"),d=s.highlight;if(u.href+=l.link+DOCUMENTATION_OPTIONS.FILE_SUFFIX,u.search="?highlight="+$.urlencode(t),c.append($("
          ").attr("href",u).html(l.title)),l.project!==e&&c.append($("").text(" (from project "+l.project+")")),d.content.length){var f=$('
          ').html(a(d.content[0]));f.find("em").addClass("highlighted"),c.append(f)}Search.output.append(c),c.slideDown(5)}n.length?Search.status.text(_("Search finished, found %s page(s) matching the search query.").replace("%s",n.length)):Search.query_fallback(t)}).fail(function(e){Search.query_fallback(t)}).always(function(){$("#search-progress").empty(),Search.stopPulse(),Search.title.text(_("Search Results")),Search.status.fadeIn(500)}),$.ajax({url:s.href,crossDomain:!0,xhrFields:{withCredentials:!0},complete:function(t,e){return"undefined"==typeof t.responseJSON||"undefined"==typeof t.responseJSON.results?o.reject():o.resolve(t.responseJSON.results)}}).error(function(t,e,r){return o.reject()})};if("undefined"!=typeof Search&&e&&r){var s=Search.query;Search.query_fallback=s,Search.query=o}$(document).ready(function(){"undefined"!=typeof Search&&Search.init()})}function n(){var t=o.get();i(t)}var o=t("./rtd-data"),a=t("./../../../../../../bower_components/xss/lib/index");e.exports={init:n}},{"./../../../../../../bower_components/xss/lib/index":3,"./rtd-data":14}],16:[function(t,e,r){function i(){var t=n.get();if($(document).on("click","[data-toggle='rst-current-version']",function(){var t=$("[data-toggle='rst-versions']").hasClass("shift-up")?"was_open":"was_closed";"undefined"!=typeof ga?ga("rtfd.send","event","Flyout","Click",t):"undefined"!=typeof _gaq&&_gaq.push(["rtfd._setAccount","UA-17997319-1"],["rtfd._trackEvent","Flyout","Click",t])}),!("builder"in t)||"builder"in t&&"mkdocs"!==t.builder){var e=o.ThemeNav;if($(document).ready(function(){setTimeout(function(){e.navBar||e.enable()},1e3)}),t.is_rtd_theme()){var r=jquery("div.wy-side-scroll:first");if(!r.length){var i=jquery("nav.wy-nav-side:first"),a=$("
          ").addClass("wy-side-scroll");i.children().detach().appendTo(a),a.prependTo(i),e.navBar=a}}}}var n=t("./rtd-data"),o=t("./../../../../../../bower_components/sphinx-rtd-theme/js/theme.js");e.exports={init:i}},{"./../../../../../../bower_components/sphinx-rtd-theme/js/theme.js":1,"./rtd-data":14}],17:[function(t,e,r){function i(){var t,e="rtd-"+(Math.random()+1).toString(36).substring(4),r=c.PROMO_TYPES.LEFTNAV,i=null;return l.is_rtd_theme()?(i="nav.wy-nav-side > div.wy-side-scroll",t="ethical-rtd"):l.get_theme_name()!==c.THEME_ALABASTER&&l.get_theme_name()!==c.THEME_CELERY||(i="div.sphinxsidebar > div.sphinxsidebarwrapper",t="ethical-alabaster"),i?($("
          ").attr("id",e).addClass(t).appendTo(i),{div_id:e,display_type:r}):null}function n(){var t,e="rtd-"+(Math.random()+1).toString(36).substring(4),r=c.PROMO_TYPES.FOOTER,i=null;return l.is_rtd_theme()?(i=$("
          ").insertAfter("footer hr"),t="ethical-rtd"):l.get_theme_name()!==c.THEME_ALABASTER&&l.get_theme_name()!==c.THEME_CELERY||(i="div.bodywrapper .body",t="ethical-alabaster"),i?($("
          ").attr("id",e).addClass(t).appendTo(i),{div_id:e,display_type:r}):null}function o(){for(var t,e=[],r=[n,i],o=0;o").insertAfter("#"+this.div_id),$("
          ").insertBefore("#"+this.div_id+".ethical-alabaster .ethical-footer"))},e.exports={Promo:a,init:s}},{"./constants":12,"./rtd-data":14}],18:[function(t,e,r){function i(t){var e=n.get();if(!t.is_highest){var r=window.location.pathname.replace(e.version,t.slug),i=$('
          ');i.find("a").attr("href",r).text(t.version);var o=$("div.body");o.length||(o=$("div.document")),o.prepend(i)}}var n=t("./rtd-data");e.exports={init:i}},{"./rtd-data":14}],19:[function(t,e,r){var i=t("./doc-embed/sponsorship"),n=t("./doc-embed/footer.js"),o=(t("./doc-embed/rtd-data"),t("./doc-embed/sphinx")),a=t("./doc-embed/search");$(document).ready(function(){n.init(),o.init(),a.init(),i.init()})},{"./doc-embed/footer.js":13,"./doc-embed/rtd-data":14,"./doc-embed/search":15,"./doc-embed/sphinx":16,"./doc-embed/sponsorship":17}]},{},[19]); \ No newline at end of file +!function(){function t(e,r,i){function n(a,s){if(!r[a]){if(!e[a]){var l="function"==typeof require&&require;if(!s&&l)return l(a,!0);if(o)return o(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var u=r[a]={exports:{}};e[a][0].call(u.exports,function(t){var r=e[a][1][t];return n(r?r:t)},u,u.exports,t,e,r,i)}return r[a].exports}for(var o="function"==typeof require&&require,a=0;a
          "),t(".wy-menu-vertical ul").not(".simple").siblings("a").each(function(){var r=t(this);expand=t(''),expand.on("click",function(t){return e.toggleCurrent(r),t.stopPropagation(),!1}),r.prepend(expand)})},t.reset=function(){var t=encodeURI(window.location.hash);if(t)try{var e=$(".wy-menu-vertical").find('[href="'+t+'"]');if(0===e.length){var r=$('.document a[href="'+t+'"]'),i=r.closest("div.section");e=$(".wy-menu-vertical").find('[href="#'+i.attr("id")+'"]')}$(".wy-menu-vertical li.toctree-l1 li.current").removeClass("current"),e.closest("li.toctree-l2").addClass("current"),e.closest("li.toctree-l3").addClass("current"),e.closest("li.toctree-l4").addClass("current")}catch(n){console.log("Error expanding nav for anchor",n)}},t.onScroll=function(){this.winScroll=!1;var t=this.win.scrollTop(),e=t+this.winHeight,r=this.navBar.scrollTop(),i=r+(t-this.winPosition);t<0||e>this.docHeight||(this.navBar.scrollTop(i),this.winPosition=t)},t.onResize=function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},t.hashChange=function(){this.linkScroll=!0,this.win.one("hashchange",function(){this.linkScroll=!1})},t.toggleCurrent=function(t){var e=t.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")},t}var n="undefined"!=typeof window?window.jQuery:t("jquery");e.exports.ThemeNav=i(),"undefined"!=typeof window&&(window.SphinxRtdTheme={StickyNav:e.exports.ThemeNav})},{jquery:"jquery"}],7:[function(t,e,r){function i(){return{a:["target","href","title"],abbr:["title"],address:[],area:["shape","coords","href","alt"],article:[],aside:[],audio:["autoplay","controls","loop","preload","src"],b:[],bdi:["dir"],bdo:["dir"],big:[],blockquote:["cite"],br:[],caption:[],center:[],cite:[],code:[],col:["align","valign","span","width"],colgroup:["align","valign","span","width"],dd:[],del:["datetime"],details:["open"],div:[],dl:[],dt:[],em:[],font:["color","size","face"],footer:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],header:[],hr:[],i:[],img:["src","alt","title","width","height"],ins:["datetime"],li:[],mark:[],nav:[],ol:[],p:[],pre:[],s:[],section:[],small:[],span:[],sub:[],sup:[],strong:[],table:["width","border","align","valign"],tbody:["align","valign"],td:["width","rowspan","colspan","align","valign"],tfoot:["align","valign"],th:["width","rowspan","colspan","align","valign"],thead:["align","valign"],tr:["rowspan","align","valign"],tt:[],u:[],ul:[],video:["autoplay","controls","loop","preload","src","height","width"]}}function n(t,e,r){}function o(t,e,r){}function a(t,e,r){}function s(t,e,r){}function l(t){return t.replace(E,"<").replace(S,">")}function c(t,e,r,i){if(r=g(r),"href"===e||"src"===e){if(r=T.trim(r),"#"===r)return"#";if("http://"!==r.substr(0,7)&&"https://"!==r.substr(0,8)&&"mailto:"!==r.substr(0,7)&&"tel:"!==r.substr(0,4)&&"#"!==r[0]&&"/"!==r[0])return""}else if("background"===e){if(I.lastIndex=0,I.test(r))return""}else if("style"===e){if($.lastIndex=0,$.test(r))return"";if(H.lastIndex=0,H.test(r)&&(I.lastIndex=0,I.test(r)))return"";i!==!1&&(i=i||k,r=i.process(r))}return r=m(r)}function u(t){return t.replace(A,""")}function d(t){return t.replace(C,'"')}function f(t){return t.replace(R,function(t,e){return"x"===e[0]||"X"===e[0]?String.fromCharCode(parseInt(e.substr(1),16)):String.fromCharCode(parseInt(e,10))})}function p(t){return t.replace(j,":").replace(O," ")}function h(t){for(var e="",r=0,i=t.length;r/g,A=/"/g,C=/"/g,R=/&#([a-zA-Z0-9]*);?/gim,j=/:?/gim,O=/&newline;?/gim,I=/((j\s*a\s*v\s*a|v\s*b|l\s*i\s*v\s*e)\s*s\s*c\s*r\s*i\s*p\s*t\s*|m\s*o\s*c\s*h\s*a)\:/gi,$=/e\s*x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n\s*\(.*/gi,H=/u\s*r\s*l\s*\(.*/gi,L=//g;r.whiteList=i(),r.getDefaultWhiteList=i,r.onTag=n,r.onIgnoreTag=o,r.onTagAttr=a,r.onIgnoreTagAttr=s,r.safeAttrValue=c,r.escapeHtml=l,r.escapeQuote=u,r.unescapeQuote=d,r.escapeHtmlEntities=f,r.escapeDangerHtml5Entities=p,r.clearNonPrintableCharacter=h,r.friendlyAttrValue=g,r.escapeAttrValue=m,r.onIgnoreTagStripAll=v,r.StripTagBody=b,r.stripCommentTag=w,r.stripBlankChar=y,r.cssFilter=k,r.getDefaultCSSWhiteList=_},{"./util":10,cssfilter:3}],8:[function(t,e,r){function i(t,e){var r=new a(e);return r.process(t)}var n=t("./default"),o=t("./parser"),a=t("./xss");r=e.exports=i,r.FilterXSS=a;for(var s in n)r[s]=n[s];for(var s in o)r[s]=o[s];"undefined"!=typeof window&&(window.filterXSS=e.exports)},{"./default":7,"./parser":9,"./xss":11}],9:[function(t,e,r){function i(t){var e=d.spaceIndex(t);if(e===-1)var r=t.slice(1,-1);else var r=t.slice(1,e+1);return r=d.trim(r).toLowerCase(),"/"===r.slice(0,1)&&(r=r.slice(1)),"/"===r.slice(-1)&&(r=r.slice(0,-1)),r}function n(t){return""===p){o+=r(t.slice(a,s)),d=t.slice(s,c+1),f=i(d),o+=e(s,o.length,f,d,n(d)),a=c+1,s=!1;continue}if(('"'===p||"'"===p)&&"="===t.charAt(c-1)){l=p;continue}}else if(p===l){l=!1;continue}}return a0;e--){var r=t[e];if(" "!==r)return"="===r?e:-1}}function c(t){return'"'===t[0]&&'"'===t[t.length-1]||"'"===t[0]&&"'"===t[t.length-1]}function u(t){return c(t)?t.substr(1,t.length-2):t}var d=t("./util"),f=/[^a-zA-Z0-9_:\.\-]/gim;r.parseTag=o,r.parseAttr=a},{"./util":10}],10:[function(t,e,r){e.exports={indexOf:function(t,e){var r,i;if(Array.prototype.indexOf)return t.indexOf(e);for(r=0,i=t.length;r";var w=n(l),y=o[r],x=d(w.html,function(t,e){var n=f.indexOf(y,t)!==-1,o=c(r,t,e,n);if(!i(o))return o;if(n)return e=h(r,t,e,m),e?t+'="'+e+'"':t;var o=p(r,t,e,n);return i(o)?void 0:o}),l="<"+r;return x&&(l+=" "+x),w.closing&&(l+=" /"),l+=">"}var b=s(r,l,v);return i(b)?g(l):b},g);return v&&(b=v.remove(b)),b},e.exports=a},{"./default":7,"./parser":9,"./util":10,cssfilter:3}],12:[function(t,e,r){var r={THEME_RTD:"sphinx_rtd_theme",THEME_ALABASTER:"alabaster",THEME_CELERY:"sphinx_celery"};r.PROMO_SUPPORTED_THEMES=[r.THEME_RTD,r.THEME_ALABASTER,r.THEME_CELERY],r.PROMO_TYPES={LEFTNAV:"doc",FOOTER:"site-footer"},e.exports=r},{}],13:[function(t,e,r){function i(t){var e=a.get();e.is_rtd_theme()?$("div.rst-other-versions").html(t.html):$("body").append(t.html),t.version_active?!t.version_supported:$(".rst-current-version").addClass("rst-out-of-date")}function n(){function t(t){return/^(GET|HEAD|OPTIONS|TRACE)$/.test(t)}$.ajaxSetup({beforeSend:function(e,r){t(r.type)||e.setRequestHeader("X-CSRFToken",$("a.bookmark[token]").attr("token"))}})}function o(){var t=a.get(),e={project:t.project,version:t.version,page:t.page,theme:t.get_theme_name(),format:"jsonp"};"docroot"in t&&(e.docroot=t.docroot),"source_suffix"in t&&(e.source_suffix=t.source_suffix),0===window.location.pathname.indexOf("/projects/")&&(e.subproject=!0),$.ajax({url:t.api_host+"/api/v2/footer_html/",crossDomain:!0,xhrFields:{withCredentials:!0},dataType:"jsonp",data:e,success:function(t){s.init(t.version_compare),i(t),n()},error:function(){console.error("Error loading Read the Docs footer")}})}var a=t("./rtd-data"),s=t("./version-compare");e.exports={init:o}},{"./rtd-data":14,"./version-compare":18}],14:[function(t,e,r){function i(){var t=Object.create(o),e={api_host:"https://readthedocs.org"};return $.extend(t,e,window.READTHEDOCS_DATA),t}var n=t("./constants"),o={is_rtd_theme:function(){return this.get_theme_name()===n.THEME_RTD},theme_supports_promo:function(){return n.PROMO_SUPPORTED_THEMES.indexOf(this.get_theme_name())>-1},is_sphinx_builder:function(){return!("builder"in this)||"mkdocs"!==this.builder},get_theme_name:function(){return this.theme!==n.THEME_RTD&&1===$("div.rst-other-versions").length?n.THEME_RTD:this.theme},show_promo:function(){return"https://readthedocs.com"!==this.api_host&&this.is_sphinx_builder()&&this.theme_supports_promo()}};e.exports={get:i}},{"./constants":12}],15:[function(t,e,r){function i(t){var e=t.project,r=t.version,i=t.language||"en",n=t.api_host,o=function(t){var o=$.Deferred(),s=document.createElement("a");s.href=n,s.pathname="/api/v2/docsearch/",s.search="?q="+$.urlencode(t)+"&project="+e+"&version="+r+"&language="+i,o.then(function(r){var i=r.hits||{},n=i.hits||[];if(n.length)for(var o in n){var s=n[o],l=s.fields||{},c=$('
        • '),u=document.createElement("a"),d=s.highlight;if(u.href+=l.link+DOCUMENTATION_OPTIONS.FILE_SUFFIX,u.search="?highlight="+$.urlencode(t),c.append($("").attr("href",u).html(l.title)),l.project!==e&&c.append($("").text(" (from project "+l.project+")")),d.content.length){var f=$('
          ').html(a(d.content[0]));f.find("em").addClass("highlighted"),c.append(f)}Search.output.append(c),c.slideDown(5)}n.length?Search.status.text(_("Search finished, found %s page(s) matching the search query.").replace("%s",n.length)):Search.query_fallback(t)}).fail(function(e){Search.query_fallback(t)}).always(function(){$("#search-progress").empty(),Search.stopPulse(),Search.title.text(_("Search Results")),Search.status.fadeIn(500)}),$.ajax({url:s.href,crossDomain:!0,xhrFields:{withCredentials:!0},complete:function(t,e){return"undefined"==typeof t.responseJSON||"undefined"==typeof t.responseJSON.results?o.reject():o.resolve(t.responseJSON.results)}}).error(function(t,e,r){return o.reject()})};if("undefined"!=typeof Search&&e&&r){var s=Search.query;Search.query_fallback=s,Search.query=o}$(document).ready(function(){"undefined"!=typeof Search&&Search.init()})}function n(){var t=o.get();i(t)}var o=t("./rtd-data"),a=t("./../../../../../../bower_components/xss/lib/index");e.exports={init:n}},{"./../../../../../../bower_components/xss/lib/index":8,"./rtd-data":14}],16:[function(t,e,r){function i(){var t=n.get();if($(document).on("click","[data-toggle='rst-current-version']",function(){var t=$("[data-toggle='rst-versions']").hasClass("shift-up")?"was_open":"was_closed";"undefined"!=typeof ga?ga("rtfd.send","event","Flyout","Click",t):"undefined"!=typeof _gaq&&_gaq.push(["rtfd._setAccount","UA-17997319-1"],["rtfd._trackEvent","Flyout","Click",t])}),!("builder"in t)||"builder"in t&&"mkdocs"!==t.builder){var e=o.ThemeNav;if($(document).ready(function(){setTimeout(function(){e.navBar||e.enable()},1e3)}),t.is_rtd_theme()){var r=jquery("div.wy-side-scroll:first");if(!r.length){var i=jquery("nav.wy-nav-side:first"),a=$("
          ").addClass("wy-side-scroll");i.children().detach().appendTo(a),a.prependTo(i),e.navBar=a}}}}var n=t("./rtd-data"),o=t("./../../../../../../bower_components/sphinx-rtd-theme/js/theme.js");e.exports={init:i}},{"./../../../../../../bower_components/sphinx-rtd-theme/js/theme.js":6,"./rtd-data":14}],17:[function(t,e,r){function i(){var t,e="rtd-"+(Math.random()+1).toString(36).substring(4),r=l.PROMO_TYPES.LEFTNAV,i=null;return s.is_rtd_theme()?(i="nav.wy-nav-side > div.wy-side-scroll",t="ethical-rtd"):s.get_theme_name()!==l.THEME_ALABASTER&&s.get_theme_name()!==l.THEME_CELERY||(i="div.sphinxsidebar > div.sphinxsidebarwrapper",t="ethical-alabaster"),i?($("
          ").attr("id",e).addClass(t).appendTo(i),{div_id:e,display_type:r}):null}function n(){var t,e="rtd-"+(Math.random()+1).toString(36).substring(4),r=l.PROMO_TYPES.FOOTER,i=null;return s.is_rtd_theme()?(i=$("
          ").insertAfter("footer hr"),t="ethical-rtd"):s.get_theme_name()!==l.THEME_ALABASTER&&s.get_theme_name()!==l.THEME_CELERY||(i="div.bodywrapper .body",t="ethical-alabaster"),i?($("
          ").attr("id",e).addClass(t).appendTo(i),{div_id:e,display_type:r}):null}function o(t){this.id=t.id,this.div_id=t.div_id||"",this.html=t.html||"",this.display_type=t.display_type||"",this.click_handler=function(){"undefined"!=typeof ga?ga("rtfd.send","event","Promo","Click",t.id):"undefined"!=typeof _gaq&&_gaq.push(["rtfd._setAccount","UA-17997319-1"],["rtfd._trackEvent","Promo","Click",t.id])}}function a(){var t,e,r={format:"jsonp"},a=[],l=[],u=[n,i];if(s=c.get(),s.show_promo()){for(var d=0;d").insertAfter("#"+this.div_id),$("
          ").insertBefore("#"+this.div_id+".ethical-alabaster .ethical-footer"))},e.exports={Promo:o,init:a}},{"./constants":12,"./rtd-data":14}],18:[function(t,e,r){function i(t){var e=n.get();if(!t.is_highest){var r=window.location.pathname.replace(e.version,t.slug),i=$('
          ');i.find("a").attr("href",r).text(t.version);var o=$("div.body");o.length||(o=$("div.document")),o.prepend(i)}}var n=t("./rtd-data");e.exports={init:i}},{"./rtd-data":14}],19:[function(t,e,r){var i=t("./doc-embed/sponsorship"),n=t("./doc-embed/footer.js"),o=(t("./doc-embed/rtd-data"),t("./doc-embed/sphinx")),a=t("./doc-embed/search");$(document).ready(function(){n.init(),o.init(),a.init(),i.init()})},{"./doc-embed/footer.js":13,"./doc-embed/rtd-data":14,"./doc-embed/search":15,"./doc-embed/sphinx":16,"./doc-embed/sponsorship":17}]},{},[19]); \ No newline at end of file diff --git a/readthedocs/core/static/core/js/site.js b/readthedocs/core/static/core/js/site.js index af18c61d6b7..7e01634bf36 100644 --- a/readthedocs/core/static/core/js/site.js +++ b/readthedocs/core/static/core/js/site.js @@ -1 +1 @@ -require=function t(r,i,n){function e(u,f){if(!i[u]){if(!r[u]){var a="function"==typeof require&&require;if(!f&&a)return a(u,!0);if(o)return o(u,!0);var c=new Error("Cannot find module '"+u+"'");throw c.code="MODULE_NOT_FOUND",c}var s=i[u]={exports:{}};r[u][0].call(s.exports,function(t){var i=r[u][1][t];return e(i?i:t)},s,s.exports,t,r,i,n)}return i[u].exports}for(var o="function"==typeof require&&require,u=0;u a").click(function(t){var r=$(this).attr("href"),i=$(this).parent().attr("data-dismiss-url");i?(t.preventDefault(),$.get(i,function(t,i,n){window.location.href=r})):$(this).hide()})})}},{}]},{},[]); \ No newline at end of file +require=function(){function t(r,n,i){function e(u,f){if(!n[u]){if(!r[u]){var a="function"==typeof require&&require;if(!f&&a)return a(u,!0);if(o)return o(u,!0);var c=new Error("Cannot find module '"+u+"'");throw c.code="MODULE_NOT_FOUND",c}var s=n[u]={exports:{}};r[u][0].call(s.exports,function(t){var n=r[u][1][t];return e(n?n:t)},s,s.exports,t,r,n,i)}return n[u].exports}for(var o="function"==typeof require&&require,u=0;u a").click(function(t){var r=$(this).attr("href"),n=$(this).parent().attr("data-dismiss-url");n?(t.preventDefault(),$.get(n,function(t,n,i){window.location.href=r})):$(this).hide()})})}},{}]},{},[]); \ No newline at end of file diff --git a/readthedocs/gold/static/gold/js/gold.js b/readthedocs/gold/static/gold/js/gold.js index 194993e19c0..49183a61bb5 100644 --- a/readthedocs/gold/static/gold/js/gold.js +++ b/readthedocs/gold/static/gold/js/gold.js @@ -1 +1 @@ -require=function e(t,r,n){function i(a,c){if(!r[a]){if(!t[a]){var u="function"==typeof require&&require;if(!c&&u)return u(a,!0);if(o)return o(a,!0);var l=new Error("Cannot find module '"+a+"'");throw l.code="MODULE_NOT_FOUND",l}var s=r[a]={exports:{}};t[a][0].call(s.exports,function(e){var r=t[a][1][e];return i(r?r:e)},s,s.exports,e,t,r,n)}return r[a].exports}for(var o="function"==typeof require&&require,a=0;a9&&(t-=9),i+=t;return i%10===0},p=function(e){var t;return null!=e.prop("selectionStart")&&e.prop("selectionStart")!==e.prop("selectionEnd")||!(null==("undefined"!=typeof document&&null!==document&&null!=(t=document.selection)?t.createRange:void 0)||!document.selection.createRange().text)},C=function(e,t){var r,n,i,o,a,c;try{n=t.prop("selectionStart")}catch(u){o=u,n=null}if(a=t.val(),t.val(e),null!==n&&t.is(":focus"))return n===a.length&&(n=e.length),a!==e&&(c=a.slice(n-1,+n+1||9e9),r=e.slice(n-1,+n+1||9e9),i=e[n],/\d/.test(i)&&c===""+i+" "&&r===" "+i&&(n+=1)),t.prop("selectionStart",n),t.prop("selectionEnd",n)},y=function(e){var t,r,n,i,o,a,c,u;for(null==e&&(e=""),n="0123456789",i="0123456789",a="",t=e.split(""),c=0,u=t.length;c-1&&(r=i[o]),a+=r;return a},m=function(t){var r;return r=e(t.currentTarget),setTimeout(function(){var e;return e=r.val(),e=y(e),e=e.replace(/\D/g,""),C(e,r)})},d=function(t){var r;return r=e(t.currentTarget),setTimeout(function(){var t;return t=r.val(),t=y(t),t=e.payment.formatCardNumber(t),C(t,r)})},c=function(r){var n,i,o,a,c,u,l;if(o=String.fromCharCode(r.which),/^\d+$/.test(o)&&(n=e(r.currentTarget),l=n.val(),i=t(l+o),a=(l.replace(/\D/g,"")+o).length,u=16,i&&(u=i.length[i.length.length-1]),!(a>=u||null!=n.prop("selectionStart")&&n.prop("selectionStart")!==l.length)))return c=i&&"amex"===i.type?/^(\d{4}|\d{4}\s\d{6})$/:/(?:^|\s)(\d{4})$/,c.test(l)?(r.preventDefault(),setTimeout(function(){return n.val(l+" "+o)})):c.test(l+o)?(r.preventDefault(),setTimeout(function(){return n.val(l+o+" ")})):void 0},o=function(t){var r,n;if(r=e(t.currentTarget),n=r.val(),8===t.which&&(null==r.prop("selectionStart")||r.prop("selectionStart")===n.length))return/\d\s$/.test(n)?(t.preventDefault(),setTimeout(function(){return r.val(n.replace(/\d\s$/,""))})):/\s\d?$/.test(n)?(t.preventDefault(),setTimeout(function(){return r.val(n.replace(/\d$/,""))})):void 0},v=function(t){var r;return r=e(t.currentTarget),setTimeout(function(){var t;return t=r.val(),t=y(t),t=e.payment.formatExpiry(t),C(t,r)})},u=function(t){var r,n,i;if(n=String.fromCharCode(t.which),/^\d+$/.test(n))return r=e(t.currentTarget),i=r.val()+n,/^\d$/.test(i)&&"0"!==i&&"1"!==i?(t.preventDefault(),setTimeout(function(){return r.val("0"+i+" / ")})):/^\d\d$/.test(i)?(t.preventDefault(),setTimeout(function(){var e,t;return e=parseInt(i[0],10),t=parseInt(i[1],10),t>2&&0!==e?r.val("0"+e+" / "+t):r.val(""+i+" / ")})):void 0},l=function(t){var r,n,i;if(n=String.fromCharCode(t.which),/^\d+$/.test(n))return r=e(t.currentTarget),i=r.val(),/^\d\d$/.test(i)?r.val(""+i+" / "):void 0},s=function(t){var r,n,i;if(i=String.fromCharCode(t.which),"/"===i||" "===i)return r=e(t.currentTarget),n=r.val(),/^\d$/.test(n)&&"0"!==n?r.val("0"+n+" / "):void 0},a=function(t){var r,n;if(r=e(t.currentTarget),n=r.val(),8===t.which&&(null==r.prop("selectionStart")||r.prop("selectionStart")===n.length))return/\d\s\/\s$/.test(n)?(t.preventDefault(),setTimeout(function(){return r.val(n.replace(/\d\s\/\s$/,""))})):void 0},h=function(t){var r;return r=e(t.currentTarget),setTimeout(function(){var e;return e=r.val(),e=y(e),e=e.replace(/\D/g,"").slice(0,4),C(e,r)})},w=function(e){var t;return!(!e.metaKey&&!e.ctrlKey)||32!==e.which&&(0===e.which||(e.which<33||(t=String.fromCharCode(e.which),!!/[\d\s]/.test(t))))},_=function(r){var n,i,o,a;if(n=e(r.currentTarget),o=String.fromCharCode(r.which),/^\d+$/.test(o)&&!p(n))return a=(n.val()+o).replace(/\D/g,""),i=t(a),i?a.length<=i.length[i.length.length-1]:a.length<=16},b=function(t){var r,n,i;if(r=e(t.currentTarget),n=String.fromCharCode(t.which),/^\d+$/.test(n)&&!p(r))return i=r.val()+n,i=i.replace(/\D/g,""),!(i.length>6)&&void 0},g=function(t){var r,n,i;if(r=e(t.currentTarget),n=String.fromCharCode(t.which),/^\d+$/.test(n)&&!p(r))return i=r.val()+n,i.length<=4},x=function(t){var r,i,o,a,c;if(r=e(t.currentTarget),c=r.val(),a=e.payment.cardType(c)||"unknown",!r.hasClass(a))return i=function(){var e,t,r;for(r=[],e=0,t=n.length;e=0&&(r.luhn===!1||f(e))))},e.payment.validateCardExpiry=function(t,r){var n,i,o;return"object"==typeof t&&"month"in t&&(o=t,t=o.month,r=o.year),!(!t||!r)&&(t=e.trim(t),r=e.trim(r),!!/^\d+$/.test(t)&&(!!/^\d+$/.test(r)&&(1<=t&&t<=12&&(2===r.length&&(r=r<70?"20"+r:"19"+r),4===r.length&&(i=new Date(r,t),n=new Date,i.setMonth(i.getMonth()-1),i.setMonth(i.getMonth()+1,1),i>n)))))},e.payment.validateCardCVC=function(t,n){var i,o;return t=e.trim(t),!!/^\d+$/.test(t)&&(i=r(n),null!=i?(o=t.length,T.call(i.cvcLength,o)>=0):t.length>=3&&t.length<=4)},e.payment.cardType=function(e){var r;return e?(null!=(r=t(e))?r.type:void 0)||null:null},e.payment.formatCardNumber=function(r){var n,i,o,a;return r=r.replace(/\D/g,""),(n=t(r))?(o=n.length[n.length.length-1],r=r.slice(0,o),n.format.global?null!=(a=r.match(n.format))?a.join(" "):void 0:(i=n.format.exec(r),null!=i?(i.shift(),i=e.grep(i,function(e){return e}),i.join(" ")):void 0)):r},e.payment.formatExpiry=function(e){var t,r,n,i;return(r=e.match(/^\D*(\d{1,2})(\D+)?(\d{1,4})?/))?(t=r[1]||"",n=r[2]||"",i=r[3]||"",i.length>0?n=" / ":" /"===n?(t=t.substring(0,1),n=""):2===t.length||n.length>0?n=" / ":1===t.length&&"0"!==t&&"1"!==t&&(t="0"+t,n=" / "),t+n+i):""}}).call(this)},{}],2:[function(e,t,r){function n(e){var t=this,e=e||{};a.publishableKey=t.stripe_key=e.key,t.form=e.form,t.cc_number=i.observable(null),t.cc_expiry=i.observable(null),t.cc_cvv=i.observable(null),t.error_cc_number=i.observable(null),t.error_cc_expiry=i.observable(null),t.error_cc_cvv=i.observable(null),t.stripe_token=i.observable(null),t.card_digits=i.observable(null),t.is_editing_card=i.observable(!1),t.show_card_form=i.computed(function(){return t.is_editing_card()||!t.card_digits()||t.cc_number()||t.cc_expiry()||t.cc_cvv()}),t.initialize_form(),t.error=i.observable(null),t.process_form=function(){var e=o.payment.cardExpiryVal(t.cc_expiry()),r={number:t.cc_number(),exp_month:e.month,exp_year:e.year,cvc:t.cc_cvv()};return t.error(null),t.error_cc_number(null),t.error_cc_expiry(null),t.error_cc_cvv(null),o.payment.validateCardNumber(r.number)?o.payment.validateCardExpiry(r.exp_month,r.exp_year)?o.payment.validateCardCVC(r.cvc)?void a.createToken(r,function(e,r){if(r.error)if("card_error"==r.error.type){var n={invalid_number:t.error_cc_number,incorrect_number:t.error_cc_number,expired_card:t.error_cc_number,card_declined:t.error_cc_number,invalid_expiry_month:t.error_cc_expiry,invalid_expiry_year:t.error_cc_expiry,invalid_cvc:t.error_cc_cvv,incorrect_cvc:t.error_cc_cvv},i=n[r.error.code]||t.error_cc_number;i(r.error.message)}else t.error_cc_number(r.error.message);else t.submit_form(r.card.last4,r.id)}):(t.error_cc_cvv("Invalid security code"),!1):(t.error_cc_expiry("Invalid expiration date"),!1):(t.error_cc_number("Invalid card number"),!1)},t.process_full_form=function(){return!t.show_card_form()||void t.process_form()}}var i=e("knockout"),o=(e("./../../../../../bower_components/jquery.payment/lib/jquery.payment.js"),e("jquery")),a=null;"undefined"!=typeof window&&"undefined"!=typeof window.Stripe&&(a=window.Stripe||{}),i.bindingHandlers.valueInit={init:function(e,t){var r=t();i.isWriteableObservable(r)&&r(e.value)}},n.prototype.submit_form=function(e,t){this.form.find("#id_card_digits").val(e),this.form.find("#id_stripe_token").val(t),this.form.submit()},n.prototype.initialize_form=function(){var e=o("input#id_cc_number"),t=o("input#id_cc_cvv"),r=o("input#id_cc_expiry");e.payment("formatCardNumber"),r.payment("formatCardExpiry"),t.payment("formatCardCVC"),e.trigger("keyup")},n.init=function(e,t){var r=new n(e),t=t||o("#payment-form")[0];return i.applyBindings(r,t),r},t.exports.PaymentView=n},{"./../../../../../bower_components/jquery.payment/lib/jquery.payment.js":1,jquery:"jquery",knockout:"knockout"}],"gold/gold":[function(e,t,r){function n(e){var t=this,e=e||{};t.constructor.call(t,e),t.last_4_digits=o.observable(null)}var i=(e("jquery"),e("readthedocs/payments/static-src/payments/js/base")),o=e("knockout");n.prototype=new i.PaymentView,n.init=function(e,t){var r=new n(e),t=t||$("#payment-form")[0];return o.applyBindings(r,t),r},n.prototype.submit_form=function(e,t){this.form.find("#id_last_4_digits").val(e),this.form.find("#id_stripe_token").val(t),this.form.submit()},t.exports.GoldView=n},{jquery:"jquery",knockout:"knockout","readthedocs/payments/static-src/payments/js/base":2}]},{},[]); \ No newline at end of file +require=function(){function e(t,r,n){function i(a,c){if(!r[a]){if(!t[a]){var u="function"==typeof require&&require;if(!c&&u)return u(a,!0);if(o)return o(a,!0);var l=new Error("Cannot find module '"+a+"'");throw l.code="MODULE_NOT_FOUND",l}var s=r[a]={exports:{}};t[a][0].call(s.exports,function(e){var r=t[a][1][e];return i(r?r:e)},s,s.exports,e,t,r,n)}return r[a].exports}for(var o="function"==typeof require&&require,a=0;a9&&(t-=9),i+=t;return i%10===0},p=function(e){var t;return null!=e.prop("selectionStart")&&e.prop("selectionStart")!==e.prop("selectionEnd")||!(null==("undefined"!=typeof document&&null!==document&&null!=(t=document.selection)?t.createRange:void 0)||!document.selection.createRange().text)},C=function(e,t){var r,n,i,o,a,c;try{n=t.prop("selectionStart")}catch(u){o=u,n=null}if(a=t.val(),t.val(e),null!==n&&t.is(":focus"))return n===a.length&&(n=e.length),a!==e&&(c=a.slice(n-1,+n+1||9e9),r=e.slice(n-1,+n+1||9e9),i=e[n],/\d/.test(i)&&c===""+i+" "&&r===" "+i&&(n+=1)),t.prop("selectionStart",n),t.prop("selectionEnd",n)},y=function(e){var t,r,n,i,o,a,c,u;for(null==e&&(e=""),n="0123456789",i="0123456789",a="",t=e.split(""),c=0,u=t.length;c-1&&(r=i[o]),a+=r;return a},m=function(t){var r;return r=e(t.currentTarget),setTimeout(function(){var e;return e=r.val(),e=y(e),e=e.replace(/\D/g,""),C(e,r)})},d=function(t){var r;return r=e(t.currentTarget),setTimeout(function(){var t;return t=r.val(),t=y(t),t=e.payment.formatCardNumber(t),C(t,r)})},c=function(r){var n,i,o,a,c,u,l;if(o=String.fromCharCode(r.which),/^\d+$/.test(o)&&(n=e(r.currentTarget),l=n.val(),i=t(l+o),a=(l.replace(/\D/g,"")+o).length,u=16,i&&(u=i.length[i.length.length-1]),!(a>=u||null!=n.prop("selectionStart")&&n.prop("selectionStart")!==l.length)))return c=i&&"amex"===i.type?/^(\d{4}|\d{4}\s\d{6})$/:/(?:^|\s)(\d{4})$/,c.test(l)?(r.preventDefault(),setTimeout(function(){return n.val(l+" "+o)})):c.test(l+o)?(r.preventDefault(),setTimeout(function(){return n.val(l+o+" ")})):void 0},o=function(t){var r,n;if(r=e(t.currentTarget),n=r.val(),8===t.which&&(null==r.prop("selectionStart")||r.prop("selectionStart")===n.length))return/\d\s$/.test(n)?(t.preventDefault(),setTimeout(function(){return r.val(n.replace(/\d\s$/,""))})):/\s\d?$/.test(n)?(t.preventDefault(),setTimeout(function(){return r.val(n.replace(/\d$/,""))})):void 0},v=function(t){var r;return r=e(t.currentTarget),setTimeout(function(){var t;return t=r.val(),t=y(t),t=e.payment.formatExpiry(t),C(t,r)})},u=function(t){var r,n,i;if(n=String.fromCharCode(t.which),/^\d+$/.test(n))return r=e(t.currentTarget),i=r.val()+n,/^\d$/.test(i)&&"0"!==i&&"1"!==i?(t.preventDefault(),setTimeout(function(){return r.val("0"+i+" / ")})):/^\d\d$/.test(i)?(t.preventDefault(),setTimeout(function(){var e,t;return e=parseInt(i[0],10),t=parseInt(i[1],10),t>2&&0!==e?r.val("0"+e+" / "+t):r.val(""+i+" / ")})):void 0},l=function(t){var r,n,i;if(n=String.fromCharCode(t.which),/^\d+$/.test(n))return r=e(t.currentTarget),i=r.val(),/^\d\d$/.test(i)?r.val(""+i+" / "):void 0},s=function(t){var r,n,i;if(i=String.fromCharCode(t.which),"/"===i||" "===i)return r=e(t.currentTarget),n=r.val(),/^\d$/.test(n)&&"0"!==n?r.val("0"+n+" / "):void 0},a=function(t){var r,n;if(r=e(t.currentTarget),n=r.val(),8===t.which&&(null==r.prop("selectionStart")||r.prop("selectionStart")===n.length))return/\d\s\/\s$/.test(n)?(t.preventDefault(),setTimeout(function(){return r.val(n.replace(/\d\s\/\s$/,""))})):void 0},h=function(t){var r;return r=e(t.currentTarget),setTimeout(function(){var e;return e=r.val(),e=y(e),e=e.replace(/\D/g,"").slice(0,4),C(e,r)})},w=function(e){var t;return!(!e.metaKey&&!e.ctrlKey)||32!==e.which&&(0===e.which||(e.which<33||(t=String.fromCharCode(e.which),!!/[\d\s]/.test(t))))},_=function(r){var n,i,o,a;if(n=e(r.currentTarget),o=String.fromCharCode(r.which),/^\d+$/.test(o)&&!p(n))return a=(n.val()+o).replace(/\D/g,""),i=t(a),i?a.length<=i.length[i.length.length-1]:a.length<=16},b=function(t){var r,n,i;if(r=e(t.currentTarget),n=String.fromCharCode(t.which),/^\d+$/.test(n)&&!p(r))return i=r.val()+n,i=i.replace(/\D/g,""),!(i.length>6)&&void 0},g=function(t){var r,n,i;if(r=e(t.currentTarget),n=String.fromCharCode(t.which),/^\d+$/.test(n)&&!p(r))return i=r.val()+n,i.length<=4},x=function(t){var r,i,o,a,c;if(r=e(t.currentTarget),c=r.val(),a=e.payment.cardType(c)||"unknown",!r.hasClass(a))return i=function(){var e,t,r;for(r=[],e=0,t=n.length;e=0&&(r.luhn===!1||f(e))))},e.payment.validateCardExpiry=function(t,r){var n,i,o;return"object"==typeof t&&"month"in t&&(o=t,t=o.month,r=o.year),!(!t||!r)&&(t=e.trim(t),r=e.trim(r),!!/^\d+$/.test(t)&&(!!/^\d+$/.test(r)&&(1<=t&&t<=12&&(2===r.length&&(r=r<70?"20"+r:"19"+r),4===r.length&&(i=new Date(r,t),n=new Date,i.setMonth(i.getMonth()-1),i.setMonth(i.getMonth()+1,1),i>n)))))},e.payment.validateCardCVC=function(t,n){var i,o;return t=e.trim(t),!!/^\d+$/.test(t)&&(i=r(n),null!=i?(o=t.length,T.call(i.cvcLength,o)>=0):t.length>=3&&t.length<=4)},e.payment.cardType=function(e){var r;return e?(null!=(r=t(e))?r.type:void 0)||null:null},e.payment.formatCardNumber=function(r){var n,i,o,a;return r=r.replace(/\D/g,""),(n=t(r))?(o=n.length[n.length.length-1],r=r.slice(0,o),n.format.global?null!=(a=r.match(n.format))?a.join(" "):void 0:(i=n.format.exec(r),null!=i?(i.shift(),i=e.grep(i,function(e){return e}),i.join(" ")):void 0)):r},e.payment.formatExpiry=function(e){var t,r,n,i;return(r=e.match(/^\D*(\d{1,2})(\D+)?(\d{1,4})?/))?(t=r[1]||"",n=r[2]||"",i=r[3]||"",i.length>0?n=" / ":" /"===n?(t=t.substring(0,1),n=""):2===t.length||n.length>0?n=" / ":1===t.length&&"0"!==t&&"1"!==t&&(t="0"+t,n=" / "),t+n+i):""}}).call(this)},{}],2:[function(e,t,r){function n(e){var t=this,e=e||{};a.publishableKey=t.stripe_key=e.key,t.form=e.form,t.cc_number=i.observable(null),t.cc_expiry=i.observable(null),t.cc_cvv=i.observable(null),t.error_cc_number=i.observable(null),t.error_cc_expiry=i.observable(null),t.error_cc_cvv=i.observable(null),t.stripe_token=i.observable(null),t.card_digits=i.observable(null),t.is_editing_card=i.observable(!1),t.show_card_form=i.computed(function(){return t.is_editing_card()||!t.card_digits()||t.cc_number()||t.cc_expiry()||t.cc_cvv()}),t.initialize_form(),t.error=i.observable(null),t.process_form=function(){var e=o.payment.cardExpiryVal(t.cc_expiry()),r={number:t.cc_number(),exp_month:e.month,exp_year:e.year,cvc:t.cc_cvv()};return t.error(null),t.error_cc_number(null),t.error_cc_expiry(null),t.error_cc_cvv(null),o.payment.validateCardNumber(r.number)?o.payment.validateCardExpiry(r.exp_month,r.exp_year)?o.payment.validateCardCVC(r.cvc)?void a.createToken(r,function(e,r){if(r.error)if("card_error"==r.error.type){var n={invalid_number:t.error_cc_number,incorrect_number:t.error_cc_number,expired_card:t.error_cc_number,card_declined:t.error_cc_number,invalid_expiry_month:t.error_cc_expiry,invalid_expiry_year:t.error_cc_expiry,invalid_cvc:t.error_cc_cvv,incorrect_cvc:t.error_cc_cvv},i=n[r.error.code]||t.error_cc_number;i(r.error.message)}else t.error_cc_number(r.error.message);else t.submit_form(r.card.last4,r.id)}):(t.error_cc_cvv("Invalid security code"),!1):(t.error_cc_expiry("Invalid expiration date"),!1):(t.error_cc_number("Invalid card number"),!1)},t.process_full_form=function(){return!t.show_card_form()||void t.process_form()}}var i=e("knockout"),o=(e("./../../../../../bower_components/jquery.payment/lib/jquery.payment.js"),e("jquery")),a=null;"undefined"!=typeof window&&"undefined"!=typeof window.Stripe&&(a=window.Stripe||{}),i.bindingHandlers.valueInit={init:function(e,t){var r=t();i.isWriteableObservable(r)&&r(e.value)}},n.prototype.submit_form=function(e,t){this.form.find("#id_card_digits").val(e),this.form.find("#id_stripe_token").val(t),this.form.submit()},n.prototype.initialize_form=function(){var e=o("input#id_cc_number"),t=o("input#id_cc_cvv"),r=o("input#id_cc_expiry");e.payment("formatCardNumber"),r.payment("formatCardExpiry"),t.payment("formatCardCVC"),e.trigger("keyup")},n.init=function(e,t){var r=new n(e),t=t||o("#payment-form")[0];return i.applyBindings(r,t),r},t.exports.PaymentView=n},{"./../../../../../bower_components/jquery.payment/lib/jquery.payment.js":1,jquery:"jquery",knockout:"knockout"}],"gold/gold":[function(e,t,r){function n(e){var t=this,e=e||{};t.constructor.call(t,e),t.last_4_digits=o.observable(null)}var i=(e("jquery"),e("readthedocs/payments/static-src/payments/js/base")),o=e("knockout");n.prototype=new i.PaymentView,n.init=function(e,t){var r=new n(e),t=t||$("#payment-form")[0];return o.applyBindings(r,t),r},n.prototype.submit_form=function(e,t){this.form.find("#id_last_4_digits").val(e),this.form.find("#id_stripe_token").val(t),this.form.submit()},t.exports.GoldView=n},{jquery:"jquery",knockout:"knockout","readthedocs/payments/static-src/payments/js/base":2}]},{},[]); \ No newline at end of file diff --git a/readthedocs/projects/static/projects/js/import.js b/readthedocs/projects/static/projects/js/import.js index 9f040cce0e3..56721b9aafe 100644 --- a/readthedocs/projects/static/projects/js/import.js +++ b/readthedocs/projects/static/projects/js/import.js @@ -1 +1 @@ -require=function e(r,t,n){function a(s,i){if(!t[s]){if(!r[s]){var u="function"==typeof require&&require;if(!i&&u)return u(s,!0);if(o)return o(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var l=t[s]={exports:{}};r[s][0].call(l.exports,function(e){var t=r[s][1][e];return a(t?t:e)},l,l.exports,e,r,t,n)}return t[s].exports}for(var o="function"==typeof require&&require,s=0;s0)setTimeout(r,2e3);else{var a=e.responseJSON.detail||e.statusText;t.reject({message:a})}})}var t=o.Deferred(),n=5;return setTimeout(r,2e3),t}function a(e){var r=o.Deferred(),t=e.url,a=e.token,s={csrfmiddlewaretoken:a};return $.ajax({method:"POST",url:t,data:s,success:function(e){n(e).then(function(){r.resolve()}).fail(function(e){r.reject(e)})},error:function(e){var t=e.responseJSON.detail||e.statusText;r.reject({message:t})}}),r}var o=e("jquery");r.exports={poll_task:n,trigger_task:a}},{jquery:"jquery"}],"projects/import":[function(e,r,t){function n(e,r){var t=c("").attr("href",e).get(0);return Object.keys(r).map(function(e){t.search&&(t.search+="&"),t.search+=e+"="+r[e]}),t.href}function a(e,r){var t=this;t.id=u.observable(e.id),t.name=u.observable(e.name),t.slug=u.observable(e.slug),t.active=u.observable(e.active),t.avatar_url=u.observable(n(e.avatar_url,{size:32})),t.display_name=u.computed(function(){return t.name()||t.slug()}),t.filter_id=u.computed(function(){return t.id()}),t.filter_type="org",t.filtered=u.computed(function(){var e=r.filter_by();return e.id&&e.id!==t.filter_id()||e.type&&e.type!==t.filter_type})}function o(e,r){var t=this;t.id=u.observable(e.id),t.username=u.observable(e.username),t.active=u.observable(e.active),t.avatar_url=u.observable(n(e.avatar_url,{size:32})),t.provider=u.observable(e.provider),t.display_name=u.computed(function(){return t.username()}),t.filter_id=u.computed(function(){return t.provider().id}),t.filter_type="own",t.filtered=u.computed(function(){var e=r.filter_by();return e.id&&e.id!==t.filter_id()||e.type&&e.type!==t.filter_type})}function s(e,r){var t=this;t.id=u.observable(e.id),t.name=u.observable(e.name),t.full_name=u.observable(e.full_name),t.description=u.observable(e.description),t.vcs=u.observable(e.vcs),t.organization=u.observable(e.organization),t.html_url=u.observable(e.html_url),t.clone_url=u.observable(e.clone_url),t.ssh_url=u.observable(e.ssh_url),t.matches=u.observable(e.matches),t.match=u.computed(function(){var e=t.matches();if(e&&e.length>0)return e[0]}),t["private"]=u.observable(e["private"]),t.active=u.observable(e.active),t.admin=u.observable(e.admin),t.is_locked=u.computed(function(){return t["private"]()&&!t.admin()}),t.avatar_url=u.observable(n(e.avatar_url,{size:32})),t.import_repo=function(){var e={name:t.name(),repo:t.clone_url(),repo_type:t.vcs(),description:t.description(),project_url:t.html_url(),remote_repository:t.id()},n=c("");n.attr("action",r.urls.projects_import).attr("method","POST").hide(),Object.keys(e).map(function(r){var t=c("").attr("type","hidden").attr("name",r).attr("value",e[r]);n.append(t)});var a=c("").attr("type","hidden").attr("name","csrfmiddlewaretoken").attr("value",r.csrf_token);n.append(a);var o=c("").attr("type","submit");n.append(o),c("body").append(n),n.submit()}}function i(e,r){var t=this;t.config=r||{},t.urls=r.urls||{},t.csrf_token=r.csrf_token||"",t.error=u.observable(null),t.is_syncing=u.observable(!1),t.is_ready=u.observable(!1),t.page_current=u.observable(null),t.page_next=u.observable(null),t.page_previous=u.observable(null),t.filter_by=u.observable({id:null,type:null}),t.accounts_raw=u.observableArray(),t.organizations_raw=u.observableArray(),t.filters=u.computed(function(){var e,r=[],n=t.accounts_raw(),s=t.organizations_raw();for(e in n){var i=new o(n[e],t);r.push(i)}for(e in s){var u=new a(s[e],t);r.push(u)}return r}),t.projects=u.observableArray(),u.computed(function(){var e=t.filter_by(),r=t.page_current()||t.urls["remoterepository-list"];t.page_current()||("org"===e.type&&(r=n(t.urls["remoterepository-list"],{org:e.id})),"own"===e.type&&(r=n(t.urls["remoterepository-list"],{own:e.id}))),t.error(null),c.getJSON(r).success(function(e){var r=[];t.page_next(e.next),t.page_previous(e.previous);var n;for(n in e.results){var a=new s(e.results[n],t);r.push(a)}t.projects(r)}).error(function(e){var r=e.responseJSON.detail||e.statusText;t.error({message:r})}).always(function(){t.is_ready(!0)})}).extend({deferred:!0}),t.get_organizations=function(){c.getJSON(t.urls["remoteorganization-list"]).success(function(e){t.organizations_raw(e.results)}).error(function(e){var r=e.responseJSON.detail||e.statusText;t.error({message:r})})},t.get_accounts=function(){c.getJSON(t.urls["remoteaccount-list"]).success(function(e){t.accounts_raw(e.results)}).error(function(e){var r=e.responseJSON.detail||e.statusText;t.error({message:r})})},t.sync_projects=function(){var e=t.urls.api_sync_remote_repositories;t.error(null),t.is_syncing(!0),l.trigger_task({url:e,token:t.csrf_token}).then(function(e){t.get_organizations(),t.get_accounts()}).fail(function(e){t.error(e)}).always(function(){t.is_syncing(!1)})},t.has_projects=u.computed(function(){return t.projects().length>0}),t.next_page=function(){t.page_current(t.page_next())},t.previous_page=function(){t.page_current(t.page_previous())},t.set_filter_by=function(e,r){var n=t.filter_by();n.id===e?(n.id=null,n.type=null):(n.id=e,n.type=r),t.filter_by(n),n.id&&t.page_current(null)}}var u=e("knockout"),c=e("jquery"),l=e("readthedocs/core/static-src/core/js/tasks");c(function(){var e=c("#id_repo"),r=c("#id_repo_type");e.blur(function(){var t,n=e.val();switch(!0){case/^hg/.test(n):t="hg";break;case/^bzr/.test(n):case/launchpad/.test(n):t="bzr";break;case/trunk/.test(n):case/^svn/.test(n):t="svn";break;default:case/github/.test(n):case/(^git|\.git$)/.test(n):t="git"}r.val(t)})}),i.init=function(e,r,t){var n=new i(r,t);return n.get_accounts(),n.get_organizations(),u.applyBindings(n,e),n},r.exports.ProjectImportView=i},{jquery:"jquery",knockout:"knockout","readthedocs/core/static-src/core/js/tasks":1}]},{},[]); \ No newline at end of file +require=function(){function e(r,t,n){function a(s,i){if(!t[s]){if(!r[s]){var u="function"==typeof require&&require;if(!i&&u)return u(s,!0);if(o)return o(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var l=t[s]={exports:{}};r[s][0].call(l.exports,function(e){var t=r[s][1][e];return a(t?t:e)},l,l.exports,e,r,t,n)}return t[s].exports}for(var o="function"==typeof require&&require,s=0;s0)setTimeout(r,2e3);else{var a=e.responseJSON.detail||e.statusText;t.reject({message:a})}})}var t=o.Deferred(),n=5;return setTimeout(r,2e3),t}function a(e){var r=o.Deferred(),t=e.url,a=e.token,s={csrfmiddlewaretoken:a};return $.ajax({method:"POST",url:t,data:s,success:function(e){n(e).then(function(){r.resolve()}).fail(function(e){r.reject(e)})},error:function(e){var t=e.responseJSON.detail||e.statusText;r.reject({message:t})}}),r}var o=e("jquery");r.exports={poll_task:n,trigger_task:a}},{jquery:"jquery"}],"projects/import":[function(e,r,t){function n(e,r){var t=c("").attr("href",e).get(0);return Object.keys(r).map(function(e){t.search&&(t.search+="&"),t.search+=e+"="+r[e]}),t.href}function a(e,r){var t=this;t.id=u.observable(e.id),t.name=u.observable(e.name),t.slug=u.observable(e.slug),t.active=u.observable(e.active),t.avatar_url=u.observable(n(e.avatar_url,{size:32})),t.display_name=u.computed(function(){return t.name()||t.slug()}),t.filter_id=u.computed(function(){return t.id()}),t.filter_type="org",t.filtered=u.computed(function(){var e=r.filter_by();return e.id&&e.id!==t.filter_id()||e.type&&e.type!==t.filter_type})}function o(e,r){var t=this;t.id=u.observable(e.id),t.username=u.observable(e.username),t.active=u.observable(e.active),t.avatar_url=u.observable(n(e.avatar_url,{size:32})),t.provider=u.observable(e.provider),t.display_name=u.computed(function(){return t.username()}),t.filter_id=u.computed(function(){return t.provider().id}),t.filter_type="own",t.filtered=u.computed(function(){var e=r.filter_by();return e.id&&e.id!==t.filter_id()||e.type&&e.type!==t.filter_type})}function s(e,r){var t=this;t.id=u.observable(e.id),t.name=u.observable(e.name),t.full_name=u.observable(e.full_name),t.description=u.observable(e.description),t.vcs=u.observable(e.vcs),t.organization=u.observable(e.organization),t.html_url=u.observable(e.html_url),t.clone_url=u.observable(e.clone_url),t.ssh_url=u.observable(e.ssh_url),t.matches=u.observable(e.matches),t.match=u.computed(function(){var e=t.matches();if(e&&e.length>0)return e[0]}),t["private"]=u.observable(e["private"]),t.active=u.observable(e.active),t.admin=u.observable(e.admin),t.is_locked=u.computed(function(){return t["private"]()&&!t.admin()}),t.avatar_url=u.observable(n(e.avatar_url,{size:32})),t.import_repo=function(){var e={name:t.name(),repo:t.clone_url(),repo_type:t.vcs(),description:t.description(),project_url:t.html_url(),remote_repository:t.id()},n=c("");n.attr("action",r.urls.projects_import).attr("method","POST").hide(),Object.keys(e).map(function(r){var t=c("").attr("type","hidden").attr("name",r).attr("value",e[r]);n.append(t)});var a=c("").attr("type","hidden").attr("name","csrfmiddlewaretoken").attr("value",r.csrf_token);n.append(a);var o=c("").attr("type","submit");n.append(o),c("body").append(n),n.submit()}}function i(e,r){var t=this;t.config=r||{},t.urls=r.urls||{},t.csrf_token=r.csrf_token||"",t.error=u.observable(null),t.is_syncing=u.observable(!1),t.is_ready=u.observable(!1),t.page_current=u.observable(null),t.page_next=u.observable(null),t.page_previous=u.observable(null),t.filter_by=u.observable({id:null,type:null}),t.accounts_raw=u.observableArray(),t.organizations_raw=u.observableArray(),t.filters=u.computed(function(){var e,r=[],n=t.accounts_raw(),s=t.organizations_raw();for(e in n){var i=new o(n[e],t);r.push(i)}for(e in s){var u=new a(s[e],t);r.push(u)}return r}),t.projects=u.observableArray(),u.computed(function(){var e=t.filter_by(),r=t.page_current()||t.urls["remoterepository-list"];t.page_current()||("org"===e.type&&(r=n(t.urls["remoterepository-list"],{org:e.id})),"own"===e.type&&(r=n(t.urls["remoterepository-list"],{own:e.id}))),t.error(null),c.getJSON(r).success(function(e){var r=[];t.page_next(e.next),t.page_previous(e.previous);var n;for(n in e.results){var a=new s(e.results[n],t);r.push(a)}t.projects(r)}).error(function(e){var r=e.responseJSON.detail||e.statusText;t.error({message:r})}).always(function(){t.is_ready(!0)})}).extend({deferred:!0}),t.get_organizations=function(){c.getJSON(t.urls["remoteorganization-list"]).success(function(e){t.organizations_raw(e.results)}).error(function(e){var r=e.responseJSON.detail||e.statusText;t.error({message:r})})},t.get_accounts=function(){c.getJSON(t.urls["remoteaccount-list"]).success(function(e){t.accounts_raw(e.results)}).error(function(e){var r=e.responseJSON.detail||e.statusText;t.error({message:r})})},t.sync_projects=function(){var e=t.urls.api_sync_remote_repositories;t.error(null),t.is_syncing(!0),l.trigger_task({url:e,token:t.csrf_token}).then(function(e){t.get_organizations(),t.get_accounts()}).fail(function(e){t.error(e)}).always(function(){t.is_syncing(!1)})},t.has_projects=u.computed(function(){return t.projects().length>0}),t.next_page=function(){t.page_current(t.page_next())},t.previous_page=function(){t.page_current(t.page_previous())},t.set_filter_by=function(e,r){var n=t.filter_by();n.id===e?(n.id=null,n.type=null):(n.id=e,n.type=r),t.filter_by(n),n.id&&t.page_current(null)}}var u=e("knockout"),c=e("jquery"),l=e("readthedocs/core/static-src/core/js/tasks");c(function(){var e=c("#id_repo"),r=c("#id_repo_type");e.blur(function(){var t,n=e.val();switch(!0){case/^hg/.test(n):t="hg";break;case/^bzr/.test(n):case/launchpad/.test(n):t="bzr";break;case/trunk/.test(n):case/^svn/.test(n):t="svn";break;default:case/github/.test(n):case/(^git|\.git$)/.test(n):t="git"}r.val(t)})}),i.init=function(e,r,t){var n=new i(r,t);return n.get_accounts(),n.get_organizations(),u.applyBindings(n,e),n},r.exports.ProjectImportView=i},{jquery:"jquery",knockout:"knockout","readthedocs/core/static-src/core/js/tasks":1}]},{},[]); \ No newline at end of file diff --git a/readthedocs/projects/static/projects/js/tools.js b/readthedocs/projects/static/projects/js/tools.js index 84100877be0..f65d13e1c81 100644 --- a/readthedocs/projects/static/projects/js/tools.js +++ b/readthedocs/projects/static/projects/js/tools.js @@ -1 +1 @@ -require=function e(t,n,r){function s(i,a){if(!n[i]){if(!t[i]){var l="function"==typeof require&&require;if(!a&&l)return l(i,!0);if(o)return o(i,!0);var c=new Error("Cannot find module '"+i+"'");throw c.code="MODULE_NOT_FOUND",c}var u=n[i]={exports:{}};t[i][0].call(u.exports,function(e){var n=t[i][1][e];return s(n?n:e)},u,u.exports,e,t,n,r)}return n[i].exports}for(var o="function"==typeof require&&require,i=0;i0;)e.firstChild.remove();e.appendChild(t)}var n=t.contentWindow;n.document.open(),n.document.write(this.content),n.document.close();var r=n.document.head,s=(n.document.body,null);if(r){s=n.document.createElement("base"),s.target="_parent",s.href=this.url,r.appendChild(s);for(var o=document.head.getElementsByTagName("link"),i=0;i0;)self._completeHandlers.shift()(e)}function success(resp){var type=o.type||resp&&setType(resp.getResponseHeader("Content-Type"));resp="jsonp"!==type?self.request:resp;var filteredResponse=globalSetupOptions.dataFilter(resp.responseText,type),r=filteredResponse;try{resp.responseText=r}catch(e){}if(r)switch(type){case"json":try{resp=win.JSON?win.JSON.parse(r):eval("("+r+")")}catch(err){return error(resp,"Could not parse JSON in response",err)}break;case"js":resp=eval(r);break;case"html":resp=r;break;case"xml":resp=resp.responseXML&&resp.responseXML.parseError&&resp.responseXML.parseError.errorCode&&resp.responseXML.parseError.reason?null:resp.responseXML}for(self._responseArgs.resp=resp,self._fulfilled=!0,fn(resp),self._successHandler(resp);self._fulfillmentHandlers.length>0;)resp=self._fulfillmentHandlers.shift()(resp);complete(resp)}function timedOut(){self._timedOut=!0,self.request.abort()}function error(e,t,n){for(e=self.request,self._responseArgs.resp=e,self._responseArgs.msg=t,self._responseArgs.t=n,self._erred=!0;self._errorHandlers.length>0;)self._errorHandlers.shift()(e,t,n);complete(e)}this.url="string"==typeof o?o:o.url,this.timeout=null,this._fulfilled=!1,this._successHandler=function(){},this._fulfillmentHandlers=[],this._errorHandlers=[],this._completeHandlers=[],this._erred=!1,this._responseArgs={};var self=this;fn=fn||function(){},o.timeout&&(this.timeout=setTimeout(function(){timedOut()},o.timeout)),o.success&&(this._successHandler=function(){o.success.apply(o,arguments)}),o.error&&this._errorHandlers.push(function(){o.error.apply(o,arguments)}),o.complete&&this._completeHandlers.push(function(){o.complete.apply(o,arguments)}),this.request=getRequest.call(this,success,error)}function reqwest(e,t){return new Reqwest(e,t)}function normalize(e){return e?e.replace(/\r?\n/g,"\r\n"):""}function serial(e,t){var n,r,s,o,i=e.name,a=e.tagName.toLowerCase(),l=function(e){e&&!e.disabled&&t(i,normalize(e.attributes.value&&e.attributes.value.specified?e.value:e.text))};if(!e.disabled&&i)switch(a){case"input":/reset|button|image|file/i.test(e.type)||(n=/checkbox/i.test(e.type),r=/radio/i.test(e.type),s=e.value,(!(n||r)||e.checked)&&t(i,normalize(n&&""===s?"on":s)));break;case"textarea":t(i,normalize(e.value));break;case"select":if("select-one"===e.type.toLowerCase())l(e.selectedIndex>=0?e.options[e.selectedIndex]:null);else for(o=0;e.length&&o'),c("body").append(t));var n=e.insertContent(t);c(n).show(),t.show(),c(document).click(function(e){c(e.target).closest("#embed-container").length||(c(n).remove(),t.remove())})}function s(e){var t=this;t.config=e||{},"undefined"==typeof t.config.api_host&&(t.config.api_host="https://readthedocs.org"),t.help=a.observable(null),t.error=a.observable(null),t.project=a.observable(t.config.project),t.file=a.observable(null),t.sections=a.observableArray(),a.computed(function(){var e=t.file();if(t.sections.removeAll(),e){t.help("Loading..."),t.error(null),t.section(null);var n=new i.Embed(t.config);n.page(t.project(),"latest",t.file(),function(e){t.sections.removeAll(),t.help(null),t.error(null);var n,r=[];for(n in e.sections){var s=e.sections[n];c.each(s,function(e,t){r.push({title:e,id:e})})}t.sections(r)},function(e){t.help(null),t.error("There was a problem retrieving data from the API")})}}),t.has_sections=a.computed(function(){return t.sections().length>0}),t.section=a.observable(null),t.has_section=a.computed(function(){return null!==t.section()&&""!==t.section()}),t.response=a.observable(null),a.computed(function(){var e=t.file(),n=t.section();if(null==e||null==n)return t.response(null);t.help("Loading..."),t.error(null),t.response(null),t.api_example(null);var r=new i.Embed(t.config);r.section(t.project(),"latest",t.file(),t.section(),function(e){t.help(null),t.error(null),t.api_example("var embed = Embed();\nembed.section(\n '"+t.project()+"', 'latest', '"+t.file()+"', '"+t.section()+"',\n function (section) {\n section.insertContent($('#help'));\n }\n);\n"),t.response(e)},function(e){t.help(null),t.error("There was a problem retrieving data from the API")})}),t.has_response=a.computed(function(){return null!=t.response()}),t.api_example=a.observable(null),t.show_help=function(){var e=new i.Embed(t.config);e.section("docs","latest","features/embed","Content Embedding",r)},t.show_embed=function(){new i.Embed(t.config);r(t.response())}}function o(e){var t=this;t.config=e||{},"undefined"==typeof t.config.api_host&&(t.config.api_host="https://readthedocs.org"),t.show_help=function(){var e=new i.Embed;e.section("docs","latest","business/analytics","Analytics",r)}}var i=e("./../../../../../bower_components/readthedocs-client/lib/readthedocs.js"),a=e("knockout"),l=e("jquery"),c=l;t.exports.init_embed=function(e){var t=new s(e);a.applyBindings(t,c("#tool-embed")[0])},t.exports.init_analytics=function(e){var t=new o(e);a.applyBindings(t,c("#tool-analytics")[0])}},{"./../../../../../bower_components/readthedocs-client/lib/readthedocs.js":3,jquery:"jquery",knockout:"knockout"}]},{},[]); \ No newline at end of file +require=function(){function e(t,n,r){function s(i,a){if(!n[i]){if(!t[i]){var l="function"==typeof require&&require;if(!a&&l)return l(i,!0);if(o)return o(i,!0);var c=new Error("Cannot find module '"+i+"'");throw c.code="MODULE_NOT_FOUND",c}var u=n[i]={exports:{}};t[i][0].call(u.exports,function(e){var n=t[i][1][e];return s(n?n:e)},u,u.exports,e,t,n,r)}return n[i].exports}for(var o="function"==typeof require&&require,i=0;i0;)e.firstChild.remove();e.appendChild(t)}var n=t.contentWindow;n.document.open(),n.document.write(this.content),n.document.close();var r=n.document.head,s=(n.document.body,null);if(r){s=n.document.createElement("base"),s.target="_parent",s.href=this.url,r.appendChild(s);for(var o=document.head.getElementsByTagName("link"),i=0;i0;)self._completeHandlers.shift()(e)}function success(resp){var type=o.type||resp&&setType(resp.getResponseHeader("Content-Type"));resp="jsonp"!==type?self.request:resp;var filteredResponse=globalSetupOptions.dataFilter(resp.responseText,type),r=filteredResponse;try{resp.responseText=r}catch(e){}if(r)switch(type){case"json":try{resp=win.JSON?win.JSON.parse(r):eval("("+r+")")}catch(err){return error(resp,"Could not parse JSON in response",err)}break;case"js":resp=eval(r);break;case"html":resp=r;break;case"xml":resp=resp.responseXML&&resp.responseXML.parseError&&resp.responseXML.parseError.errorCode&&resp.responseXML.parseError.reason?null:resp.responseXML}for(self._responseArgs.resp=resp,self._fulfilled=!0,fn(resp),self._successHandler(resp);self._fulfillmentHandlers.length>0;)resp=self._fulfillmentHandlers.shift()(resp);complete(resp)}function timedOut(){self._timedOut=!0,self.request.abort()}function error(e,t,n){for(e=self.request,self._responseArgs.resp=e,self._responseArgs.msg=t,self._responseArgs.t=n,self._erred=!0;self._errorHandlers.length>0;)self._errorHandlers.shift()(e,t,n);complete(e)}this.url="string"==typeof o?o:o.url,this.timeout=null,this._fulfilled=!1,this._successHandler=function(){},this._fulfillmentHandlers=[],this._errorHandlers=[],this._completeHandlers=[],this._erred=!1,this._responseArgs={};var self=this;fn=fn||function(){},o.timeout&&(this.timeout=setTimeout(function(){timedOut()},o.timeout)),o.success&&(this._successHandler=function(){o.success.apply(o,arguments)}),o.error&&this._errorHandlers.push(function(){o.error.apply(o,arguments)}),o.complete&&this._completeHandlers.push(function(){o.complete.apply(o,arguments)}),this.request=getRequest.call(this,success,error)}function reqwest(e,t){return new Reqwest(e,t)}function normalize(e){return e?e.replace(/\r?\n/g,"\r\n"):""}function serial(e,t){var n,r,s,o,i=e.name,a=e.tagName.toLowerCase(),l=function(e){e&&!e.disabled&&t(i,normalize(e.attributes.value&&e.attributes.value.specified?e.value:e.text))};if(!e.disabled&&i)switch(a){case"input":/reset|button|image|file/i.test(e.type)||(n=/checkbox/i.test(e.type),r=/radio/i.test(e.type),s=e.value,(!(n||r)||e.checked)&&t(i,normalize(n&&""===s?"on":s)));break;case"textarea":t(i,normalize(e.value));break;case"select":if("select-one"===e.type.toLowerCase())l(e.selectedIndex>=0?e.options[e.selectedIndex]:null);else for(o=0;e.length&&o'),c("body").append(t));var n=e.insertContent(t);c(n).show(),t.show(),c(document).click(function(e){c(e.target).closest("#embed-container").length||(c(n).remove(),t.remove())})}function s(e){var t=this;t.config=e||{},"undefined"==typeof t.config.api_host&&(t.config.api_host="https://readthedocs.org"),t.help=a.observable(null),t.error=a.observable(null),t.project=a.observable(t.config.project),t.file=a.observable(null),t.sections=a.observableArray(),a.computed(function(){var e=t.file();if(t.sections.removeAll(),e){t.help("Loading..."),t.error(null),t.section(null);var n=new i.Embed(t.config);n.page(t.project(),"latest",t.file(),function(e){t.sections.removeAll(),t.help(null),t.error(null);var n,r=[];for(n in e.sections){var s=e.sections[n];c.each(s,function(e,t){r.push({title:e,id:e})})}t.sections(r)},function(e){t.help(null),t.error("There was a problem retrieving data from the API")})}}),t.has_sections=a.computed(function(){return t.sections().length>0}),t.section=a.observable(null),t.has_section=a.computed(function(){return null!==t.section()&&""!==t.section()}),t.response=a.observable(null),a.computed(function(){var e=t.file(),n=t.section();if(null==e||null==n)return t.response(null);t.help("Loading..."),t.error(null),t.response(null),t.api_example(null);var r=new i.Embed(t.config);r.section(t.project(),"latest",t.file(),t.section(),function(e){t.help(null),t.error(null),t.api_example("var embed = Embed();\nembed.section(\n '"+t.project()+"', 'latest', '"+t.file()+"', '"+t.section()+"',\n function (section) {\n section.insertContent($('#help'));\n }\n);\n"),t.response(e)},function(e){t.help(null),t.error("There was a problem retrieving data from the API")})}),t.has_response=a.computed(function(){return null!=t.response()}),t.api_example=a.observable(null),t.show_help=function(){var e=new i.Embed(t.config);e.section("docs","latest","features/embed","Content Embedding",r)},t.show_embed=function(){new i.Embed(t.config);r(t.response())}}function o(e){var t=this;t.config=e||{},"undefined"==typeof t.config.api_host&&(t.config.api_host="https://readthedocs.org"),t.show_help=function(){var e=new i.Embed;e.section("docs","latest","business/analytics","Analytics",r)}}var i=e("./../../../../../bower_components/readthedocs-client/lib/readthedocs.js"),a=e("knockout"),l=e("jquery"),c=l;t.exports.init_embed=function(e){var t=new s(e);a.applyBindings(t,c("#tool-embed")[0])},t.exports.init_analytics=function(e){var t=new o(e);a.applyBindings(t,c("#tool-analytics")[0])}},{"./../../../../../bower_components/readthedocs-client/lib/readthedocs.js":3,jquery:"jquery",knockout:"knockout"}]},{},[]); \ No newline at end of file From f4e645dcd5186459b70403f4ead15673f104611c Mon Sep 17 00:00:00 2001 From: Anthony Johnson Date: Mon, 26 Mar 2018 18:46:06 -0600 Subject: [PATCH 144/190] Release 2.3.4 --- CHANGELOG.rst | 24 +++++++++++++++++++++--- setup.cfg | 2 +- tasks.py | 18 ++++++++++-------- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d1ca9fb7854..56848252cb8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,9 +1,27 @@ -Version 2.3.3 +.. _version-2.3.4: + +Version 2.3.4 ------------- -TBD +* Release for static assets + +Version 2.3.3 +------------- -.. _version-2.3.2: +* `@davidfischer `_: Fix linting errors in tests (`#3855 `_) +* `@humitos `_: Fix linting issues (`#3838 `_) +* `@humitos `_: Update instance and model when `record_as_success` (`#3831 `_) +* `@ericholscher `_: Reorder GSOC projects, and note priority order (`#3823 `_) +* `@agjohnson `_: Add temporary method for skipping submodule checkout (`#3821 `_) +* `@davidfischer `_: Remove pinned CSS Select version (`#3813 `_) +* `@humitos `_: Use readthedocs-common to share linting files accross different repos (`#3808 `_) +* `@davidfischer `_: Use JSONP for sustainability API (`#3789 `_) +* `@humitos `_: Define useful celery beat task for development (`#3762 `_) +* `@humitos `_: Auto-generate conf.py compatible with Py2 and Py3 (`#3745 `_) +* `@humitos `_: Task to remove orphan symlinks (`#3543 `_) +* `@stsewd `_: Fix regex for public bitbucket repo (`#3533 `_) +* `@humitos `_: Documentation for RTD context sent to the Sphinx theme (`#3490 `_) +* `@stsewd `_: Show link to docs on a build (`#3446 `_) Version 2.3.2 ------------- diff --git a/setup.cfg b/setup.cfg index 4a14464c135..5eb8d7b3625 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = readthedocs -version = 2.3.3 +version = 2.3.4 license = MIT description = Read the Docs builds and hosts documentation author = Read the Docs, Inc diff --git a/tasks.py b/tasks.py index 70db0d630f3..b4eef5c5eaa 100644 --- a/tasks.py +++ b/tasks.py @@ -12,7 +12,7 @@ @task -def prepare(ctx, version): +def prepare(ctx, version, since): """ Prepare the next release version by updating files. @@ -41,10 +41,11 @@ def prepare(ctx, version): config.write(configfile) print('Installing github-changelog') - # Get last modified date from Git instead of assuming the file metadata is - # correct. This can change depending on git reset, etc. - git_log = ctx.run('git log -1 --format="%ad" -- CHANGELOG.rst') - last_modified = parse(git_log.stdout.strip()).strftime('%Y-%m-%d') + if not since: + # Get last modified date from Git instead of assuming the file metadata is + # correct. This can change depending on git reset, etc. + git_log = ctx.run('git log -1 --format="%ad" -- CHANGELOG.rst') + since = parse(git_log.stdout.strip()).strftime('%Y-%m-%d') # Install and run ctx.run('npm install git+https://github.com/agjohnson/github-changelog.git') changelog_path = os.path.join(os.path.dirname(__file__), 'CHANGELOG.rst') @@ -62,15 +63,16 @@ def prepare(ctx, version): '{bin_path}/gh-changelog ' '-o rtfd -r readthedocs.org ' '--file {changelog_path} ' - '--since {last_modified} ' + '--since {since} ' '--template {template_path} ' - '--header "Version {version}"' + '--header "Version {version}" ' + '--merged' ).format( bin_path=bin_path, version=version, template_path=template_path, changelog_path=changelog_path, - last_modified=last_modified, + since=since, ) # yapf: disable try: token = os.environ['GITHUB_TOKEN'] From f2ac3cc3aa651115bfd9b987a97708e2f76a6519 Mon Sep 17 00:00:00 2001 From: David Fischer Date: Mon, 26 Mar 2018 21:07:13 -0700 Subject: [PATCH 145/190] Another CORS hotfix for the sustainability API --- readthedocs/core/signals.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/readthedocs/core/signals.py b/readthedocs/core/signals.py index a3e229656f3..aa2a30936c0 100644 --- a/readthedocs/core/signals.py +++ b/readthedocs/core/signals.py @@ -20,6 +20,7 @@ '/api/v2/footer_html', '/api/v2/search', '/api/v2/docsearch', + '/api/v2/sustainability', ] @@ -46,6 +47,10 @@ def decide_if_cors(sender, request, **kwargs): # pylint: disable=unused-argumen if request.path_info.startswith(url): valid_url = True + # Don't do domain checking for this API for now + if request.path_info.startswith('/api/v2/sustainability'): + return True + if valid_url: project_slug = request.GET.get('project', None) try: From 54cc39f166704720c6f42b163609b004c4a3d8ed Mon Sep 17 00:00:00 2001 From: Raju Jha Date: Mon, 26 Mar 2018 17:27:34 +0530 Subject: [PATCH 146/190] written guide for elasticsearch --- docs/guides/run-elasticsearch.rst | 84 +++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 docs/guides/run-elasticsearch.rst diff --git a/docs/guides/run-elasticsearch.rst b/docs/guides/run-elasticsearch.rst new file mode 100644 index 00000000000..64e0ce67621 --- /dev/null +++ b/docs/guides/run-elasticsearch.rst @@ -0,0 +1,84 @@ +Enabling Elasticsearch on the local server +========================================== + +Read the Docs has been using Elasticsearch which is a platform for distributed search and analysis of data in real time. To enable the search feature on your local installation, you need to install the elasticsearch locally and run the Elastic server. + +Installation has been mainly divided into following steps. + +1. Installing Java +------------------ + +First, you need to a Java Runtime Environment (JRE) because Elasticsearch is written in the Java programming lanaguage and requires Java 7 or higher. + +Installing OpenJDK 8:: + + (READTHEDOCS)$ sudo add-apt-repository ppa:openjdk-r/ppa + (READTHEDOCS)$ sudo apt-get update + (READTHEDOCS)$ sudo apt-get install openjdk-8-jre + +To verify the installation,:: + + (READTHEDOCS)$ java -version + +The result should be something like this:: + + openjdk version "1.8.0_151" + OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-0ubuntu0.16.04.2-b12) + OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode) + + +2. Downloading and installing Elasticsearch +------------------------------------------- + +Elasticsearch can be downloaded directly from elastic.co in zip, tar.gz, deb, or rpm packages. For Ubuntu, it's best to use the deb (Debian) package which will install everything you need to run Elasticsearch. + +RTD currently uses elasticsearch 1.x which can be easily downloaded and installed from the official website (http://elastic.co). + +Download it in a directory parallel to where the readthedocs.org project has been stored.:: + + (READTHEDOCS)$ wget https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.3.8.tar.gz + (READTHEDOCS)$ tar -xzf elasticsearch-1.3.8.tar.gz + (READTHEDOCS)$ cd elasticsearch-1.3.8 + +Your directory structure after the above command would be: + +READTHEDOCS + |- readthedocs.org + |- elasticsearch-1.3.8 + +3. Running Elasticsearch from command line +------------------------------------------ + +Goto elasticsearch home directory.:: + + (READTHEDOCS/elasticsearch-1.3.8)$ cd elasticsearch-1.3.8/bin/ + (READTHEDOCS/elasticsearch-1.3.8/bin)$ ./elasticsearch + +To verify run:: + + (READTHEDOCS/elasticsearch-1.3.8/bin)$ curl http://localhost:9200 + +You should get something like: + +``{ + status: 200, + name: "Amina Synge", + version: { + number: "1.3.8", + build_hash: "475733ee0837fba18c00c3ee76cd49a08755550c", + build_timestamp: "2015-02-11T14:45:42Z", + build_snapshot: false, + lucene_version: "4.9" + }, + tagline: "You Know, for Search" +} +`` + +4. Index the data available at RTD database +------------------------------------------- + +In order to search through the RTD database, you need to index it into the elasticsearch index.:: + + (READTHEDOCS/readthedocs.org)$ python manage.py reindex_elasticsearch + +You are ready to go! From 84aea29b6d7fe63c255922c584adc9dd63bdabd9 Mon Sep 17 00:00:00 2001 From: Raju Jha Date: Tue, 27 Mar 2018 14:57:20 +0530 Subject: [PATCH 147/190] added links for installation of JDK --- docs/guides/run-elasticsearch.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/guides/run-elasticsearch.rst b/docs/guides/run-elasticsearch.rst index 64e0ce67621..fb3145a5ae5 100644 --- a/docs/guides/run-elasticsearch.rst +++ b/docs/guides/run-elasticsearch.rst @@ -1,3 +1,4 @@ +========================================== Enabling Elasticsearch on the local server ========================================== From 53f4124693e4e60bc64440bfbfc8fd2d53e710a9 Mon Sep 17 00:00:00 2001 From: Raju Jha Date: Tue, 27 Mar 2018 15:00:34 +0530 Subject: [PATCH 148/190] updated official links for JDK --- docs/guides/run-elasticsearch.rst | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/docs/guides/run-elasticsearch.rst b/docs/guides/run-elasticsearch.rst index fb3145a5ae5..b43945e2e1a 100644 --- a/docs/guides/run-elasticsearch.rst +++ b/docs/guides/run-elasticsearch.rst @@ -9,15 +9,9 @@ Installation has been mainly divided into following steps. 1. Installing Java ------------------ -First, you need to a Java Runtime Environment (JRE) because Elasticsearch is written in the Java programming lanaguage and requires Java 7 or higher. +Elasticsearch requires JAVA 8 or later. Use .. _Oracle official documentation:http://www.oracle.com/technetwork/java/javase/downloads/index.html or opensource distribution like .. _OpenJDK:http://openjdk.java.net/install/ -Installing OpenJDK 8:: - - (READTHEDOCS)$ sudo add-apt-repository ppa:openjdk-r/ppa - (READTHEDOCS)$ sudo apt-get update - (READTHEDOCS)$ sudo apt-get install openjdk-8-jre - -To verify the installation,:: +After installing java, verify the installation by,:: (READTHEDOCS)$ java -version From ca6bcd1ad14992d06402d4ab8bea53e8368ccaa7 Mon Sep 17 00:00:00 2001 From: Raju Jha Date: Tue, 27 Mar 2018 16:52:24 +0530 Subject: [PATCH 149/190] corrected typo in features.rst --- docs/features.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features.rst b/docs/features.rst index 5d3fd2358c4..f0ceb1336be 100644 --- a/docs/features.rst +++ b/docs/features.rst @@ -60,7 +60,7 @@ When you build your project on RTD, we automatically build a PDF of your project Search ------ -We provide full-text search across all of the pages of documentation hosted on our site. This uses the excellent Haystack project and Solr as the search backend. We hope to be integrating this into the site more fully in the future. +We provide full-text search across all of the pages of documentation hosted on our site. This uses the excellent Haystack project and Elasticsearch as the search backend. We hope to be integrating this into the site more fully in the future. Alternate Domains ----------------- From f10e7459e4c76f4c478cf61342c9cb4ea0f97cd2 Mon Sep 17 00:00:00 2001 From: Raju Jha Date: Tue, 27 Mar 2018 16:55:37 +0530 Subject: [PATCH 150/190] deleted unintended file --- docs/guides/run-elasticsearch.rst | 79 ------------------------------- 1 file changed, 79 deletions(-) delete mode 100644 docs/guides/run-elasticsearch.rst diff --git a/docs/guides/run-elasticsearch.rst b/docs/guides/run-elasticsearch.rst deleted file mode 100644 index b43945e2e1a..00000000000 --- a/docs/guides/run-elasticsearch.rst +++ /dev/null @@ -1,79 +0,0 @@ -========================================== -Enabling Elasticsearch on the local server -========================================== - -Read the Docs has been using Elasticsearch which is a platform for distributed search and analysis of data in real time. To enable the search feature on your local installation, you need to install the elasticsearch locally and run the Elastic server. - -Installation has been mainly divided into following steps. - -1. Installing Java ------------------- - -Elasticsearch requires JAVA 8 or later. Use .. _Oracle official documentation:http://www.oracle.com/technetwork/java/javase/downloads/index.html or opensource distribution like .. _OpenJDK:http://openjdk.java.net/install/ - -After installing java, verify the installation by,:: - - (READTHEDOCS)$ java -version - -The result should be something like this:: - - openjdk version "1.8.0_151" - OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-0ubuntu0.16.04.2-b12) - OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode) - - -2. Downloading and installing Elasticsearch -------------------------------------------- - -Elasticsearch can be downloaded directly from elastic.co in zip, tar.gz, deb, or rpm packages. For Ubuntu, it's best to use the deb (Debian) package which will install everything you need to run Elasticsearch. - -RTD currently uses elasticsearch 1.x which can be easily downloaded and installed from the official website (http://elastic.co). - -Download it in a directory parallel to where the readthedocs.org project has been stored.:: - - (READTHEDOCS)$ wget https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.3.8.tar.gz - (READTHEDOCS)$ tar -xzf elasticsearch-1.3.8.tar.gz - (READTHEDOCS)$ cd elasticsearch-1.3.8 - -Your directory structure after the above command would be: - -READTHEDOCS - |- readthedocs.org - |- elasticsearch-1.3.8 - -3. Running Elasticsearch from command line ------------------------------------------- - -Goto elasticsearch home directory.:: - - (READTHEDOCS/elasticsearch-1.3.8)$ cd elasticsearch-1.3.8/bin/ - (READTHEDOCS/elasticsearch-1.3.8/bin)$ ./elasticsearch - -To verify run:: - - (READTHEDOCS/elasticsearch-1.3.8/bin)$ curl http://localhost:9200 - -You should get something like: - -``{ - status: 200, - name: "Amina Synge", - version: { - number: "1.3.8", - build_hash: "475733ee0837fba18c00c3ee76cd49a08755550c", - build_timestamp: "2015-02-11T14:45:42Z", - build_snapshot: false, - lucene_version: "4.9" - }, - tagline: "You Know, for Search" -} -`` - -4. Index the data available at RTD database -------------------------------------------- - -In order to search through the RTD database, you need to index it into the elasticsearch index.:: - - (READTHEDOCS/readthedocs.org)$ python manage.py reindex_elasticsearch - -You are ready to go! From 4e43cafada7f3c11ab6f949b6f37524a8731738c Mon Sep 17 00:00:00 2001 From: Bernat Gabor Date: Wed, 28 Mar 2018 09:46:44 +0100 Subject: [PATCH 151/190] add description for tox tasks For example: default environments: py27 -> run test suite for the application with python2.7 py36 -> run test suite for the application with python3.6 lint -> run linter (prospector) to ensure the source code corresponds to our coding standards docs -> build readthedocs documentation additional environments: coverage -> run test suite with code coverage for the application with /usr/bin/python eslint -> run the JavaScript linter (requires gulp installed) --- tox.ini | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tox.ini b/tox.ini index 7610f818657..e4ea2e3add4 100644 --- a/tox.ini +++ b/tox.ini @@ -1,4 +1,5 @@ [tox] +minversion=2.9.0 envlist = py{27,36},lint,docs skipsdist = True @@ -8,6 +9,7 @@ python = 3.6: py36 [testenv] +description = run test suite for the application with {basepython} setenv = PYTHONPATH={toxinidir}/readthedocs:{toxinidir} DJANGO_SETTINGS_MODULE=readthedocs.settings.test @@ -19,11 +21,13 @@ commands = py.test {posargs} [testenv:docs] +description = build readthedocs documentation changedir = {toxinidir}/docs commands = sphinx-build -b html -d {envtmpdir}/doctrees . {envtmpdir}/html [testenv:lint] +description = run linter (prospector) to ensure the source code corresponds to our coding standards deps = -r{toxinidir}/requirements/lint.txt commands = prospector \ @@ -36,10 +40,12 @@ commands = --die-on-tool-error {posargs} [testenv:eslint] +description = run the JavaScript linter (requires gulp installed) commands = gulp lint [testenv:coverage] +description = run test suite with code coverage for the application with {basepython} deps = -r{toxinidir}/requirements/testing.txt pytest-cov From 216578ca567e3e9504eb4c5201fca7c2e2dabadc Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Wed, 28 Mar 2018 17:36:54 +0200 Subject: [PATCH 152/190] templates: mark a few more strings for translations --- .../projects/integration_webhook_detail.html | 2 +- readthedocs/templates/projects/onboard_detail.html | 4 ++-- readthedocs/templates/projects/onboard_import.html | 9 ++++++--- .../templates/projects/project_dashboard_base.html | 14 ++++++++------ readthedocs/templates/projects/project_users.html | 2 +- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/readthedocs/templates/projects/integration_webhook_detail.html b/readthedocs/templates/projects/integration_webhook_detail.html index 26b00864b12..485bc894b09 100644 --- a/readthedocs/templates/projects/integration_webhook_detail.html +++ b/readthedocs/templates/projects/integration_webhook_detail.html @@ -72,7 +72,7 @@

          {% endif %} -

          Recent Activity

          +

          {% trans "Recent Activity" %}