From 7a0fbdecc484284296574a2c2ba9afda01212723 Mon Sep 17 00:00:00 2001 From: Alexandre Flament Date: Mon, 22 Mar 2021 12:00:48 +0100 Subject: [enh] oscar: image thumbnail layout Adjust thumbnail sizes to fill the container width --- searx/static/themes/oscar/js/searx.js | 172 ++++++++++++++++++++++++++ searx/static/themes/oscar/js/searx.min.js | 4 +- searx/static/themes/oscar/js/searx.min.js.map | 2 +- 3 files changed, 175 insertions(+), 3 deletions(-) (limited to 'searx/static/themes/oscar/js') diff --git a/searx/static/themes/oscar/js/searx.js b/searx/static/themes/oscar/js/searx.js index 163009481..c377e4534 100644 --- a/searx/static/themes/oscar/js/searx.js +++ b/searx/static/themes/oscar/js/searx.js @@ -17,6 +17,9 @@ window.searx = (function(d) { 'use strict'; + // + d.getElementsByTagName("html")[0].className = "js"; + // add data- properties var script = d.currentScript || (function() { var scripts = d.getElementsByTagName('script'); @@ -199,6 +202,12 @@ $(document).ready(function(){ tabs.children().attr("aria-selected", "false"); $(a.target).parent().attr("aria-selected", "true"); }); + + /** + * Layout images according to their sizes + */ + searx.image_thumbnail_layout = new searx.ImageLayout('#main_results', '#main_results .result-images', 'img.img-thumbnail', 15, 200); + searx.image_thumbnail_layout.watch(); }); ;window.addEventListener('load', function() { // Hide infobox toggle if shrunk size already fits all content. @@ -383,3 +392,166 @@ $(document).ready(function(){ }); }); +;/** +* +* Google Image Layout v0.0.1 +* Description, by Anh Trinh. +* Heavily modified for searx +* https://ptgamr.github.io/2014-09-12-google-image-layout/ +* https://ptgamr.github.io/google-image-layout/src/google-image-layout.js +* +* @license Free to use under the MIT License. +* +*/ + +(function (w, d) { + function ImageLayout(container_selector, results_selector, img_selector, margin, maxHeight) { + this.container_selector = container_selector; + this.results_selector = results_selector; + this.img_selector = img_selector; + this.margin = margin; + this.maxHeight = maxHeight; + this.isAlignDone = true; + } + + /** + * Get the height that make all images fit the container + * + * width = w1 + w2 + w3 + ... = r1*h + r2*h + r3*h + ... + * + * @param {[type]} images the images to be calculated + * @param {[type]} width the container witdth + * @param {[type]} margin the margin between each image + * + * @return {[type]} the height + */ + ImageLayout.prototype._getHeigth = function (images, width) { + var i, img; + var r = 0; + + for (i = 0; i < images.length; i++) { + img = images[i]; + if ((img.naturalWidth > 0) && (img.naturalHeight > 0)) { + r += img.naturalWidth / img.naturalHeight; + } else { + // assume that not loaded images are square + r += 1; + } + } + + return (width - images.length * this.margin) / r; //have to round down because Firefox will automatically roundup value with number of decimals > 3 + }; + + ImageLayout.prototype._setSize = function (images, height) { + var i, img, imgWidth; + var imagesLength = images.length, resultNode; + + for (i = 0; i < imagesLength; i++) { + img = images[i]; + if ((img.naturalWidth > 0) && (img.naturalHeight > 0)) { + imgWidth = height * img.naturalWidth / img.naturalHeight; + } else { + // not loaded image : make it square as _getHeigth said it + imgWidth = height; + } + img.style.width = imgWidth + 'px'; + img.style.height = height + 'px'; + img.style.marginLeft = '3px'; + img.style.marginTop = '3px'; + img.style.marginRight = this.margin - 7 + 'px'; // -4 is the negative margin of the inline element + img.style.marginBottom = this.margin - 7 + 'px'; + resultNode = img.parentNode.parentNode; + if (!resultNode.classList.contains('js')) { + resultNode.classList.add('js'); + } + } + }; + + ImageLayout.prototype._alignImgs = function (imgGroup) { + var isSearching, slice, i, h; + var containerElement = d.querySelector(this.container_selector); + var containerCompStyles = window.getComputedStyle(containerElement); + var containerPaddingLeft = parseInt(containerCompStyles.getPropertyValue('padding-left'), 10); + var containerPaddingRight = parseInt(containerCompStyles.getPropertyValue('padding-right'), 10); + var containerWidth = containerElement.clientWidth - containerPaddingLeft - containerPaddingRight; + + while (imgGroup.length > 0) { + isSearching = true; + for (i = 1; i <= imgGroup.length && isSearching; i++) { + slice = imgGroup.slice(0, i); + h = this._getHeigth(slice, containerWidth); + if (h < this.maxHeight) { + this._setSize(slice, h); + // continue with the remaining images + imgGroup = imgGroup.slice(i); + isSearching = false; + } + } + if (isSearching) { + this._setSize(slice, Math.min(this.maxHeight, h)); + break; + } + } + }; + + ImageLayout.prototype.align = function () { + var i; + var results_selectorNode = d.querySelectorAll(this.results_selector); + var results_length = results_selectorNode.length; + var previous = null; + var current = null; + var imgGroup = []; + + for (i = 0; i < results_length; i++) { + current = results_selectorNode[i]; + if (current.previousElementSibling !== previous && imgGroup.length > 0) { + // the current image is not connected to previous one + // so the current image is the start of a new group of images. + // so call _alignImgs to align the current group + this._alignImgs(imgGroup); + // and start a new empty group of images + imgGroup = []; + } + // add the current image to the group (only the img tag) + imgGroup.push(current.querySelector(this.img_selector)); + // update the previous variable + previous = current; + } + // align the remaining images + if (imgGroup.length > 0) { + this._alignImgs(imgGroup); + } + }; + + ImageLayout.prototype.watch = function () { + var i, img; + var obj = this; + var results_nodes = d.querySelectorAll(this.results_selector); + var results_length = results_nodes.length; + + function throttleAlign() { + if (obj.isAlignDone) { + obj.isAlignDone = false; + setTimeout(function () { + obj.align(); + obj.isAlignDone = true; + }, 100); + } + } + + w.addEventListener('pageshow', throttleAlign); + w.addEventListener('load', throttleAlign); + w.addEventListener('resize', throttleAlign); + + for (i = 0; i < results_length; i++) { + img = results_nodes[i].querySelector(this.img_selector); + if (img !== null && img !== undefined) { + img.addEventListener('load', throttleAlign); + img.addEventListener('error', throttleAlign); + } + } + }; + + w.searx.ImageLayout = ImageLayout; + +}(window, document)); diff --git a/searx/static/themes/oscar/js/searx.min.js b/searx/static/themes/oscar/js/searx.min.js index b3317e0c5..8b17d4f61 100644 --- a/searx/static/themes/oscar/js/searx.min.js +++ b/searx/static/themes/oscar/js/searx.min.js @@ -1,4 +1,4 @@ -/*! oscar/searx.min.js | 22-03-2021 | */ +/*! oscar/searx.min.js | 05-04-2021 | */ -window.searx=function(t){"use strict";var a,a=t.currentScript||(a=t.getElementsByTagName("script"))[a.length-1];return{autocompleter:"true"===a.getAttribute("data-autocompleter"),method:a.getAttribute("data-method"),translations:JSON.parse(a.getAttribute("data-translations"))}}(document),$(document).ready(function(){var t,e="";searx.autocompleter&&((t=new Bloodhound({datumTokenizer:Bloodhound.tokenizers.obj.whitespace("value"),queryTokenizer:Bloodhound.tokenizers.whitespace,remote:{url:"./autocompleter?q=%QUERY",wildcard:"%QUERY"}})).initialize(),$("#q").on("keydown",function(t){13==t.which&&(e=$("#q").val())}),$("#q").typeahead({name:"search-results",highlight:!1,hint:!0,displayKey:function(t){return t},classNames:{input:"tt-input",hint:"tt-hint",menu:"tt-dropdown-menu",dataset:"tt-dataset-search-results"}},{name:"autocomplete",source:t}),$("#q").bind("typeahead:select",function(t,a){e&&$("#q").val(e),$("#search_form").submit()}))}),$(document).ready(function(){$("#q.autofocus").focus(),$("#clear_search").click(function(){document.getElementById("q").value=""}),$(".select-all-on-click").click(function(){$(this).select()}),$(".btn-collapse").click(function(){var t=$(this).data("btn-text-collapsed"),a=$(this).data("btn-text-not-collapsed");""!==t&&""!==a&&(new_html=$(this).hasClass("collapsed")?$(this).html().replace(t,a):$(this).html().replace(a,t),$(this).html(new_html))}),$(".btn-toggle .btn").click(function(){var t="btn-"+$(this).data("btn-class"),a=$(this).data("btn-label-default"),e=$(this).data("btn-label-toggled");""!==e&&(new_html=$(this).hasClass("btn-default")?$(this).html().replace(a,e):$(this).html().replace(e,a),$(this).html(new_html)),$(this).toggleClass(t),$(this).toggleClass("btn-default")}),$(".media-loader").click(function(){var t=$(this).data("target"),a=$(t+" > iframe"),t=a.attr("src");void 0!==t&&!1!==t||a.attr("src",a.data("src"))}),$(".btn-sm").dblclick(function(){var t="btn-"+$(this).data("btn-class");$(this).hasClass("btn-default")?($(".btn-sm > input").attr("checked","checked"),$(".btn-sm > input").prop("checked",!0),$(".btn-sm").addClass(t),$(".btn-sm").addClass("active"),$(".btn-sm").removeClass("btn-default")):($(".btn-sm > input").attr("checked",""),$(".btn-sm > input").removeAttr("checked"),$(".btn-sm > input").checked=!1,$(".btn-sm").removeClass(t),$(".btn-sm").removeClass("active"),$(".btn-sm").addClass("btn-default"))}),$(".nav-tabs").click(function(t){$(t.target).parents("ul").children().attr("aria-selected","false"),$(t.target).parent().attr("aria-selected","true")})}),window.addEventListener("load",function(){$(".infobox").each(function(){var t=$(this).find(".infobox_body");t.prop("scrollHeight")+t.find("img.infobox_part").height()<=t.css("max-height").replace("px","")&&$(this).find(".infobox_toggle").hide()})}),$(document).ready(function(){$(".searx_overpass_request").on("click",function(t){var a="https://overpass-api.de/api/interpreter?data=[out:json][timeout:25];(",e=");out meta;",s=$(this).data("osm-id"),n=$(this).data("osm-type"),i=$(this).data("result-table"),o="#"+$(this).data("result-table-loadicon"),r=["addr:city","addr:country","addr:housenumber","addr:postcode","addr:street"];if(s&&n&&i){var i="#"+i,l=null;switch(n){case"node":l=a+"node("+s+");"+e;break;case"way":l=a+"way("+s+");"+e;break;case"relation":l=a+"relation("+s+");"+e}l&&$.ajax(l).done(function(t){if(t&&t.elements&&t.elements[0]){var a,e=t.elements[0],s=$(i).html();for(a in e.tags)if(null===e.tags.name||-1==r.indexOf(a)){switch(s+=""+a+"",a){case"phone":case"fax":s+=''+e.tags[a]+"";break;case"email":s+=''+e.tags[a]+"";break;case"website":case"url":s+=''+e.tags[a]+"";break;case"wikidata":s+=''+e.tags[a]+"";break;case"wikipedia":if(-1!=e.tags[a].indexOf(":")){s+=''+e.tags[a]+"";break}default:s+=e.tags[a]}s+=""}$(i).html(s),$(i).removeClass("hidden"),$(o).addClass("hidden")}}).fail(function(){$(o).html($(o).html()+'

'+searx.translations.could_not_load+"

")})}$(this).off(t)}),$(".searx_init_map").on("click",function(t){var a=$(this).data("leaflet-target"),e=$(this).data("map-lon"),s=$(this).data("map-lat"),n=$(this).data("map-zoom"),i=$(this).data("map-boundingbox"),o=$(this).data("map-geojson");i&&(southWest=L.latLng(i[0],i[2]),northEast=L.latLng(i[1],i[3]),map_bounds=L.latLngBounds(southWest,northEast)),L.Icon.Default.imagePath="./static/themes/oscar/css/images/";var r=L.map(a),a=new L.TileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",{minZoom:1,maxZoom:19,attribution:'Map data © OpenStreetMap contributors'});new L.TileLayer("https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png",{minZoom:1,maxZoom:19,attribution:'Wikimedia maps beta | Maps data © OpenStreetMap contributors'});setTimeout(function(){map_bounds?r.fitBounds(map_bounds,{maxZoom:17}):e&&s&&(n?r.setView(new L.LatLng(s,e),n):r.setView(new L.LatLng(s,e),8))},0),r.addLayer(a),L.control.layers({"OSM Mapnik":a}).addTo(r),o&&L.geoJson(o).addTo(r),$(this).off(t)})}),$(document).ready(function(){$("#allow-all-engines").click(function(){$(".onoffswitch-checkbox").each(function(){this.checked=!1})}),$("#disable-all-engines").click(function(){$(".onoffswitch-checkbox").each(function(){this.checked=!0})})}); +window.searx=function(t){"use strict";t.getElementsByTagName("html")[0].className="js";var e,e=t.currentScript||(e=t.getElementsByTagName("script"))[e.length-1];return{autocompleter:"true"===e.getAttribute("data-autocompleter"),method:e.getAttribute("data-method"),translations:JSON.parse(e.getAttribute("data-translations"))}}(document),$(document).ready(function(){var t,a="";searx.autocompleter&&((t=new Bloodhound({datumTokenizer:Bloodhound.tokenizers.obj.whitespace("value"),queryTokenizer:Bloodhound.tokenizers.whitespace,remote:{url:"./autocompleter?q=%QUERY",wildcard:"%QUERY"}})).initialize(),$("#q").on("keydown",function(t){13==t.which&&(a=$("#q").val())}),$("#q").typeahead({name:"search-results",highlight:!1,hint:!0,displayKey:function(t){return t},classNames:{input:"tt-input",hint:"tt-hint",menu:"tt-dropdown-menu",dataset:"tt-dataset-search-results"}},{name:"autocomplete",source:t}),$("#q").bind("typeahead:select",function(t,e){a&&$("#q").val(a),$("#search_form").submit()}))}),$(document).ready(function(){$("#q.autofocus").focus(),$("#clear_search").click(function(){document.getElementById("q").value=""}),$(".select-all-on-click").click(function(){$(this).select()}),$(".btn-collapse").click(function(){var t=$(this).data("btn-text-collapsed"),e=$(this).data("btn-text-not-collapsed");""!==t&&""!==e&&(new_html=$(this).hasClass("collapsed")?$(this).html().replace(t,e):$(this).html().replace(e,t),$(this).html(new_html))}),$(".btn-toggle .btn").click(function(){var t="btn-"+$(this).data("btn-class"),e=$(this).data("btn-label-default"),a=$(this).data("btn-label-toggled");""!==a&&(new_html=$(this).hasClass("btn-default")?$(this).html().replace(e,a):$(this).html().replace(a,e),$(this).html(new_html)),$(this).toggleClass(t),$(this).toggleClass("btn-default")}),$(".media-loader").click(function(){var t=$(this).data("target"),e=$(t+" > iframe"),t=e.attr("src");void 0!==t&&!1!==t||e.attr("src",e.data("src"))}),$(".btn-sm").dblclick(function(){var t="btn-"+$(this).data("btn-class");$(this).hasClass("btn-default")?($(".btn-sm > input").attr("checked","checked"),$(".btn-sm > input").prop("checked",!0),$(".btn-sm").addClass(t),$(".btn-sm").addClass("active"),$(".btn-sm").removeClass("btn-default")):($(".btn-sm > input").attr("checked",""),$(".btn-sm > input").removeAttr("checked"),$(".btn-sm > input").checked=!1,$(".btn-sm").removeClass(t),$(".btn-sm").removeClass("active"),$(".btn-sm").addClass("btn-default"))}),$(".nav-tabs").click(function(t){$(t.target).parents("ul").children().attr("aria-selected","false"),$(t.target).parent().attr("aria-selected","true")}),searx.image_thumbnail_layout=new searx.ImageLayout("#main_results","#main_results .result-images","img.img-thumbnail",15,200),searx.image_thumbnail_layout.watch()}),window.addEventListener("load",function(){$(".infobox").each(function(){var t=$(this).find(".infobox_body");t.prop("scrollHeight")+t.find("img.infobox_part").height()<=t.css("max-height").replace("px","")&&$(this).find(".infobox_toggle").hide()})}),$(document).ready(function(){$(".searx_overpass_request").on("click",function(t){var e="https://overpass-api.de/api/interpreter?data=[out:json][timeout:25];(",a=");out meta;",s=$(this).data("osm-id"),i=$(this).data("osm-type"),n=$(this).data("result-table"),o="#"+$(this).data("result-table-loadicon"),r=["addr:city","addr:country","addr:housenumber","addr:postcode","addr:street"];if(s&&i&&n){var n="#"+n,l=null;switch(i){case"node":l=e+"node("+s+");"+a;break;case"way":l=e+"way("+s+");"+a;break;case"relation":l=e+"relation("+s+");"+a}l&&$.ajax(l).done(function(t){if(t&&t.elements&&t.elements[0]){var e,a=t.elements[0],s=$(n).html();for(e in a.tags)if(null===a.tags.name||-1==r.indexOf(e)){switch(s+=""+e+"",e){case"phone":case"fax":s+=''+a.tags[e]+"";break;case"email":s+=''+a.tags[e]+"";break;case"website":case"url":s+=''+a.tags[e]+"";break;case"wikidata":s+=''+a.tags[e]+"";break;case"wikipedia":if(-1!=a.tags[e].indexOf(":")){s+=''+a.tags[e]+"";break}default:s+=a.tags[e]}s+=""}$(n).html(s),$(n).removeClass("hidden"),$(o).addClass("hidden")}}).fail(function(){$(o).html($(o).html()+'

'+searx.translations.could_not_load+"

")})}$(this).off(t)}),$(".searx_init_map").on("click",function(t){var e=$(this).data("leaflet-target"),a=$(this).data("map-lon"),s=$(this).data("map-lat"),i=$(this).data("map-zoom"),n=$(this).data("map-boundingbox"),o=$(this).data("map-geojson");n&&(southWest=L.latLng(n[0],n[2]),northEast=L.latLng(n[1],n[3]),map_bounds=L.latLngBounds(southWest,northEast)),L.Icon.Default.imagePath="./static/themes/oscar/css/images/";var r=L.map(e),e=new L.TileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",{minZoom:1,maxZoom:19,attribution:'Map data © OpenStreetMap contributors'});new L.TileLayer("https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png",{minZoom:1,maxZoom:19,attribution:'Wikimedia maps beta | Maps data © OpenStreetMap contributors'});setTimeout(function(){map_bounds?r.fitBounds(map_bounds,{maxZoom:17}):a&&s&&(i?r.setView(new L.LatLng(s,a),i):r.setView(new L.LatLng(s,a),8))},0),r.addLayer(e),L.control.layers({"OSM Mapnik":e}).addTo(r),o&&L.geoJson(o).addTo(r),$(this).off(t)})}),$(document).ready(function(){$("#allow-all-engines").click(function(){$(".onoffswitch-checkbox").each(function(){this.checked=!1})}),$("#disable-all-engines").click(function(){$(".onoffswitch-checkbox").each(function(){this.checked=!0})})}),function(o,c){function t(t,e,a,s,i){this.container_selector=t,this.results_selector=e,this.img_selector=a,this.margin=s,this.maxHeight=i,this.isAlignDone=!0}t.prototype._getHeigth=function(t,e){for(var a,s=0,i=0;i