diff --git a/.gitignore b/.gitignore index 1a137e4..2f9f972 100644 --- a/.gitignore +++ b/.gitignore @@ -136,3 +136,5 @@ node_modules/ # MacOS .DS_Store + +.vscode \ No newline at end of file diff --git a/main.py b/main.py index 2a54af0..1e880a3 100644 --- a/main.py +++ b/main.py @@ -184,15 +184,43 @@ def chat(): @app.route("/papers.json") def papers_json(): - return jsonify(site_data["papers"]) + all_papers = [] + all_papers.extend(site_data["papers"]) + for wsh in site_data["workshops"]: + all_papers.extend(wsh.papers) + return jsonify(all_papers) -@app.route("/track_.json") -def track_json(track_name): +@app.route("/papers_.json") +def papers_program(program): paper: Paper - papers_for_track = [ - paper for paper in site_data["papers"] if paper.content.track == track_name - ] + if program == "workshop": + papers_for_program = [] + for wsh in site_data["workshops"]: + papers_for_program.extend(wsh.papers) + else: + papers_for_program = [ + paper for paper in site_data["papers"] if paper.content.program == program + ] + return jsonify(papers_for_program) + + +@app.route("/track__.json") +def track_json(program_name, track_name): + paper: Paper + if program_name == "workshop": + papers_for_track = None + for wsh in site_data["workshops"]: + if wsh.title == track_name: + papers_for_track = wsh.papers + break + else: + papers_for_track = [ + paper + for paper in site_data["papers"] + if paper.content.track == track_name + and paper.content.program == program_name + ] return jsonify(papers_for_track) @@ -216,8 +244,14 @@ def generator(): paper: Paper for paper in site_data["papers"]: yield "paper", {"uid": paper.id} - for track in site_data["tracks"]: - yield "track_json", {"track_name": track} + for program in site_data["programs"]: + yield "papers_program", {"program": program} + for track in site_data["tracks"]: + yield "track_json", {"track_name": track, "program_name": program} + + yield "papers_program", {"program": "workshop"} + for wsh in site_data["workshops"]: + yield "track_json", {"track_name": wsh.title, "program_name": "workshop"} plenary_session: PlenarySession for _, plenary_sessions_on_date in site_data["plenary_sessions"].items(): for plenary_session in plenary_sessions_on_date: diff --git a/miniconf/load_site_data.py b/miniconf/load_site_data.py index 9fddd00..0533044 100644 --- a/miniconf/load_site_data.py +++ b/miniconf/load_site_data.py @@ -159,6 +159,20 @@ def load_site_data( ] site_data["plenary_session_days"][0][-1] = "active" + # Papers' progam to their data + for p in ( + site_data["main_papers"] + site_data["cl_papers"] + site_data["tacl_papers"] + ): + p["program"] = "main" + + for p in site_data["demo_papers"]: + p["program"] = "demo" + + for p in site_data["srw_papers"]: + p["program"] = "srw" + + site_data["programs"] = ["main", "demo", "findings", "srw", "workshop"] + # papers.{html,json} papers = build_papers( raw_papers=site_data["main_papers"] @@ -653,6 +667,7 @@ def build_papers( paper_type=item.get("paper_type", ""), sessions=sessions_for_paper[item["UID"]], similar_paper_uids=paper_recs.get(item["UID"], [item["UID"]]), + program=item["program"], ), ) for item in raw_papers @@ -711,6 +726,11 @@ def build_workshops( raw_workshop_papers: Dict[str, List[Dict[str, Any]]], workshop_schedules: Dict[str, List[Dict[str, Any]]], ) -> List[Workshop]: + def workshop_title(workshop_id): + for wsh in raw_workshops: + if wsh["UID"] == workshop_id: + return wsh["title"] + return "" workshop_papers: DefaultDict[str, List[WorkshopPaper]] = defaultdict(list) for workshop_id, papers in raw_workshop_papers.items(): @@ -720,7 +740,21 @@ def build_workshops( id=item["UID"], title=item["title"], speakers=item["speakers"], - presentation_id=item.get("presentation_id", ""), + presentation_id=item.get("presentation_id", None), + content=PaperContent( + title=item["title"], + authors=[item["speakers"]], + track=workshop_title(workshop_id), + paper_type=None, + abstract=None, + tldr=None, + keywords=[], + pdf_url=None, + demo_url=None, + sessions=[], + similar_paper_uids=[], + program="workshop", + ), ) ) diff --git a/miniconf/site_data.py b/miniconf/site_data.py index 797111f..26b0279 100644 --- a/miniconf/site_data.py +++ b/miniconf/site_data.py @@ -63,16 +63,19 @@ class PaperContent: demo_url: Optional[str] sessions: List[SessionInfo] similar_paper_uids: List[str] + program: str def __post_init__(self): - assert self.track, self + if self.program != "workshop": + assert self.track, self if self.pdf_url: assert self.pdf_url.startswith("https://"), self.pdf_url if self.demo_url: assert self.demo_url.startswith("https://") or self.demo_url.startswith( "http://" ), self.demo_url - assert self.paper_type[0].isupper(), self + if self.program != "workshop": + assert self.paper_type[0].isupper(), self @dataclass(frozen=True) @@ -178,6 +181,7 @@ class WorkshopPaper: title: str speakers: str presentation_id: Optional[str] + content: PaperContent @dataclass(frozen=True) diff --git a/static/css/main.css b/static/css/main.css index 87b5e26..9ab5f20 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -585,3 +585,21 @@ div#papers_options > div { .card-link-warning { color: #ffc107 !important; } + +.button-box { + display: flex; +} + +.bottom-bar { + margin-bottom: 0em; +} + +@media (max-width: 768px) { + .button-box { + display: block; + } + + .bottom-bar { + margin-bottom: 1em; + } +} diff --git a/static/js/little_helpers.js b/static/js/little_helpers.js index 7782ea5..427a6ac 100644 --- a/static/js/little_helpers.js +++ b/static/js/little_helpers.js @@ -81,15 +81,18 @@ let calcAllKeys = function (allPapers, allKeys) { const collectAuthors = new Set(); const collectKeywords = new Set(); const collectSessions = new Set(); + const collectTracks = new Set(); allPapers.forEach( d => { d.content.authors.forEach(a => collectAuthors.add(a)); d.content.keywords.forEach(a => collectKeywords.add(a)); d.content.sessions.forEach(a => collectSessions.add(a)); + collectTracks.add(d.content.track); allKeys.titles.push(d.content.title); }); allKeys.authors = Array.from(collectAuthors); allKeys.keywords = Array.from(collectKeywords); allKeys.sessions = Array.from(collectSessions); + allKeys.tracks = Array.from(collectTracks).sort(); }; diff --git a/static/js/papers.js b/static/js/papers.js index 4fab76c..9da418b 100644 --- a/static/js/papers.js +++ b/static/js/papers.js @@ -118,6 +118,17 @@ const setUpKeyBindings = () => { const persistor = new Persistor('Mini-Conf-Papers'); const favPersistor = new Persistor('Mini-Conf-Favorite-Papers'); +const updateTrackList = (tracks, default_track) => { + default_track = default_track || "All tracks"; + + tracks = Array.from([default_track]).concat(tracks); + let optionsHtml = tracks.map(track_html); + + $('#track_selector').html(optionsHtml); + $('#track_selector').selectpicker('refresh'); + $('#track_selector').selectpicker('val', default_track); +} + const updateCards = (papers) => { const storedPapers = persistor.getAll(); const favPapers = favPersistor.getAll(); @@ -207,8 +218,23 @@ const openQuickviewModal = (paper) => { $('#quickviewModal').modal('show') } +const maybe_update = (element_ids, value, callback) => { + if (value && ( + (typeof value == "string" && value !== "") || + (Array.isArray(value) && value.length > 0 ))) + element_ids.forEach(x => $(x).show()); + else + element_ids.forEach(x => $(x).hide()); + + callback(value); +} + const updateModalData = (paper) => { - $('#modalTitle').text(paper.content.title); + + let program = paper.content.program; + let badgeClass = program_to_badge_class[program]; + $('#modalTitle').html( + `${paper.content.title}   ${program}`); let isVisited = persistor.get(paper.id) || false if (isVisited) @@ -217,23 +243,56 @@ const updateModalData = (paper) => { $('#modalTitle').removeClass('card-title-visited'); let authorsHtml = paper.content.authors.map(author_html).join(', '); - $('#modalAuthors').html(authorsHtml); - - $('#modalPaperType').text(paper.content.paper_type); - $('#modalPaperTrack').text(paper.content.track); - - $('#modalAbstract').text(paper.content.abstract); + maybe_update( + ["#modalAuthors"], + authorsHtml, + x => $('#modalAuthors').html(x)); - $('#modalChatUrl').attr('href', `https://${chat_server}/channel/paper-${paper.id.replace('.', '-')}`); - $('#modalPresUrl').attr('href', `https://slideslive.com/${paper.presentation_id}`); - $('#modalPaperUrl').attr('href', paper.content.pdf_url); - $('#modalPaperPage').attr('href', `paper_${paper.id}.html`); + + maybe_update( + ['#modalPaperType'], + paper.content.paper_type, + x => $('#modalPaperType').text(x)); + maybe_update( + ['#modalPaperTrack'], + paper.content.track, + x => $('#modalPaperTrack').text(x)); + + maybe_update( + ['#modalAbstract', '#modalAbstractHeader'], + paper.content.abstract, + x => $('#modalAbstract').text(x)); + + if (program != "workshop"){ + $('#modalChatUrl').attr('href', `https://${chat_server}/channel/paper-${paper.id.replace('.', '-')}`); + $('#modalPaperPage').attr('href', `paper_${paper.id}.html`); + } else { + $('#modalChatUrl').hide(); + $('#modalPaperPage').hide(); + } + + maybe_update( + ['#modalPresUrl'], + paper.presentation_id, + x => $('#modalPresUrl').attr('href', `https://slideslive.com/${x}`)); + maybe_update( + ['#modalPaperUrl'], + paper.content.pdf_url, + x => $('#modalPaperUrl').attr('href', x)); + let keywordsHtml = paper.content.keywords.map(modal_keyword).join('\n'); - $('#modalKeywords').html(keywordsHtml); + maybe_update( + ['#modalKeywords', '#modalKeywordsHeader'], + paper.content.keywords, + x => $('#modalKeywords').html(keywordsHtml)); let sessionsHtml = paper.content.sessions.map(s => modal_session_html(s, paper)).join('\n'); $('#modalSessions').html(sessionsHtml); + maybe_update( + ['#modalSessions', '#modalSessionsHeader'], + paper.content.sessions, + x => $('#modalSessions').html(sessionsHtml)); $('#modalPaperPage').unbind( "click" ); $('#modalPaperPage').click(() => { @@ -388,38 +447,68 @@ const updateSession = () => { } } +const updateToolboxUI = (program, urlFilter, track) =>{ + updateFilterSelectionBtn(urlFilter); + + // Update program selector UI + document.querySelector(`input[name=program][value=${program}]`).checked = true; + + if (["main", "workshop"].includes(program)) { + $("#track_selector").selectpicker('show'); + $("#track_selector_placeholder").removeClass("d-lg-block"); + } else{ + $("#track_selector").selectpicker('hide'); + $("#track_selector_placeholder").addClass("d-lg-block"); + } +} + /** * START here and load JSON. */ -const start = (track) => { - // const urlFilter = getUrlParameter("filter") || 'keywords'; +const start = (reset_track) => { + + reset_track = reset_track || false; + const urlFilter = getUrlParameter("filter") || 'titles'; + const program = getUrlParameter("program") || 'main' + let default_track = program == "workshop"? "All workshops" : "All tracks"; + + let track = getUrlParameter("track") || default_track; + if (reset_track) + track = default_track; setQueryStringParameter("filter", urlFilter); - updateFilterSelectionBtn(urlFilter); + setQueryStringParameter("program", program); - var path_to_papers_json; - if (track === "All tracks") { - path_to_papers_json = "papers.json"; + updateToolboxUI(program, urlFilter, track) + + let path_to_papers_json; + if (program === "all"){ + path_to_papers_json = `papers.json`; + } else if (track === default_track) { + path_to_papers_json = `papers_${program}.json`; } else { - path_to_papers_json = "track_" + track + ".json"; + path_to_papers_json = `track_${program}_${track}.json`; } + $('.cards').empty(); + $('#progressBar').show(); + d3.json(path_to_papers_json).then(papers => { shuffleArray(papers); allPapers = papers; - - $('#progressBar').hide(); calcAllKeys(allPapers, allKeys); + if (path_to_papers_json.startsWith("papers")) + updateTrackList(allKeys.tracks, default_track); + setTypeAhead(urlFilter, allKeys, filters, render); - // updateCards(allPapers); render(); - }).catch(e => console.error(e)) + }).catch(e => console.error(e)); }; @@ -453,6 +542,14 @@ d3.selectAll('.render_option input').on('click', function () { render(); }); +d3.selectAll('.program_option input').on('click', function () { + const me = d3.select(this); + let program = me.property('value'); + setQueryStringParameter("program", program); + + start(reset_track=true); +}); + d3.select('.visited').on('click', () => { sortSelectedFirst(allPapers); @@ -471,6 +568,8 @@ d3.select('.reshuffle').on('click', () => { * CARDS */ +const track_html = track => ``; + const keyword = kw => `${kw.toLowerCase()}`; @@ -504,6 +603,21 @@ const card_fav_btn_html = (is_fav) => { } } +const program_to_badge_class = new Map() +program_to_badge_class["main"] = "danger"; +program_to_badge_class["demo"] = "primary"; +program_to_badge_class["findings"] = "warning"; +program_to_badge_class["workshop"] = "info"; +const card_program_badge = (paper) => { + let selected_program = getUrlParameter("program"); + if (selected_program === "all") + return `${paper.content.program}`; + else + return ``; +} + //language=HTML const card_html = openreview => `
${openreview.content.authors.join(', ')} + ${card_program_badge(openreview)} + ${card_image(openreview, render_mode !== 'list')} ${card_detail(openreview, (render_mode === 'detail'))} diff --git a/templates/papers.html b/templates/papers.html index 0954ca0..c737bf7 100644 --- a/templates/papers.html +++ b/templates/papers.html @@ -101,21 +101,73 @@
+
+
-
+
+ +
+
+ + + + + + +
+
+
@@ -257,18 +309,24 @@
Sessions
$(document).ready(function () { tippy("[data-tippy-content]", { trigger: "mouseenter focus" }); - const track = getUrlParameter("track") || "All tracks"; + const program = getUrlParameter("program") || 'main' + let track = "" + if (program !== "workshop") { + track = getUrlParameter("track") || 'All tracks' + } else { + track = getUrlParameter("track") || 'All workshops' + } updateTabs(); - // start(track); - $('#track_selector').selectpicker('val', track); + start(); }); $('#track_selector').on('changed.bs.select', function (e, clickedIndex, isSelected, previousValue) { let track = e.target.value; + if (track === previousValue) return; setQueryStringParameter("track", track); - start(track); + start(); }); $('#tabBrowse').click(()=>{