Page MenuHomeSoftware Heritage

No OneTemporary

diff --git a/cypress/integration/origin-visits.spec.js b/cypress/integration/origin-visits.spec.js
index f0b1b000..3f2a7897 100644
--- a/cypress/integration/origin-visits.spec.js
+++ b/cypress/integration/origin-visits.spec.js
@@ -1,78 +1,94 @@
/**
* Copyright (C) 2019-2020 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU Affero General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
import {getTime} from '../utils';
let origin;
function checkTimeLink(element) {
expect(element.text()).not.to.be.empty;
const urlParams = new URLSearchParams(element.attr('href').split('?')[1]);
const timeStringLink = urlParams.get('timestamp');
// time in link should be equal to that in text
assert.deepEqual(getTime(timeStringLink), getTime(element.text()));
}
function searchInCalendar(date) {
cy.contains('label', 'Show all visits')
.click();
cy.get(`.year${date.year}`)
.click({force: true});
cy.contains('.month', date.monthName)
.find('.day-content')
.eq(date.date - 1)
.trigger('mouseenter')
.get('.popover-body')
.should('be.visible')
.and('contain', `${date.hours}:${date.minutes} UTC`);
}
describe('Visits tests', function() {
before(function() {
origin = this.origin[1];
});
beforeEach(function() {
cy.visit(`${this.Urls.browse_origin_visits()}?origin_url=${origin.url}`);
});
it('should display first full visit time', function() {
cy.get('#swh-first-full-visit > .swh-visit-full')
.then(($el) => {
checkTimeLink($el);
searchInCalendar(getTime($el.text()));
});
});
it('should display last full visit time', function() {
cy.get('#swh-last-full-visit > .swh-visit-full')
.then(($el) => {
checkTimeLink($el);
searchInCalendar(getTime($el.text()));
});
});
it('should display last visit time', function() {
cy.get('#swh-last-visit > .swh-visit-full')
.then(($el) => {
checkTimeLink($el);
searchInCalendar(getTime($el.text()));
});
});
it('should display list of visits and mark them on calendar', function() {
cy.get('.swh-visits-list-row .swh-visit-full')
.should('be.visible')
.each(($el) => {
checkTimeLink($el);
searchInCalendar(getTime($el.text()));
});
});
+
+ it('should close calendar popover when leaving day', function() {
+ cy.get('#swh-last-visit > .swh-visit-full')
+ .then(($el) => {
+ const date = getTime($el.text());
+ searchInCalendar(date);
+ cy.contains('.month', date.monthName)
+ .find('.day-content')
+ .eq(date.date - 1)
+ .trigger('mouseout');
+
+ cy.get('.popover')
+ .should('not.be.visible');
+ });
+ });
+
});
diff --git a/swh/web/assets/src/bundles/origin/visits-calendar.js b/swh/web/assets/src/bundles/origin/visits-calendar.js
index 92dd919e..3617e958 100644
--- a/swh/web/assets/src/bundles/origin/visits-calendar.js
+++ b/swh/web/assets/src/bundles/origin/visits-calendar.js
@@ -1,140 +1,147 @@
/**
* Copyright (C) 2018-2019 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU Affero General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
import Calendar from 'js-year-calendar';
import 'js-year-calendar/dist/js-year-calendar.css';
let minSize = 15;
let maxSize = 28;
let currentPopover = null;
let visitsByDate = {};
function closePopover() {
if (currentPopover) {
- $(currentPopover).popover('hide');
+ $(currentPopover).popover('dispose');
currentPopover = null;
}
}
// function to update the visits calendar view based on the selected year
export function updateCalendar(year, filteredVisits, yearClickedCallback) {
visitsByDate = {};
let maxNbVisitsByDate = 0;
let minDate, maxDate;
for (let i = 0; i < filteredVisits.length; ++i) {
filteredVisits[i]['startDate'] = filteredVisits[i]['date'];
filteredVisits[i]['endDate'] = filteredVisits[i]['startDate'];
let date = new Date(filteredVisits[i]['date']);
date.setHours(0, 0, 0, 0);
let dateStr = date.toDateString();
if (!visitsByDate.hasOwnProperty(dateStr)) {
visitsByDate[dateStr] = [filteredVisits[i]];
} else {
visitsByDate[dateStr].push(filteredVisits[i]);
}
maxNbVisitsByDate = Math.max(maxNbVisitsByDate, visitsByDate[dateStr].length);
if (i === 0) {
minDate = maxDate = date;
} else {
if (date.getTime() < minDate.getTime()) {
minDate = date;
}
if (date.getTime() > maxDate.getTime()) {
maxDate = date;
}
}
}
closePopover();
new Calendar('#swh-visits-calendar', {
dataSource: filteredVisits,
style: 'custom',
minDate: minDate,
maxDate: maxDate,
startYear: year,
renderEnd: e => yearClickedCallback(e.currentYear),
customDataSourceRenderer: (element, date, events) => {
let dateStr = date.toDateString();
let nbVisits = visitsByDate[dateStr].length;
let t = nbVisits / maxNbVisitsByDate;
if (maxNbVisitsByDate === 1) {
t = 0;
}
let size = minSize + t * (maxSize - minSize);
let offsetX = (maxSize - size) / 2 - parseInt($(element).css('padding-left'));
let offsetY = (maxSize - size) / 2 - parseInt($(element).css('padding-top')) + 1;
let cellWrapper = $('<div></div>');
cellWrapper.css('position', 'relative');
let dayNumber = $('<div></div>');
dayNumber.text($(element).text());
let circle = $('<div></div>');
let r = 0;
let g = 0;
for (let i = 0; i < nbVisits; ++i) {
let visit = visitsByDate[dateStr][i];
if (visit.status === 'full') {
g += 255;
} else if (visit.status === 'partial') {
r += 255;
g += 255;
} else {
r += 255;
}
}
r /= nbVisits;
g /= nbVisits;
circle.css('background-color', 'rgba(' + r + ', ' + g + ', 0, 0.3)');
circle.css('width', size + 'px');
circle.css('height', size + 'px');
circle.css('border-radius', size + 'px');
circle.css('position', 'absolute');
circle.css('top', offsetY + 'px');
circle.css('left', offsetX + 'px');
cellWrapper.append(dayNumber);
cellWrapper.append(circle);
$(element)[0].innerHTML = $(cellWrapper)[0].outerHTML;
},
mouseOnDay: e => {
if (currentPopover !== e.element) {
closePopover();
}
let dateStr = e.date.toDateString();
if (visitsByDate.hasOwnProperty(dateStr)) {
let visits = visitsByDate[dateStr];
let content = '<div><h6>' + e.date.toDateString() + '</h6></div>';
content += '<ul style="list-style-type: none;">';
for (let i = 0; i < visits.length; ++i) {
let visitTime = visits[i].formatted_date.substr(visits[i].formatted_date.indexOf(',') + 2);
content += '<li><a class="swh-visit-' + visits[i].status + '" title="' + visits[i].status +
' visit" href="' + visits[i].url + '">' + visitTime + '</a></li>';
}
content += '</ul>';
$(e.element).popover({
trigger: 'manual',
container: 'body',
html: true,
content: content
+ }).on('mouseleave', () => {
+ if (!$('.popover:hover').length) {
+ // close popover when leaving day in calendar
+ // except if the pointer is hovering it
+ closePopover();
+ }
+ });
+
+ $(e.element).on('shown.bs.popover', () => {
+ $('.popover').mouseleave(() => {
+ // close popover when pointer leaves it
+ closePopover();
+ });
});
$(e.element).popover('show');
currentPopover = e.element;
}
}
});
- $('#swh-visits-timeline').mouseenter(() => {
- closePopover();
- });
- $('#swh-visits-list').mouseenter(() => {
- closePopover();
- });
$('#swh-visits-calendar.calendar table td').css('width', maxSize + 'px');
$('#swh-visits-calendar.calendar table td').css('height', maxSize + 'px');
$('#swh-visits-calendar.calendar table td').css('padding', '0px');
}

File Metadata

Mime Type
text/x-diff
Expires
Jul 4 2025, 9:54 AM (5 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3262298

Event Timeline