base.html 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. {% load i18n static tz %}
  2. {% get_current_language as LANGUAGE_CODE %}
  3. {% get_current_language_bidi as LANGUAGE_BIDI %}
  4. <!DOCTYPE html>
  5. <html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
  6. <head>
  7. <title>{% block title %}Home{% endblock %} | ArchiveBox</title>
  8. {% block blockbots %}
  9. <meta name="robots" content="NONE,NOARCHIVE">
  10. {% endblock %}
  11. <link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}">
  12. {% block extrastyle %}
  13. <style>
  14. #upgrade-banner {
  15. position: fixed;
  16. right: 20px;
  17. bottom: 20px;
  18. background-color: #f8f8f8;
  19. color: #333333;
  20. border: 2px solid #772948;
  21. padding: 10px 20px;
  22. z-index: 1000;
  23. text-align: center;
  24. }
  25. #dismiss-btn {
  26. background: #aa1e55;
  27. color: white;
  28. cursor: pointer;
  29. }
  30. </style>
  31. {% endblock %}
  32. {% if LANGUAGE_BIDI %}
  33. <link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}">
  34. {% endif %}
  35. {% block responsive %}
  36. <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0">
  37. <link rel="stylesheet" type="text/css" href="{% static "admin/css/responsive.css" %}">
  38. {% if LANGUAGE_BIDI %}
  39. <link rel="stylesheet" type="text/css" href="{% static "admin/css/responsive_rtl.css" %}">
  40. {% endif %}
  41. {% endblock %}
  42. <script
  43. src="{% static 'jquery-3.7.1.slim.min.js' %}"
  44. integrity="sha256-kmHvs0B+OpCW5GVHUNjv9rOmY0IvSIRcf7zGUDTDQM8="
  45. crossorigin="anonymous"></script>
  46. <link href="{% static 'select2.min.css' %}" rel="stylesheet"/>
  47. <script src="{% static 'select2.min.js' %}"></script>
  48. <link rel="stylesheet" type="text/css" href="{% static "admin.css" %}">
  49. <script>
  50. function selectSnapshotListView(e) {
  51. e && e.stopPropagation()
  52. e && e.preventDefault()
  53. console.log('Switching to Snapshot list view...')
  54. localStorage.setItem('preferred_snapshot_view_mode', 'list')
  55. window.location = "{% url 'admin:core_snapshot_changelist' %}" + document.location.search
  56. return false
  57. }
  58. function selectSnapshotGridView(e) {
  59. e && e.stopPropagation()
  60. e && e.preventDefault()
  61. console.log('Switching to Snapshot grid view...')
  62. localStorage.setItem('preferred_snapshot_view_mode', 'grid')
  63. window.location = "{% url 'admin:grid' %}" + document.location.search
  64. return false
  65. }
  66. const preferred_view = localStorage.getItem('preferred_snapshot_view_mode') || 'unset'
  67. const current_view = (
  68. window.location.pathname === "{% url 'admin:core_snapshot_changelist' %}"
  69. ? 'list'
  70. : 'grid')
  71. console.log('Preferred snapshot view is:', preferred_view, 'Current view mode is:', current_view)
  72. if (preferred_view === 'grid' && current_view !== 'grid') {
  73. selectSnapshotGridView()
  74. }
  75. </script>
  76. {% block extrahead %}{% endblock %}
  77. </head>
  78. <body class="{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}" data-admin-utc-offset="{% now "Z" %}">
  79. {% include 'progressbar.html' %}
  80. <div id="container">
  81. {% if not is_popup %}
  82. <div id="header">
  83. <div id="branding">
  84. <h1 id="site-name">
  85. <a href="{% url 'Home' %}">
  86. <img src="{% static 'archive.png' %}" id="logo">
  87. ArchiveBox
  88. </a>
  89. </h1>
  90. </div>
  91. {% block usertools %}
  92. {% if has_permission %}
  93. {% include 'navigation.html' %}
  94. {% endif %}
  95. {% endblock %}
  96. {% block nav-global %}{% endblock %}
  97. </div>
  98. {% block breadcrumbs %}
  99. <div class="breadcrumbs">
  100. <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
  101. {% if title %} &rsaquo; {{ title }}{% endif %}
  102. </div>
  103. {% endblock %}
  104. {% endif %}
  105. {% block messages %}
  106. {% if messages %}
  107. <ul class="messagelist">
  108. {% for message in messages %}
  109. <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message|capfirst }}</li>
  110. {% endfor %}
  111. </ul>
  112. {% endif %}
  113. {% endblock messages %}
  114. <div id="content" class="{% block coltype %}colM{% endblock %}">
  115. {% if opts.model_name == 'snapshot' and cl %}
  116. <small id="snapshot-view-mode">
  117. <a href="#list" title="List view" id="snapshot-view-list">☰</a> |
  118. <a href="#grid" title="Grid view" id="snapshot-view-grid" style="letter-spacing: -.4em;">⣿⣿</a>
  119. </small>
  120. {% endif %}
  121. {% block pretitle %}{% endblock %}
  122. {% block content_title %}{# {% if title %}<h1>{{ title }}</h1>{% endif %} #}{% endblock %}
  123. {% block content %}
  124. {% block object-tools %}{% endblock %}
  125. {{ content }}
  126. {% endblock %}
  127. {% block sidebar %}{% endblock %}
  128. <br class="clear">
  129. </div>
  130. {% block footer %}<div id="footer"></div>{% endblock %}
  131. </div>
  132. {% comment %}
  133. {% if user.is_authenticated and user.is_superuser and CAN_UPGRADE %}
  134. <script>
  135. if (!localStorage.getItem("bannerDismissed")) {
  136. const upgradeVersionTag = "{{VERSIONS_AVAILABLE.recommended_version.tag_name}}"
  137. const upgradeVersionURL = "{{VERSIONS_AVAILABLE.recommended_version.html_url}}"
  138. const currentVersionTag = "{{VERSION}}"
  139. const currentVersionURL = "{{VERSIONS_AVAILABLE.recommended_version.html_url}}"
  140. createBanner(currentVersionTag, currentVersionURL, upgradeVersionTag, upgradeVersionURL)
  141. }
  142. function createBanner(currentVersionTag, currentVersionURL, upgradeVersionTag, upgradeVersionURL) {
  143. const banner = document.createElement('div')
  144. banner.setAttribute('id', 'upgrade-banner');
  145. banner.innerHTML = `
  146. <p>There's a new version of ArchiveBox available!</p>
  147. Your version: <a href=${currentVersionURL}>${currentVersionTag}</a> | New version: <a href=${upgradeVersionURL}>${upgradeVersionTag}</a>
  148. <p>
  149. <a href=https://github.com/ArchiveBox/ArchiveBox/wiki/Upgrading-or-Merging-Archives>Upgrade Instructions</a> | <a href=https://github.com/ArchiveBox/ArchiveBox/releases>Changelog</a> | <a href=https://github.com/ArchiveBox/ArchiveBox/wiki/Roadmap>Roadmap</a>
  150. </p>
  151. <button id="dismiss-btn">Dismiss</button>
  152. `
  153. document.body.appendChild(banner);
  154. const dismissButton = document.querySelector("#dismiss-btn")
  155. if (dismissButton) {
  156. dismissButton.addEventListener("click", dismissBanner)
  157. }
  158. }
  159. function dismissBanner() {
  160. const banner = document.getElementById("upgrade-banner")
  161. banner.style.display = "none"
  162. localStorage.setItem("bannerDismissed", "true")
  163. }
  164. </script>
  165. {% endif %}
  166. {% endcomment %}
  167. <script>
  168. $ = django.jQuery;
  169. $.fn.reverse = [].reverse;
  170. // hide images that fail to load
  171. document.querySelector('body').addEventListener('error', function (e) {
  172. e.target.style.opacity = 0;
  173. }, true)
  174. // setup timezone
  175. {% get_current_timezone as TIME_ZONE %}
  176. window.TIME_ZONE = '{{TIME_ZONE}}'
  177. window.setCookie = function(name, value, days) {
  178. let expires = ""
  179. if (days) {
  180. const date = new Date()
  181. date.setTime(date.getTime() + (days*24*60*60*1000))
  182. expires = "; expires=" + date.toUTCString()
  183. }
  184. document.cookie = name + "=" + (value || "") + expires + "; path=/"
  185. }
  186. function setTimeOffset() {
  187. if (window.GMT_OFFSET) return
  188. window.GMT_OFFSET = -(new Date).getTimezoneOffset()
  189. window.setCookie('GMT_OFFSET', window.GMT_OFFSET, 365)
  190. }
  191. // change the admin actions button from a dropdown to buttons across
  192. function fix_actions() {
  193. const container = $('div.actions')
  194. // too many actions to turn into buttons
  195. if (container.find('select[name=action] option').length >= 11) return
  196. // hide the empty default option thats just a placeholder with no value
  197. container.find('label:nth-child(1), button[value=0]').hide()
  198. const buttons = $('<div></div>')
  199. .insertAfter('div.actions button[type=submit]')
  200. .css('display', 'inline')
  201. .addClass('class', 'action-buttons');
  202. // for each action in the dropdown, turn it into a button instead
  203. container.find('select[name=action] option:gt(0)').each(function () {
  204. const action_type = this.value
  205. $('<button>')
  206. .attr('type', 'button')
  207. .attr('name', action_type)
  208. .addClass('button')
  209. .text(this.text)
  210. .click(function (e) {
  211. e.preventDefault()
  212. e.stopPropagation()
  213. const num_selected = document.querySelector('.action-counter').innerText.split(' ')[0]
  214. if (action_type === 'overwrite_snapshots') {
  215. const message = (
  216. 'Are you sure you want to re-archive (overwrite) ' + num_selected + ' Snapshots?\n\n' +
  217. 'This will delete all previously saved files from these Snapshots and re-archive them from scratch.\n\n'
  218. )
  219. if (!window.confirm(message)) return false
  220. }
  221. if (action_type === 'delete_snapshots') {
  222. const message = (
  223. 'Are you sure you want to permanently delete ' + num_selected + ' Snapshots?\n\n' +
  224. 'They will be removed from your index, and all their Snapshot content on disk will be permanently deleted.'
  225. )
  226. if (!window.confirm(message)) return false
  227. }
  228. // select the action button from the dropdown
  229. container.find('select[name=action]')
  230. .find('[selected]').removeAttr('selected').end()
  231. .find('[value=' + action_type + ']').attr('selected', 'selected').click()
  232. // click submit & replace the archivebox logo with a spinner
  233. $('#changelist-form button[name="index"]').click()
  234. document.querySelector('#logo').outerHTML = '<div class="loader"></div>'
  235. return false
  236. })
  237. .appendTo(buttons)
  238. })
  239. console.log('Converted', buttons.children().length, 'admin actions from dropdown to buttons')
  240. jQuery('select[multiple]').select2();
  241. }
  242. function fixInlineAddRow() {
  243. $('#id_snapshottag-MAX_NUM_FORMS').val('1000')
  244. $('.add-row').show()
  245. }
  246. function setupSnapshotGridListToggle() {
  247. $("#snapshot-view-list").click(selectSnapshotListView)
  248. $("#snapshot-view-grid").click(selectSnapshotGridView)
  249. $('#changelist-form .card input:checkbox').change(function() {
  250. if ($(this).is(':checked'))
  251. $(this).parents('.card').addClass('selected-card')
  252. else
  253. $(this).parents('.card').removeClass('selected-card')
  254. })
  255. };
  256. function selectSnapshotIfHotlinked() {
  257. // if we arrive at the index with a url like ??id__startswith=...
  258. // we were hotlinked here with the intention of making it easy for the user to perform some
  259. // actions on the given snapshot. therefore we should preselect the snapshot to save them a click
  260. if (window.location.search.startsWith('?')) {
  261. const result_checkboxes = [...document.querySelectorAll('#result_list .action-checkbox input[type=checkbox]')]
  262. if (result_checkboxes.length === 1) {
  263. result_checkboxes[0].click()
  264. }
  265. }
  266. }
  267. $(document).ready(function() {
  268. fix_actions()
  269. fixInlineAddRow()
  270. setupSnapshotGridListToggle()
  271. setTimeOffset()
  272. selectSnapshotIfHotlinked()
  273. })
  274. </script>
  275. </body>
  276. </html>