Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ bower_components
#Icon?
ehthumbs.db
Thumbs.db
app/styles/*.css
app/styles/*.css.map
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Timetable.js
Vanilla javascript plugin for building nice responsive timetables. Provides a simple javascript interface to add events and locations which can be rendered to nice HTML. Works on mobile devices as well.
Vanilla javascript plugin for building nice responsive timetables. Provides a simple javascript interface to add events and locations which can be rendered to nice HTML. Works on mobile devices as well.

## Just show me the demo
Okay: [**demo**](http://timetablejs.grible.co). Also, have a look at the website: [http://timetablejs.org](http://timetablejs.org).
Expand Down
16 changes: 14 additions & 2 deletions app/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,22 @@ <h1>Timetable.js demo</h1>
<script>
var timetable = new Timetable();

timetable.setScope(9,3)
timetable.setScope(9,3);

timetable.addLocations(['Rotterdam', 'Madrid', 'Los Angeles', 'London', 'New York', 'Jakarta', 'Tokyo']);
timetable.addLocations(['Rotterdam', 'Madrid']);

timetable.addLocations(
[
{ id: 'Petersburg', title: 'St.Petersburg', href: 'http://www.visit-petersburg.ru/en/'},
{ id: 'Los Angeles', title: 'Los Angeles'},
{ id: 'London', title: 'London'},
{ id: 'New York', title: 'New York'},
{ id: 'Jakarta', title: 'Jakarta'},
{ id: 'Tokyo', title: 'Tokyo'}
]
);

timetable.addEvent('Beer party', 'Petersburg', new Date(2015,7,17,19,00), new Date(2015,7,18,08,00), { url: '#' });
timetable.addEvent('Sightseeing', 'Rotterdam', new Date(2015,7,17,9,00), new Date(2015,7,17,11,30), { url: '#' });
timetable.addEvent('Zumba', 'Madrid', new Date(2015,7,17,12), new Date(2015,7,17,13), { url: '#' });
timetable.addEvent('Zumbu', 'Madrid', new Date(2015,7,17,13,30), new Date(2015,7,17,15), { url: '#' });
Expand Down
54 changes: 41 additions & 13 deletions app/scripts/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,23 @@ Timetable.Renderer = function(tt) {
return number === parseInt(number, 10);
}
function isInHourRange(number) {
return number >= 0 && number < 24;
return number >= 0 && number < 25;
}
function locationExistsIn(loc, locs) {
return locs.indexOf(loc) !== -1;
for (var k=0; k<locs.length; k++) {
if (loc === locs[k].id) {
return true;
}
}
return false;
}
function isValidTimeRange(start, end) {
var correctTypes = start instanceof Date && end instanceof Date;
var correctOrder = start < end;
return correctTypes && correctOrder;
}
function getDurationHours(startHour, endHour) {
return endHour >= startHour ? endHour - startHour : 24 + endHour - startHour;
return endHour >= startHour ? endHour - startHour : 25 + endHour - startHour;
}

Timetable.prototype = {
Expand All @@ -49,27 +54,43 @@ Timetable.Renderer = function(tt) {
this.scope.hourStart = start;
this.scope.hourEnd = end;
} else {
throw new RangeError('Timetable scope should consist of (start, end) in whole hours from 0 to 23');
throw new RangeError('Timetable scope should consist of (start, end) in whole hours from 0 to 24');
}

return this;
},
addLocations: function(newLocations) {
function hasProperFormat() {
return newLocations instanceof Array;
return newLocations instanceof Array && typeof newLocations[0] === 'string';
}

function hasExtendFormat() {
return newLocations instanceof Array && newLocations[0] instanceof Object;
}

var existingLocations = this.locations;

if (hasProperFormat()) {
newLocations.forEach(function(loc) {
if (!locationExistsIn(loc, existingLocations)) {
existingLocations.push({
id: loc,
title: loc
});
} else {
throw new Error('Location already exists');
}
});
} else if (hasExtendFormat()) {
newLocations.forEach(function(loc) {
if (!locationExistsIn(loc, existingLocations)) {
existingLocations.push(loc);
} else {
throw new Error('Location already exists');
}
});
} else {
}
else {
throw new Error('Tried to add locations in wrong format');
}

Expand All @@ -80,7 +101,8 @@ Timetable.Renderer = function(tt) {
throw new Error('Unknown location');
}
if (!isValidTimeRange(start, end)) {
throw new Error('Invalid time range: ' + JSON.stringify([start, end]));
console.log('Invalid time range: ' + JSON.stringify([start, end]));
return;
}

var optionsHasValidType = Object.prototype.toString.call(options) === '[object Object]';
Expand Down Expand Up @@ -122,10 +144,16 @@ Timetable.Renderer = function(tt) {
}
function appendRowHeaders(ulNode) {
for (var k=0; k<timetable.locations.length; k++) {
var url = timetable.locations[k].href;
var liNode = ulNode.appendChild(document.createElement('li'));
var spanNode = liNode.appendChild(document.createElement('span'));
if (url !== undefined) {
var aNode = liNode.appendChild(document.createElement('a'));
aNode.href = timetable.locations[k].href;
aNode.appendChild(spanNode);
}
spanNode.className = 'row-heading';
spanNode.textContent = timetable.locations[k];
spanNode.textContent = timetable.locations[k].title;
}
}
function appendTimetableSection(container) {
Expand All @@ -150,7 +178,7 @@ Timetable.Renderer = function(tt) {
if (hour === timetable.scope.hourEnd && (timetable.scope.hourStart !== timetable.scope.hourEnd || looped)) {
completed = true;
}
if (++hour === 24) {
if (++hour === 25) {
hour = 0;
looped = true;
}
Expand All @@ -167,7 +195,7 @@ Timetable.Renderer = function(tt) {
function appendLocationEvents(location, node) {
for (var k=0; k<timetable.events.length; k++) {
var event = timetable.events[k];
if (event.location === location) {
if (event.location === location.id) {
appendEvent(event, node);
}
}
Expand All @@ -177,9 +205,9 @@ Timetable.Renderer = function(tt) {
var hasURL, hasAdditionalClass, hasDataAttributes = false;

if(hasOptions) {
hasURL = (event.options.url !== undefined) ? true : false;
hasAdditionalClass = (event.options.class !== undefined) ? true : false;
hasDataAttributes = (event.options.data !== undefined) ? true : false;
hasURL = event.options.url !== undefined;
hasAdditionalClass = event.options.class !== undefined;
hasDataAttributes = event.options.data !== undefined;
}

var elementType = hasURL ? 'a' : 'span';
Expand Down
8 changes: 4 additions & 4 deletions app/styles/demo.sass
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
body
background: #fcfcfc
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif
color: #333
font-size: 15px
background: #fcfcfc
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif
color: #333
font-size: 15px

a
text-decoration: none
Expand Down
16 changes: 14 additions & 2 deletions dist/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,22 @@ <h1>Timetable.js demo</h1>
<script>
var timetable = new Timetable();

timetable.setScope(9,3)
timetable.setScope(9,3);

timetable.addLocations(['Rotterdam', 'Madrid', 'Los Angeles', 'London', 'New York', 'Jakarta', 'Tokyo']);
timetable.addLocations(['Rotterdam', 'Madrid']);

timetable.addLocations(
[
{ id: 'Petersburg', title: 'St.Petersburg', href: 'http://www.visit-petersburg.ru/en/'},
{ id: 'Los Angeles', title: 'Los Angeles'},
{ id: 'London', title: 'London'},
{ id: 'New York', title: 'New York'},
{ id: 'Jakarta', title: 'Jakarta'},
{ id: 'Tokyo', title: 'Tokyo'}
]
);

timetable.addEvent('Beer party', 'Petersburg', new Date(2015,7,17,19,00), new Date(2015,7,18,08,00), { url: '#' });
timetable.addEvent('Sightseeing', 'Rotterdam', new Date(2015,7,17,9,00), new Date(2015,7,17,11,30), { url: '#' });
timetable.addEvent('Zumba', 'Madrid', new Date(2015,7,17,12), new Date(2015,7,17,13), { url: '#' });
timetable.addEvent('Zumbu', 'Madrid', new Date(2015,7,17,13,30), new Date(2015,7,17,15), { url: '#' });
Expand Down
54 changes: 41 additions & 13 deletions dist/scripts/timetable.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,23 @@ Timetable.Renderer = function(tt) {
return number === parseInt(number, 10);
}
function isInHourRange(number) {
return number >= 0 && number < 24;
return number >= 0 && number < 25;
}
function locationExistsIn(loc, locs) {
return locs.indexOf(loc) !== -1;
for (var k=0; k<locs.length; k++) {
if (loc === locs[k].id) {
return true;
}
}
return false;
}
function isValidTimeRange(start, end) {
var correctTypes = start instanceof Date && end instanceof Date;
var correctOrder = start < end;
return correctTypes && correctOrder;
}
function getDurationHours(startHour, endHour) {
return endHour >= startHour ? endHour - startHour : 24 + endHour - startHour;
return endHour >= startHour ? endHour - startHour : 25 + endHour - startHour;
}

Timetable.prototype = {
Expand All @@ -49,27 +54,43 @@ Timetable.Renderer = function(tt) {
this.scope.hourStart = start;
this.scope.hourEnd = end;
} else {
throw new RangeError('Timetable scope should consist of (start, end) in whole hours from 0 to 23');
throw new RangeError('Timetable scope should consist of (start, end) in whole hours from 0 to 24');
}

return this;
},
addLocations: function(newLocations) {
function hasProperFormat() {
return newLocations instanceof Array;
return newLocations instanceof Array && typeof newLocations[0] === 'string';
}

function hasExtendFormat() {
return newLocations instanceof Array && newLocations[0] instanceof Object;
}

var existingLocations = this.locations;

if (hasProperFormat()) {
newLocations.forEach(function(loc) {
if (!locationExistsIn(loc, existingLocations)) {
existingLocations.push({
id: loc,
title: loc
});
} else {
throw new Error('Location already exists');
}
});
} else if (hasExtendFormat()) {
newLocations.forEach(function(loc) {
if (!locationExistsIn(loc, existingLocations)) {
existingLocations.push(loc);
} else {
throw new Error('Location already exists');
}
});
} else {
}
else {
throw new Error('Tried to add locations in wrong format');
}

Expand All @@ -80,7 +101,8 @@ Timetable.Renderer = function(tt) {
throw new Error('Unknown location');
}
if (!isValidTimeRange(start, end)) {
throw new Error('Invalid time range: ' + JSON.stringify([start, end]));
console.log('Invalid time range: ' + JSON.stringify([start, end]));
return;
}

var optionsHasValidType = Object.prototype.toString.call(options) === '[object Object]';
Expand Down Expand Up @@ -122,10 +144,16 @@ Timetable.Renderer = function(tt) {
}
function appendRowHeaders(ulNode) {
for (var k=0; k<timetable.locations.length; k++) {
var url = timetable.locations[k].href;
var liNode = ulNode.appendChild(document.createElement('li'));
var spanNode = liNode.appendChild(document.createElement('span'));
if (url !== undefined) {
var aNode = liNode.appendChild(document.createElement('a'));
aNode.href = timetable.locations[k].href;
aNode.appendChild(spanNode);
}
spanNode.className = 'row-heading';
spanNode.textContent = timetable.locations[k];
spanNode.textContent = timetable.locations[k].title;
}
}
function appendTimetableSection(container) {
Expand All @@ -150,7 +178,7 @@ Timetable.Renderer = function(tt) {
if (hour === timetable.scope.hourEnd && (timetable.scope.hourStart !== timetable.scope.hourEnd || looped)) {
completed = true;
}
if (++hour === 24) {
if (++hour === 25) {
hour = 0;
looped = true;
}
Expand All @@ -167,7 +195,7 @@ Timetable.Renderer = function(tt) {
function appendLocationEvents(location, node) {
for (var k=0; k<timetable.events.length; k++) {
var event = timetable.events[k];
if (event.location === location) {
if (event.location === location.id) {
appendEvent(event, node);
}
}
Expand All @@ -177,9 +205,9 @@ Timetable.Renderer = function(tt) {
var hasURL, hasAdditionalClass, hasDataAttributes = false;

if(hasOptions) {
hasURL = (event.options.url !== undefined) ? true : false;
hasAdditionalClass = (event.options.class !== undefined) ? true : false;
hasDataAttributes = (event.options.data !== undefined) ? true : false;
hasURL = event.options.url !== undefined;
hasAdditionalClass = event.options.class !== undefined;
hasDataAttributes = event.options.data !== undefined;
}

var elementType = hasURL ? 'a' : 'span';
Expand Down
2 changes: 1 addition & 1 deletion dist/scripts/timetable.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading