diff --git a/package.json b/package.json --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "ansi_up": "^4.0.3", "bootstrap": "^4.3.1", "bootstrap-year-calendar-bs4": "^1.0.0", + "chosen-js": "^1.8.7", "clipboard": "^2.0.4", "core-js": "^3.1.4", "d3": "^5.9.7", diff --git a/swh/web/assets/config/webpack.config.development.js b/swh/web/assets/config/webpack.config.development.js --- a/swh/web/assets/config/webpack.config.development.js +++ b/swh/web/assets/config/webpack.config.development.js @@ -302,6 +302,15 @@ outputPath: 'fonts/' } }] + }, { + test: /\.png$/, + use: [{ + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: 'img/thirdParty/' + } + }] } ], // tell webpack to not parse minified pdfjs file to speedup build process diff --git a/swh/web/assets/src/bundles/browse/content.css b/swh/web/assets/src/bundles/browse/content.css --- a/swh/web/assets/src/bundles/browse/content.css +++ b/swh/web/assets/src/bundles/browse/content.css @@ -21,3 +21,32 @@ .swh-content svg { max-width: 100%; } + +.chosen-container { + color: #444; +} + +.chosen-container .chosen-single div b { + margin-top: 2px; + filter: brightness(0%); +} + +.chosen-container .chosen-single { + height: 31px; + line-height: 1.5; + border-radius: 0px; + background-color: #f4f4f4; + border-color: #ddd; + background-image:none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + font-weight: 400; + font-size: 14px; + padding-top: 4px; + padding-bottom: 4px; +} + +.chosen-container .chosen-single:hover { + background-color: #e7e7e7; +} diff --git a/swh/web/assets/src/bundles/browse/origin-search.js b/swh/web/assets/src/bundles/browse/origin-search.js --- a/swh/web/assets/src/bundles/browse/origin-search.js +++ b/swh/web/assets/src/bundles/browse/origin-search.js @@ -43,7 +43,7 @@ table.append(tableRow); // get async latest visit snapshot and update visit status icon let latestSnapshotUrl = Urls.api_1_origin_visit_latest(origin.url); - latestSnapshotUrl += "?require_snapshot=true"; + latestSnapshotUrl += '?require_snapshot=true'; fetch(latestSnapshotUrl) .then(response => response.json()) .then(data => { diff --git a/swh/web/assets/src/bundles/vendors/index.js b/swh/web/assets/src/bundles/vendors/index.js --- a/swh/web/assets/src/bundles/vendors/index.js +++ b/swh/web/assets/src/bundles/vendors/index.js @@ -31,6 +31,12 @@ import 'datatables.net-responsive-bs4/css/responsive.bootstrap4.css'; import './datatables.css'; +// chosen-js +import 'chosen-js'; +import 'chosen-js/chosen.min.css'; +import 'chosen-js/chosen-sprite.png'; +import 'chosen-js/chosen-sprite@2x.png'; + // iframe-resizer import 'iframe-resizer'; diff --git a/swh/web/browse/views/content.py b/swh/web/browse/views/content.py --- a/swh/web/browse/views/content.py +++ b/swh/web/browse/views/content.py @@ -14,7 +14,7 @@ from swh.model.hashutil import hash_to_hex -from swh.web.common import query, service +from swh.web.common import query, service, highlightjs from swh.web.common.utils import ( reverse, gen_path_info, swh_object_icons ) @@ -181,6 +181,8 @@ raise_if_unavailable=False) origin_type = request.GET.get('origin_type', None) origin_url = request.GET.get('origin_url', None) + selected_language = request.GET.get('language', None) + if not origin_url: origin_url = request.GET.get('origin', None) snapshot_context = None @@ -218,6 +220,15 @@ language = content_display_data['language'] mimetype = content_display_data['mimetype'] + # Override language with selected language + if selected_language is not None: + language = selected_language + + language_select = None + + if 'text/' in mimetype: + language_select = highlightjs._hljs_languages + root_dir = None filename = None path_info = None @@ -303,6 +314,7 @@ 'max_content_size': content_display_max_size, 'mimetype': mimetype, 'language': language, + 'language_select': language_select, 'breadcrumbs': breadcrumbs, 'top_right_link': { 'url': content_raw_url, diff --git a/swh/web/browse/views/origin.py b/swh/web/browse/views/origin.py --- a/swh/web/browse/views/origin.py +++ b/swh/web/browse/views/origin.py @@ -79,9 +79,10 @@ * :http:get:`/browse/origin/[(origin_type)/url/](origin_url)/visit/(timestamp)/content/(path)/` """ # noqa + language = request.GET.get('language', None) return browse_snapshot_content(request, origin_type=origin_type, origin_url=origin_url, timestamp=timestamp, - path=path) + path=path, selected_language=language) PER_PAGE = 20 diff --git a/swh/web/browse/views/snapshot.py b/swh/web/browse/views/snapshot.py --- a/swh/web/browse/views/snapshot.py +++ b/swh/web/browse/views/snapshot.py @@ -60,7 +60,9 @@ The url that points to it is :http:get:`/browse/snapshot/(snapshot_id)/content/(path)/` """ - return browse_snapshot_content(request, snapshot_id=snapshot_id, path=path) + language = request.GET.get('language', None) + return browse_snapshot_content(request, snapshot_id=snapshot_id, path=path, + selected_language=language) @browse_route(r'snapshot/(?P[0-9a-f]+)/log/', diff --git a/swh/web/browse/views/utils/snapshot_context.py b/swh/web/browse/views/utils/snapshot_context.py --- a/swh/web/browse/views/utils/snapshot_context.py +++ b/swh/web/browse/views/utils/snapshot_context.py @@ -23,7 +23,7 @@ gen_snapshot_link, process_snapshot_branches ) -from swh.web.common import service +from swh.web.common import service, highlightjs from swh.web.common.exc import ( handle_view_exception, NotFoundExc ) @@ -399,7 +399,8 @@ def browse_snapshot_content(request, snapshot_id=None, origin_type=None, - origin_url=None, timestamp=None, path=None): + origin_url=None, timestamp=None, path=None, + selected_language=None): """ Django view implementation for browsing a content in a snapshot context. """ @@ -453,6 +454,15 @@ language = content_display_data['language'] mimetype = content_display_data['mimetype'] + # Override language with selected language + if selected_language is not None: + language = selected_language + + language_select = None + + if 'text/' in mimetype: + language_select = highlightjs._hljs_languages + browse_view_name = 'browse-' + swh_type + '-directory' breadcrumbs = [] @@ -562,6 +572,7 @@ 'max_content_size': content_display_max_size, 'mimetype': mimetype, 'language': language, + 'language_select': language_select, 'breadcrumbs': breadcrumbs if root_sha1_git else [], 'top_right_link': { 'url': content_raw_url, diff --git a/swh/web/templates/includes/content-display.html b/swh/web/templates/includes/content-display.html --- a/swh/web/templates/includes/content-display.html +++ b/swh/web/templates/includes/content-display.html @@ -53,7 +53,25 @@ {% elif swh_object_metadata.filename and swh_object_metadata.filename|default:""|slice:"-5:" == "ipynb" %} swh.webapp.renderNotebook({{ top_right_link.url|jsonify }}, '.swh-ipynb'); {% elif content %} + let codeContainer = $('code'); + let content = codeContainer.text(); + swh.webapp.highlightCode(); + + function updateLanguage(language) { + codeContainer.text(content); + codeContainer.removeClass(); + codeContainer.addClass(language); + + let urlParams = new URLSearchParams(window.location.search); + urlParams.set('language', language); + + const newUrl = window.location.pathname + '?' + urlParams.toString() + window.location.hash; + window.history.replaceState('', document.title, newUrl); + + swh.webapp.highlightCode(); + } + {% endif %} {% endif %} diff --git a/swh/web/templates/includes/top-navigation.html b/swh/web/templates/includes/top-navigation.html --- a/swh/web/templates/includes/top-navigation.html +++ b/swh/web/templates/includes/top-navigation.html @@ -94,6 +94,14 @@ {{ top_right_link.text }} {% endif %} + {% if language_select %} + + {% endif %} {% if show_actions_menu %}