Create schedule.js

This commit is contained in:
Mimi 2020-08-06 15:27:14 +08:00
parent 6814b16aba
commit 4f192213b3
7 changed files with 148 additions and 146 deletions

View File

@ -20,8 +20,7 @@ labels:
labeled:
issue:
body: |
:wave: Hey there! we use the issue tracker exclusively for bug reports
and feature requests. However, this issue appears to be a support request.
:wave: Hey there! we use the issue tracker exclusively for bug reports and feature requests. However, this issue appears to be a support request.
Please use our [support channels](https://github.com/next-theme/hexo-theme-next#feedback) to get help with the project.
action: close
- name: Wontfix

1
.github/stale.yml vendored
View File

@ -10,7 +10,6 @@ exemptLabels:
- Feature Request
- Discussion
- Help Wanted
- Question
# Label to use when marking as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable

View File

@ -4,11 +4,11 @@
You can use internationalization to present your site in different languages. The default language is set by modifying the `language` setting in Hexo `_config.yml`. You can also set multiple languages and modify the order of default languages.
```yaml
```yml
language: en
```
```yaml
```yml
language:
- zh-CN
- en
@ -21,7 +21,7 @@ If you would like to customize the default translation, you do not need to modif
1. Creat a `languages.yml` in `source/_data`.
2. Insert following codes: (be careful about the two-space indent)
```yaml
```yml
# language
zh-CN:
# items

View File

@ -1,138 +1,4 @@
<script{{ pjax }}>
(function() {
// Initialization
const calendar = {
orderBy : 'startTime',
showLocation: false,
offsetMax : 72,
offsetMin : 4,
showDeleted : false,
singleEvents: true,
maxResults : 250
};
// Read config form theme config file
Object.assign(calendar, {{ theme.calendar | safedump }});
const now = new Date();
const timeMax = new Date();
const timeMin = new Date();
timeMax.setHours(now.getHours() + calendar.offsetMax);
timeMin.setHours(now.getHours() - calendar.offsetMin);
// Build URL
const params = {
key : calendar.api_key,
orderBy : calendar.orderBy,
timeMax : timeMax.toISOString(),
timeMin : timeMin.toISOString(),
showDeleted : calendar.showDeleted,
singleEvents: calendar.singleEvents,
maxResults : calendar.maxResults
};
const request_url = 'https://www.googleapis.com/calendar/v3/calendars/' + calendar.calendar_id + '/events?' + Object.entries(params).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join('&');
function getRelativeTime(current, previous) {
const msPerMinute = 60 * 1000;
const msPerHour = msPerMinute * 60;
const msPerDay = msPerHour * 24;
const msPerMonth = msPerDay * 30;
const msPerYear = msPerDay * 365;
let elapsed = current - previous;
const tense = elapsed > 0 ? ' ago' : ' later';
elapsed = Math.abs(elapsed);
if (elapsed < msPerHour) {
return Math.round(elapsed / msPerMinute) + ' minutes' + tense;
} else if (elapsed < msPerDay) {
return Math.round(elapsed / msPerHour) + ' hours' + tense;
} else if (elapsed < msPerMonth) {
return 'about ' + Math.round(elapsed / msPerDay) + ' days' + tense;
} else if (elapsed < msPerYear) {
return 'about ' + Math.round(elapsed / msPerMonth) + ' months' + tense;
}
return 'about ' + Math.round(elapsed / msPerYear) + ' years' + tense;
}
function buildEventDOM(tense, event) {
const start = event.start.dateTime;
const end = event.end.dateTime;
const durationFormat = {
weekday: 'short',
hour : '2-digit',
minute : '2-digit'
};
const relativeTime = tense === 'now' ? 'NOW' : getRelativeTime(now, start);
const duration = start.toLocaleTimeString([], durationFormat) + ' - ' + end.toLocaleTimeString([], durationFormat);
let location = '';
if (calendar.showLocation && event.location) {
location = `<span class="event-location event-details">${event.location}</span>`;
}
let description = '';
if (event.description) {
description = `<span class="event-description event-details">${event.description}</span>`;
}
const eventContent = `<section class="event event-${tense}">
<h2 class="event-summary">
${event.summary}
<span class="event-relative-time">${relativeTime}</span>
</h2>
${location}
<span class="event-duration event-details">${duration}</span>
${description}
</section>`;
return eventContent;
}
function fetchData() {
const eventList = document.querySelector('.event-list');
if (!eventList) return;
fetch(request_url).then(response => {
return response.json();
}).then(data => {
if (data.items.length === 0) {
eventList.innerHTML = '<hr>';
return;
}
// Clean the event list
eventList.innerHTML = '';
let prevEnd = 0; // used to decide where to insert an <hr>
data.items.forEach(event => {
// Parse data
const utc = new Date().getTimezoneOffset() * 60000;
const start = event.start.dateTime = new Date(event.start.dateTime || (new Date(event.start.date).getTime() + utc));
const end = event.end.dateTime = new Date(event.end.dateTime || (new Date(event.end.date).getTime() + utc));
let tense = 'now';
if (end < now) {
tense = 'past';
} else if (start > now) {
tense = 'future';
}
if (tense === 'future' && prevEnd < now) {
eventList.innerHTML += '<hr>';
}
eventList.innerHTML += buildEventDOM(tense, event);
prevEnd = end;
});
});
}
fetchData();
const fetchDataTimer = setInterval(fetchData, 60000);
document.addEventListener('pjax:send', () => {
clearInterval(fetchDataTimer);
});
})();
CONFIG.calendar = {{ theme.calendar | safedump }};
</script>
{{- next_js('schedule.js', true) }}

View File

@ -15,17 +15,17 @@ hexo.extend.helper.register('next_inject', function(point) {
.join('');
});
hexo.extend.helper.register('next_js', function(url) {
hexo.extend.helper.register('next_js', function(url, pjax = false) {
const { next_version } = this;
const { js } = this.theme;
const { internal } = this.theme.vendors;
let src = `${js}/${url}`;
let src = this.url_for(`${js}/${url}`);
if (internal === 'jsdelivr') {
src = `//cdn.jsdelivr.net/npm/hexo-theme-next@${next_version}/source/js/${url}`;
} else if (internal === 'unpkg') {
src = `//unpkg.com/hexo-theme-next@${next_version}/source/js/${url}`;
}
return this.js(src);
return `<script ${pjax ? 'data-pjax ' : ''}src="${src}"></script>`;
});
hexo.extend.helper.register('post_edit', function(src) {

View File

@ -11,8 +11,8 @@
flex: 1;
img {
margin: 0;
height: 100%;
margin: 0;
object-fit: cover;
width: 100%;
}

138
source/js/schedule.js Normal file
View File

@ -0,0 +1,138 @@
/* global CONFIG */
(function() {
// Initialization
const calendar = {
orderBy : 'startTime',
showLocation: false,
offsetMax : 72,
offsetMin : 4,
showDeleted : false,
singleEvents: true,
maxResults : 250
};
// Read config form theme config file
Object.assign(calendar, CONFIG.calendar);
const now = new Date();
const timeMax = new Date();
const timeMin = new Date();
timeMax.setHours(now.getHours() + calendar.offsetMax);
timeMin.setHours(now.getHours() - calendar.offsetMin);
// Build URL
const params = {
key : calendar.api_key,
orderBy : calendar.orderBy,
timeMax : timeMax.toISOString(),
timeMin : timeMin.toISOString(),
showDeleted : calendar.showDeleted,
singleEvents: calendar.singleEvents,
maxResults : calendar.maxResults
};
const request_url = 'https://www.googleapis.com/calendar/v3/calendars/' + calendar.calendar_id + '/events?' + Object.entries(params).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join('&');
function getRelativeTime(current, previous) {
const msPerMinute = 60 * 1000;
const msPerHour = msPerMinute * 60;
const msPerDay = msPerHour * 24;
const msPerMonth = msPerDay * 30;
const msPerYear = msPerDay * 365;
let elapsed = current - previous;
const tense = elapsed > 0 ? ' ago' : ' later';
elapsed = Math.abs(elapsed);
if (elapsed < msPerHour) {
return Math.round(elapsed / msPerMinute) + ' minutes' + tense;
} else if (elapsed < msPerDay) {
return Math.round(elapsed / msPerHour) + ' hours' + tense;
} else if (elapsed < msPerMonth) {
return 'about ' + Math.round(elapsed / msPerDay) + ' days' + tense;
} else if (elapsed < msPerYear) {
return 'about ' + Math.round(elapsed / msPerMonth) + ' months' + tense;
}
return 'about ' + Math.round(elapsed / msPerYear) + ' years' + tense;
}
function buildEventDOM(tense, event) {
const start = event.start.dateTime;
const end = event.end.dateTime;
const durationFormat = {
weekday: 'short',
hour : '2-digit',
minute : '2-digit'
};
const relativeTime = tense === 'now' ? 'NOW' : getRelativeTime(now, start);
const duration = start.toLocaleTimeString([], durationFormat) + ' - ' + end.toLocaleTimeString([], durationFormat);
let location = '';
if (calendar.showLocation && event.location) {
location = `<span class="event-location event-details">${event.location}</span>`;
}
let description = '';
if (event.description) {
description = `<span class="event-description event-details">${event.description}</span>`;
}
const eventContent = `<section class="event event-${tense}">
<h2 class="event-summary">
${event.summary}
<span class="event-relative-time">${relativeTime}</span>
</h2>
${location}
<span class="event-duration event-details">${duration}</span>
${description}
</section>`;
return eventContent;
}
function fetchData() {
const eventList = document.querySelector('.event-list');
if (!eventList) return;
fetch(request_url).then(response => {
return response.json();
}).then(data => {
if (data.items.length === 0) {
eventList.innerHTML = '<hr>';
return;
}
// Clean the event list
eventList.innerHTML = '';
let prevEnd = 0; // used to decide where to insert an <hr>
data.items.forEach(event => {
// Parse data
const utc = new Date().getTimezoneOffset() * 60000;
const start = event.start.dateTime = new Date(event.start.dateTime || (new Date(event.start.date).getTime() + utc));
const end = event.end.dateTime = new Date(event.end.dateTime || (new Date(event.end.date).getTime() + utc));
let tense = 'now';
if (end < now) {
tense = 'past';
} else if (start > now) {
tense = 'future';
}
if (tense === 'future' && prevEnd < now) {
eventList.innerHTML += '<hr>';
}
eventList.innerHTML += buildEventDOM(tense, event);
prevEnd = end;
});
});
}
fetchData();
const fetchDataTimer = setInterval(fetchData, 60000);
document.addEventListener('pjax:send', () => {
clearInterval(fetchDataTimer);
});
})();