diff --git a/main.py b/main.py index 3c255feed..d43eeddfc 100644 --- a/main.py +++ b/main.py @@ -195,6 +195,21 @@ def paperVis(): return render_template('pages/papers_vis.html') +@app.route('/paper_like.html') +def paperLike(standalone=False): + data = {"keyword": "all", + "page": "papers", + "openreviews": site_data["papers"].values(), + "standalone": standalone, + "siteroot": "https://iclr.cc/virtual_2020/" if standalone else ""} + return render_template('pages/paper_like.html', **data) + + +@app.route('/paper_like_standalone.html') +def paperLikeStandalone(): + return paperLike(True) + + @app.route('/recs.html') def recommendations(): data = {"choices": site_data["author_recs"].keys(), @@ -383,6 +398,8 @@ def your_generator_here(): yield "sponsors", {} yield "workshops", {} yield "paperVis", {} + yield "paperLike", {} + yield "paperLikeStandalone", {} yield "papers", {} yield "paper_json", {} yield "index", {} diff --git a/static/css/ilike.css b/static/css/ilike.css new file mode 100644 index 000000000..c01f1c4fe --- /dev/null +++ b/static/css/ilike.css @@ -0,0 +1,293 @@ +.overlay{ + position: fixed; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + background-color: rgba(0, 0, 0, 0.8); + z-index: 250; + opacity: 0.5; + + .overlay-content { + height: 100%; + overflow: scroll; + } +} + +#loading { + background-color: gray; + display: none; +} + +#loading-indicator { + position: absolute; + left: 50%; + top: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); +} + +.lds-grid { + display: inline-block; + position: relative; + width: 64px; + height: 64px; +} +.lds-grid div { + position: absolute; + width: 13px; + height: 13px; + border-radius: 50%; + background: #fff; + animation: lds-grid 1.2s linear infinite; +} +.lds-grid div:nth-child(1) { + top: 6px; + left: 6px; + animation-delay: 0s; +} +.lds-grid div:nth-child(2) { + top: 6px; + left: 26px; + animation-delay: -0.4s; +} +.lds-grid div:nth-child(3) { + top: 6px; + left: 45px; + animation-delay: -0.8s; +} +.lds-grid div:nth-child(4) { + top: 26px; + left: 6px; + animation-delay: -0.4s; +} +.lds-grid div:nth-child(5) { + top: 26px; + left: 26px; + animation-delay: -0.8s; +} +.lds-grid div:nth-child(6) { + top: 26px; + left: 45px; + animation-delay: -1.2s; +} +.lds-grid div:nth-child(7) { + top: 45px; + left: 6px; + animation-delay: -0.8s; +} +.lds-grid div:nth-child(8) { + top: 45px; + left: 26px; + animation-delay: -1.2s; +} +.lds-grid div:nth-child(9) { + top: 45px; + left: 45px; + animation-delay: -1.6s; +} +@keyframes lds-grid { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +.cards { + z-index: 5; +} + +.pp-card-detail { + /*border: 4px solid #eee;*/ + font-family: "Exo"; + height: 250px; + padding-top : 10px; + + padding-left : 15px; + padding-right : 15px; + display: none; +} + +.match { + background-color: lightgray; + height: 8px; + margin: 2px; + display: none; +} + +.match .matchperc { + height: 100%; + background-color: #F3BB00; + width: 50%; +} + +.countLabel { + font-size: 70%; +} + +.session-selector .float-right .btn { + padding-top: 0px; + padding-bottom: 0px; +} + +.session-selector .float-right .btn input { + margin-top: -10px; + margin-bottom: -10px; +} + +.session-selector .float-right { + /*margin-top: -4px; + margin-bottom: -4px;*/ + display: inline-flex; + flex-direction: column; +} + +.session-selector .session_day .btn { + /*margin-top: -16px;*/ + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; +} + +.session-selector .session_number .btn { + /*margin-top: -16px;*/ + border-top-left-radius: 0px; + border-top-right-radius: 0px; +} + +.session-selector .input { + /*margin: -40px;*/ + /*margin-top: -16px;*/ +} + +.pp-mode-ilike:hover { + /*width: 500px; + height: 500px; + margin-top: -100px; + margin-bottom: -100px; + margin-left: -100px; + margin-right: -100px;*/ + width: 150%; + height: 150%; + /*height: auto;*/ + margin-top: -25%; + margin-bottom: -25%; + margin-left: -25%; + margin-right: -25%; + z-index: 1; + background-color: rgba(255,255,255,0.8); +} + +.pp-mode-ilike:hover .match { + display: inherit; +} + +.myCard:hover { + z-index: 1; +} + +.pp-mode-ilike:hover .pp-card-header .pp-card-detail { + /*border: 4px solid #eee;*/ + display: block; +} + +.pp-mode-ilike:hover .pp-card-header { + height: inherit; +} + +.pp-mode-ilike:hover .pp-card-header .title-wrapper .feedback { + display: block; +} + +.pp-mode-ilike:hover .pp-card-header .title-inner { + padding-left: 50px; + padding-right: 50px; +} + +.pp-mode-ilike:hover .cards_img { + width: 64%; + max-height: 120px; +} + +.pp-mode-ilike .pp-card-header { + /*height: 175px;*/ + border: 1px solid #eee; + } + + + .pp-mode-ilike .pp-card-header .card-title { + font-size: 17px; + } + + .title-wrapper { + position: relative; + } + + .title-wrapper .feedback { + display: none; + position: absolute; + top: 0px; + } + + .pp-mode-ilike:hover .title-wrapper .preview { + display: none !important; + } + + .title-wrapper .preview { + display: none; + position: absolute; + top: -18px; + } + + .title-wrapper .preview.dislike { + left: 8px; + } + + .title-wrapper .preview.like { + right: 8px; + } + + .title-wrapper .feedback.dislike { + left: 0px; + } + + .title-wrapper .feedback.like { + right: 0px; + } +/* + .pp-mode-ilike .pp-card-header .title-wrapper div { + display: inline-block; + }*/ + + .feedback .fa-heart{ + margin-top: 2px; + color: lightgreen; + } + + .like .fa-thumbs-up{ + color: #0cb10c; + } + + .feedback .fa-remove{ + color: indianred; + } + + .feedback .fa-times{ + color: indianred; + } + + .dislike .fa-thumbs-up{ + color: indianred; + -webkit-transform: rotate(180deg); + } + + .feedback .fa-thumbs-down{ + color: indianred; + } + + .feedback .fa-stack:hover { + transform:scale(1.2); + transform-origin: center; + cursor: pointer; + } \ No newline at end of file diff --git a/static/images/IlikeCLR-logo.png b/static/images/IlikeCLR-logo.png new file mode 100644 index 000000000..1499ef875 Binary files /dev/null and b/static/images/IlikeCLR-logo.png differ diff --git a/static/js/kriging.js b/static/js/kriging.js new file mode 100644 index 000000000..628c4f8cf --- /dev/null +++ b/static/js/kriging.js @@ -0,0 +1,477 @@ +// Extend the Array class +Array.prototype.max = function() { + return Math.max.apply(null, this); +}; +Array.prototype.min = function() { + return Math.min.apply(null, this); +}; +Array.prototype.mean = function() { + var i, sum; + for(i=0,sum=0;iy) != (this[j][1]>y)) && + (x<(this[j][0]-this[i][0]) * (y-this[i][1]) / (this[j][1]-this[i][1]) + this[i][0]) ) { + c = !c; + } + } + return c; +} + +var kriging = function() { + var kriging = {}; + + // Matrix algebra + kriging_matrix_diag = function(c, n) { + var i, Z = [0].rep(n*n); + for(i=0;i=big) { + big = Math.abs(X[j*n+k]); + irow = j; + icol = k; + } + } + } + } + } + ++(ipiv[icol]); + + if(irow!=icol) { + for(l=0;l=0;l--) + if(indxr[l]!=indxc[l]) { + for(k=0;krange) return nugget + (sill-nugget)/range; + return nugget + ((sill-nugget)/range)* + ( 1.5*(h/range) - 0.5*Math.pow(h/range, 3) ); + }; + + // Train using gaussian processes with bayesian priors + kriging.train = function(t, x, y, model, sigma2, alpha) { + var variogram = { + t : t, + x : x, + y : y, + nugget : 0.0, + range : 0.0, + sill : 0.0, + A : 1/3, + n : 0 + }; + switch(model) { + case "gaussian": + variogram.model = kriging_variogram_gaussian; + break; + case "exponential": + variogram.model = kriging_variogram_exponential; + break; + case "spherical": + variogram.model = kriging_variogram_spherical; + break; + }; + + // Lag distance/semivariance + var i, j, k, l, n = t.length; + var distance = Array((n*n-n)/2); + for(i=0,k=0;i30?30:(n*n-n)/2; + var tolerance = variogram.range/lags; + var lag = [0].rep(lags); + var semi = [0].rep(lags); + if(lags<30) { + for(l=0;l=((n*n-n)/2)) break; + } + if(k>0) { + lag[l] /= k; + semi[l] /= k; + l++; + } + } + if(l<2) return variogram; // Error: Not enough points + } + + // Feature transformation + n = l; + variogram.range = lag[n-1]-lag[0]; + var X = [1].rep(2*n); + var Y = Array(n); + var A = variogram.A; + for(i=0;ixlim[1]) + xlim[1] = polygons[i][j][0]; + if(polygons[i][j][1]ylim[1]) + ylim[1] = polygons[i][j][1]; + } + + // Alloc for O(n^2) space + var xtarget, ytarget; + var a = Array(2), b = Array(2); + var lxlim = Array(2); // Local dimensions + var lylim = Array(2); // Local dimensions + var x = Math.ceil((xlim[1]-xlim[0])/width); + var y = Math.ceil((ylim[1]-ylim[0])/width); + + var A = Array(x+1); + for(i=0;i<=x;i++) A[i] = Array(y+1); + for(i=0;ilxlim[1]) + lxlim[1] = polygons[i][j][0]; + if(polygons[i][j][1]lylim[1]) + lylim[1] = polygons[i][j][1]; + } + + // Loop through polygon subspace + a[0] = Math.floor(((lxlim[0]-((lxlim[0]-xlim[0])%width)) - xlim[0])/width); + a[1] = Math.ceil(((lxlim[1]-((lxlim[1]-xlim[1])%width)) - xlim[0])/width); + b[0] = Math.floor(((lylim[0]-((lylim[0]-ylim[0])%width)) - ylim[0])/width); + b[1] = Math.ceil(((lylim[1]-((lylim[1]-ylim[1])%width)) - ylim[0])/width); + for(j=a[0];j<=a[1];j++) + for(k=b[0];k<=b[1];k++) { + xtarget = xlim[0] + j*width; + ytarget = ylim[0] + k*width; + if(polygons[i].pip(xtarget, ytarget)) + A[j][k] = kriging.predict(xtarget, + ytarget, + variogram); + } + } + A.xlim = xlim; + A.ylim = ylim; + A.zlim = [variogram.t.min(), variogram.t.max()]; + A.width = width; + return A; + }; + kriging.contour = function(value, polygons, variogram) { + + }; + + // Plotting on the DOM + kriging.plot = function(canvas, grid, xlim, ylim, colors) { + // Clear screen + var ctx = canvas.getContext("2d"); + ctx.clearRect(0, 0, canvas.width, canvas.height); + + // Starting boundaries + var range = [xlim[1]-xlim[0], ylim[1]-ylim[0], grid.zlim[1]-grid.zlim[0]]; + var i, j, x, y, z; + var n = grid.length; + var m = grid[0].length; + var wx = Math.ceil(grid.width*canvas.width/(xlim[1]-xlim[0])); + var wy = Math.ceil(grid.width*canvas.height/(ylim[1]-ylim[0])); + for(i=0;i1.0) z = 1.0; + + ctx.fillStyle = colors[Math.floor((colors.length-1)*z)]; + ctx.fillRect(Math.round(x-wx/2), Math.round(y-wy/2), wx, wy); + } + + }; + + + return kriging; +}(); \ No newline at end of file diff --git a/static/js/paper_like.js b/static/js/paper_like.js new file mode 100644 index 000000000..6baf300f8 --- /dev/null +++ b/static/js/paper_like.js @@ -0,0 +1,531 @@ +let allPapers = []; +const allKeys = { + authors: [], + keywords: [], + session: [], + titles: [], + recs: [], +} + +let order_by = null; +let session_day = null; +let session_number = null; +let likelihood_outdated = false; +let $grid = null; +var iso = null; +let allProj = []; + +// From https://stackoverflow.com/questions/7128675/from-green-to-red-color-depend-on-percentage +const percentColors = [ + { pct: 0.0, color: { r: 205, g: 92, b: 92 } }, + { pct: 0.5, color: { r: 243, g: 187, b: 0 } }, + { pct: 1.0, color: { r: 0, g: 176, b: 13 } } +]; + +const getColorForPercentage = function(pct) { + for (var i = 1; i < percentColors.length - 1; i++) { + if (pct < percentColors[i].pct) { + break; + } + } + var lower = percentColors[i - 1]; + var upper = percentColors[i]; + var range = upper.pct - lower.pct; + var rangePct = (pct - lower.pct) / range; + var pctLower = 1 - rangePct; + var pctUpper = rangePct; + var color = { + r: Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper), + g: Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper), + b: Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper) + }; + return 'rgb(' + [color.r, color.g, color.b].join(',') + ')'; +} + +const scoreToPercentage = function(score){ + var scale = 0.9; + return Math.max(Math.min((score * scale + 1) * 0.5, 1), 0); +} + +const updateCards = (papers) => { + jQuery('.cards').append(jQuery.map(papers, card_html)) + lazyLoader(); +} + +const setOrderBy = value => { + if (value != order_by){ + jQuery('.btn-group.order_by input[value="' + value + '"]').click() + } +} + +const likesChanged = () => { + // Add to url + const likestr = jQuery('.myCard[data-likes!=0]').map((i, el) => { + let val = parseInt(jQuery(el).attr('data-likes')); + return jQuery(el).attr('data-id') + "=" + val; // (val >= 0 ? "+" : "-") + Math.abs(val); + }).toArray().join(","); + setQueryStringParameter("likes", encodeURIComponent(likestr)); + + // Note: we minimize, so like gets low value + // Only update directly if we are currently sorting by likelihood, + // otherwise we will update when sorting by likelihood + if (order_by == "likelihood"){ + computeLikelihood(); + } else { + likelihood_outdated = true; + } +} + +const addLike = (card, delta) => { + let mycard = card.parent() + + const likes = parseInt(mycard.attr('data-likes') || '0') + delta; + mycard.attr('data-likes', likes); + // Remove responsiveness to mouse temporarily, so card is no longer hovered + card.css('pointerEvents', "none"); + // Undo after timeout (this way it is queued so we give time for unhover to happen) + setTimeout(() => { card.css('pointerEvents', "auto") }, 0) + + card.find('.preview.like').toggle(likes > 0); + card.find('.preview.dislike').toggle(likes < 0); + + likesChanged() + +} + +const setLikesFromStr = (likestr) => { + + var patt = /(([A-Za-z0-9]+)=([-]?\d+))/ + var changed = false; + jQuery.each(likestr.split(","), (i, s) => { + const match = s.match(patt); + if (match){ + changed = true; + + const id = match[2]; + const likes = parseInt(match[3]); + + const card = jQuery('#card-' + id); + const mycard = card.parent(); + + mycard.attr('data-likes', likes); + + card.find('.preview.like').toggle(likes > 0); + card.find('.preview.dislike').toggle(likes < 0); + } + + }) + + if (changed) { + likesChanged(); + } + +} + +const filterGrid = () => { + $grid.isotope({ filter: function() { + $this = jQuery(this) + let matchSession = true + if ((session_day != 'all') || (session_number != 'all')){ + matchSession = $this.find('.card-session').toArray().some(el => { + let sessArr = jQuery(el).text().split(" "); + return ( + ((session_day == 'all') || sessArr[0].toLowerCase().startsWith(session_day)) && + ((session_number == 'all') || parseInt(sessArr[1]) == session_number) + ) + }); + } + return matchSession && (parseFloat($this.attr('data-search-match')) > 0); + } }) + jQuery('.filterCount').text( iso.filteredItems.length ); +} + +const setSessionFromStr = (sessStr) => { + const sessArr = sessStr.split(" "); + const sessDay = sessArr[0].toLowerCase(); // Bit hacky fixed length + const sessDayMatches = jQuery('.btn-group.session_day input').filter((i, el) => {return sessDay.startsWith(jQuery(el).attr('value'))}); + const sessNum = parseInt(sessArr[1]); + const sessNumMatches = jQuery('.btn-group.session_number input[value="' + sessNum + '"]') + return setSession( + sessDayMatches.length > 0 ? sessDayMatches.attr('value') : 'all', + sessNumMatches.length > 0 ? sessNumMatches.attr('value') : 'all', + ) +} + +const setSession = (day, num) => { + if (day != session_day){ + jQuery('.btn-group.session_day input[value="' + day + '"]').click() + } + if (num != session_number){ + jQuery('.btn-group.session_number input[value="' + num + '"]').click() + } +} + +const doExactSearch = it => { + return doSearch(it, true) + // Disabled since it somehow gets overridden by the typahead script + // Todo some other way to indicate that we perform an exact search? + // return doSearch((it.charAt(0) == '"' ? '' : '"') + it + (it.charAt(it.length -1) == '"' ? '' : '"')) +} + +const doSearch = (it, exact) => { + + $('.typeahead_all').val(it); + setQueryStringParameter("search", encodeURIComponent(it)); + + const gridItems = $grid.find('.grid-item'); + + // TODO improve search functionality + const query = it.trim().toLowerCase(); + if (query.length > 0){ + // const exact = (query.charAt(0) == '"' && query.charAt(query.length - 1) == '"') + let itarr = ( + exact ? + jQuery([query.substring(query.charAt(0) == '"' ? 1 : 0, query.length - (query.charAt(query.length - 1) == '"' ? 1 : 0))]) : + jQuery(query.split(" ")).filter((i, el) => { return ['and', 'or', 'on', 'of', 'for', 'by', 'with', 'via', 'in', 'to', 'a', 'an', 'the'].indexOf(el) < 0 }) + ); + gridItems.each((i, el) => { + el = jQuery(el) + const haystack = el.text(); + const compute_match = haystack => { + haystack = haystack.trim().toLowerCase(); + var score = 0; + jQuery.each(itarr, (i, w) => { + if (haystack.indexOf(w) > -1){ + score++ + } + }) + return score; + } + + const score = ( + compute_match(el.find('.card-title').text()) * 4 + + compute_match(el.find('.card-authors').text()) * 2 + + compute_match(el.find('.keywords').text()) * 2 + + compute_match(el.find('.tldr').text()) * 1 + ) + el.attr('data-search-match', score) + }) + } else { + gridItems.attr('data-search-match', 1) + } + + filterGrid(); + + if (it.length > 0){ + // Sort descending by filter score + if (order_by == 'search'){ + $grid.isotope('updateSortData').isotope(); + } else { + setOrderBy('search') + } + } else { + if (order_by == 'search'){ + // If the ordering was set to search but we cleared the search, we're effectively + // ordering random, so set ordering to random explicitly to make this clear + setOrderBy('random') + } + + } +}; + +const setScore = (card, score) => { + card.attr('data-score', score); + + const likes = parseInt(card.attr('data-likes')) + const perc = likes > 0 ? 1. : (likes < 0 ? -1. : scoreToPercentage(score)); + + $matchperc = card.find('.matchperc'); + $matchperc.width(Math.round(perc * 100) + "%"); + var color = getColorForPercentage(perc); + $matchperc.css("background-color", color); +} + +function computeLikelihood(){ + + jQuery('#loading').show(); + + + // Use kriging.js, see https://oeo4b.github.io/ + var t = [ /* Target variable */ ]; + var x = [ /* X-axis coordinates */ ]; + var y = [ /* Y-axis coordinates */ ]; + jQuery('.myCard[data-likes!=0]').each((i, el) => { + el = jQuery(el); + t.push(parseInt(jQuery(el).attr('data-likes'))); + let emb = proj_dict[jQuery(el).attr('data-id')]; + x.push(emb[0]); + y.push(emb[1]); + }) + if (t.length > 1){ + // var model = "exponential"; + var model = "gaussian"; + var sigma2 = 0.3, alpha = 1; + var variogram = kriging.train(t, x, y, model, sigma2, alpha); + + jQuery('.myCard').each( (i, el) => { + el = jQuery(el) + let emb = proj_dict[jQuery(el).attr('data-id')]; + let score = kriging.predict(emb[0], emb[1], variogram) + setScore(el, score) + }) + } else { + jQuery('.myCard').each( (i, el) => { + setScore(jQuery(el), 0) + }) + } + jQuery('#loading').hide(); + // jQuery('#main-grid').removeClass('grid-non-updating'); + if (order_by == 'likelihood'){ + // Update in realtime, otherwise don't since random will reshuffle as well + $grid.isotope('updateSortData').isotope(); + } +} + + +/** + * START here and load JSON. + */ +const start = () => { + // jQuery.noConflict(); // Free the dollar sign + + Promise.all([ + jQuery.getJSON('papers.json'), + jQuery.getJSON('embeddings_tsne.json') + ]).then(([papers, proj]) => { + // shuffleArray(papers); + + allPapers = papers; + allProj = proj; + proj_dict = {}; + jQuery.each(allProj, (i, el) => { proj_dict[el['id']] = el['pos']}); + calcAllKeys(allPapers, allKeys); + const allKeysCombined = allKeys['authors'].concat(allKeys['keywords'], allKeys['titles']); + initTypeAhead(allKeysCombined, '.typeahead_all', 'ilike', (el, it) => { allKeysCombined.indexOf(it) >= 0 ? doExactSearch(it) : doSearch(it) }); + updateCards(allPapers) + + + + + + // Copy id's into parent cards for sorting + jQuery('.myCard').each( (i, el) => { + el = jQuery(el) + el.attr('data-id', el.find('.pp-card').attr('data-id')) + el.attr('data-likes', 0) + el.attr('data-search-match', 1) + }) + + + + jQuery('.pp-card .keywords').on('click', 'a', function(){ + doExactSearch(jQuery(this).text()); + return false; + }); + + jQuery('.pp-card .card-session').on('click', function(){ + setSessionFromStr(jQuery(this).text()); + return false; + }); + + $grid = jQuery('.grid'); + + $grid.isotope({ + // options + itemSelector: '.grid-item', + layoutMode: 'fitRows', + getSortData: { + searchMatch: '[data-search-match] parseFloat', + id: '[data-id]', + score: '[data-score] parseFloat', + //maxScore: '[data-max-score] parseFloat', + // ei: '[data-ei] parseFloat', + like: '[data-likes] parseInt', + } + }); + iso = $grid.data('isotope'); + + $grid.on( 'click', '.grid-item .feedback .like', function() { + addLike(jQuery(this.closest('.pp-card')), 1) + }); + + $grid.on( 'click', '.grid-item .feedback .dislike', function() { + addLike(jQuery(this.closest('.pp-card')), -1) + }); + + if (getUrlParameter("noinfo")){ + jQuery('.remove_alert').click() + } + const urlSearch = decodeURIComponent(getUrlParameter("search")); + const likestr = decodeURIComponent(getUrlParameter("likes")); + const orderBy = decodeURIComponent(getUrlParameter("order_by")) || 'likelihood'; + const sessionDay = decodeURIComponent(getUrlParameter("session_day")) || 'all'; + const sessionNumber = decodeURIComponent(getUrlParameter("session_number")) || 'all'; + setSession(sessionDay, sessionNumber); + if (urlSearch !== '') { + let it = urlSearch; + allKeysCombined.indexOf(it) >= 0 ? doExactSearch(it) : doSearch(it) + } + // setSessionDay(sessionDay) + // setSessionNumber(sessionNumber) + + // Set the likes + setLikesFromStr(likestr); + + setOrderBy(orderBy); + + + }).catch(e => console.error(e)) +} + + +/** + * EVENTS + * **/ + +jQuery('.btn-group.order_by').on( 'click', 'input', function() { + order_by = jQuery(this).attr('value'); + setQueryStringParameter("order_by", encodeURIComponent(order_by)); + $grid.isotope('updateSortData').isotope(); + if (order_by == 'random'){ + $grid.isotope({ sortBy: 'random', sortAscending: true }); + } else if(order_by == 'search') { + $grid.isotope({ + sortBy: ['searchMatch', 'random'], + sortAscending: { + 'searchMatch': false, + 'random': true + } + }); + } else if (order_by == 'likelihood'){ + if (likelihood_outdated){ + computeLikelihood(); + } + $grid.isotope({ sortBy: ['like', 'score', 'random'], sortAscending: { + 'like': false, + 'score': false, + 'random': true + } }); + } +}); + +jQuery('.btn-group.session_day').on( 'click', 'input', function() { + session_day = jQuery(this).attr('value'); + setQueryStringParameter("session_day", encodeURIComponent(session_day)); + filterGrid(); +}); + +jQuery('.btn-group.session_number').on( 'click', 'input', function() { + session_number = jQuery(this).attr('value'); + session_number = (session_number == 'all') ? 'all' : parseInt(session_number) + setQueryStringParameter("session_number", encodeURIComponent(session_number)); + filterGrid(); +}); + +jQuery('.remove_alert').on('click', function() { + setQueryStringParameter("noinfo", 1) +}) + +/** + * CARDS + */ + +const keyword = kw => `${kw.toLowerCase()}` + +// const card_time_small = (openreview, show) => { +// const cnt = openreview.content; +// return show ? (!SITE_ROOT ? ` +// +//
+// ${cnt.session.filter(s => s.match(/.*[0-9]/g)).map( +// (s,i) => `${s.replace('Session ','')} ${card_live(cnt.session_links[i])} ${card_cal(openreview, i)} `).join(', ')} +//
+// +// ` : ` +// +//
+// ${cnt.session.filter(s => s.match(/.*[0-9]/g)).map( +// (s,i) => `${s.replace('Session ','')}`).join(', ')} +//
+// +// `) : ''; +// } + +const card_time_small = (openreview, show) => { + const cnt = openreview.content; + return show ? ` + +
+ ${cnt.session.filter(s => s.match(/.*[0-9]/g)).map( + (s,i) => `${s.replace('Session ','')} ${card_live(cnt.session_links[i])} ${card_cal(openreview, i)} `).join(', ')} +
+ + ` : ''; +} + +const card_icon_video = icon_video(16); +const card_icon_cal = icon_cal(16); + +const card_live = (link)=> SITE_ROOT ? '' : `${card_icon_video}` +const card_cal = (openreview, i)=> `${card_icon_cal}` + + +//language=HTML +const card_html = openreview => ` +
+
+
+
+
+
+ +
+
+ +
${openreview.content.title}
+
+
+ ${openreview.content.authors.join(', ')} +
+
+
+
+
+
+ ${card_time_small(openreview, true)} +
+ +
+
+

${openreview.content.TLDR}

+

Keywords: + ${openreview.content.keywords.map(keyword).join(', ')} +

+
+
+
+
` \ No newline at end of file diff --git a/templates/misc/paper_tabs.html b/templates/misc/paper_tabs.html new file mode 100644 index 000000000..bf0e6ce94 --- /dev/null +++ b/templates/misc/paper_tabs.html @@ -0,0 +1,69 @@ +{% set paper_tabs = [ + ('papers.html', 'Browse'), + ('paper_vis.html', 'Visualization'), + ('paper_like.html', 'IlikeCLR'), +] -%} + + + \ No newline at end of file diff --git a/templates/pages/header_like.html b/templates/pages/header_like.html new file mode 100644 index 000000000..7686e0f8f --- /dev/null +++ b/templates/pages/header_like.html @@ -0,0 +1,31 @@ +{##} + + + + + + + + \ No newline at end of file diff --git a/templates/pages/paper_like.html b/templates/pages/paper_like.html new file mode 100644 index 000000000..ee75cb521 --- /dev/null +++ b/templates/pages/paper_like.html @@ -0,0 +1,370 @@ + + + {% set page_title = "ICLR 2020" %} + {% include 'pages/head.html' %} + + + + + + + + + + + + {% set active_page = "IlikeCLR" %} + + {% if standalone %} + {% include 'pages/header_like.html' %} + {% else %} + {% include 'pages/header.html' %} + {% endif %} +
+ +
+
+
+
+
+ + {% if not standalone %} + {% set active_paper_tab_id = "IlikeCLR" %} + {% include 'misc/paper_tabs.html' %} + {% endif %} +
+ +
+ + + + + {% include 'pages/footer.html' %} + + \ No newline at end of file diff --git a/templates/pages/papers.html b/templates/pages/papers.html index a6a3ddbff..d160f168f 100644 --- a/templates/pages/papers.html +++ b/templates/pages/papers.html @@ -10,18 +10,8 @@ {% include 'pages/header.html' %}
- + {% set active_paper_tab_id = "Browse" %} + {% include 'misc/paper_tabs.html' %}