Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
SRCT
schedules
Commits
f444af2e
Commit
f444af2e
authored
Oct 28, 2018
by
Zac Wood
Browse files
basic courses page
parent
fdfb621b
Changes
24
Hide whitespace changes
Inline
Side-by-side
schedules/app/assets/javascripts/application.js
View file @
f444af2e
...
...
@@ -10,13 +10,14 @@
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require rails-ujs
// require turbolinks
//= require FileSaver
//= require_tree .
//= require cart
// require_tree .
// require jquery3
// require popper
// require bootstrap-sprockets
// require rails-ujs
const
elementFromString
=
string
=>
{
const
html
=
new
DOMParser
().
parseFromString
(
string
,
'
text/html
'
);
...
...
@@ -25,7 +26,7 @@ const elementFromString = string => {
document
.
addEventListener
(
'
DOMContentLoaded
'
,
()
=>
{
this
.
cart
=
new
Cart
();
FontAwesome
.
dom
.
i2svg
();
initGlobalListeners
();
});
const
setSemester
=
async
select
=>
{
...
...
@@ -33,8 +34,7 @@ const setSemester = async select => {
location
.
reload
(
true
);
};
/** Loads FontAwesome icons on load; fixes weird flickering */
FontAwesome
.
dom
.
watch
({
observeMutationsRoot
:
document
});
// document.addEventListener('turbolinks:load', () => {
// FontAwesome.dom.i2svg();
// });
const
initGlobalListeners
=
()
=>
{
const
semesterSelect
=
document
.
getElementById
(
'
semester-select
'
);
semesterSelect
.
onchange
=
()
=>
setSemester
(
semesterSelect
);
};
schedules/app/assets/javascripts/jsconfig.json
0 → 100644
View file @
f444af2e
{
"compilerOptions"
:
{
"lib"
:
[
"es2015"
,
"dom"
]
}
}
schedules/app/assets/javascripts/schedules.js
View file @
f444af2e
...
...
@@ -10,28 +10,42 @@ document.addEventListener('DOMContentLoaded', () => {
header
:
false
,
events
:
renderEvents
,
});
// document.getElementById('numSchedules').innerText = window.events.length;
}
});
// let i = 0;
initListeners
();
});
const
renderEvents
=
(
start
,
end
,
timezone
,
callback
)
=>
{
// document.getElementById('currentSchedule').innerText = i + 1;
callback
(
window
.
events
);
};
// const nextSchedule = () => {
// if (i + 1 < window.events.length) i++;
const
remove
=
async
item
=>
{
await
window
.
cart
.
addSection
({
...
item
.
dataset
});
location
.
reload
(
true
);
};
/**
* Generates a URL for the current sections in the schedule
* and sets the link in the modal to it.
*/
const
setUrlInModal
=
()
=>
{
document
.
getElementById
(
'
calendar-link
'
).
innerText
=
`
${
window
.
location
.
protocol
}
//
${
window
.
location
.
hostname
}
/api/schedules?section_ids=
${
window
.
cart
.
_courses
.
join
(
'
,
'
)}
`
;
};
// $('#calendar').fullCalendar('refetchEvents');
// };
const
downloadIcs
=
async
()
=>
{
const
response
=
await
fetch
(
`http://localhost:3000/api/schedules?section_ids=
${
window
.
cart
.
_courses
.
join
(
'
,
'
)}
`
);
const
text
=
await
response
.
text
();
const
blob
=
new
Blob
([
text
],
{
type
:
'
text/calendar;charset=utf-8
'
});
saveAs
(
blob
,
'
GMU Schedule.ics
'
);
};
// const prevSchedule = () => {
// if (i > 0) i--;
const
addToSystemCalendar
=
()
=>
{};
// $('#calendar').fullCalendar('refetchEvents');
const
initListeners
=
()
=>
{
const
items
=
Array
.
from
(
document
.
querySelectorAll
(
'
.section-item
'
));
items
.
forEach
(
item
=>
(
item
.
onclick
=
()
=>
remove
(
item
)));
// console.log(window.events[i]);
// };
document
.
getElementById
(
'
open-modal-btn
'
).
onclick
=
setUrlInModal
;
document
.
getElementById
(
'
download-ics
'
).
onclick
=
downloadIcs
;
document
.
getElementById
(
'
add-to-system
'
).
onclick
=
addToSystemCalendar
;
};
schedules/app/assets/javascripts/search.js
View file @
f444af2e
...
...
@@ -3,20 +3,6 @@
const
sectionWithCrn
=
crn
=>
document
.
getElementById
(
'
search-list
'
).
querySelector
(
`[data-crn="
${
crn
}
"]`
);
// const addCourse = async (event, id) => {
// event && event.stopPropagation();
// const courseCard = document.getElementById(`course-${id}`);
// const title = courseCard.querySelector('.title').innerText;
// const sectionsItems = Array.from(courseCard.querySelectorAll('li'));
// const filtered = sectionsItems.filter(li => {
// return !li.parentNode.classList.contains('pair') || li.dataset.type === 'Lecture';
// });
// for (const section of filtered) {
// await addOrRemoveFromCart(undefined, section);
// }
// }
/**
* Either adds or removes a section from the cart depending on
* if it is currently in the cart.
...
...
@@ -46,10 +32,14 @@ const toggleSections = course => {
}
};
/**
* Generates a webcal:// URL for the current sections in the schedule
* and sets the link in the modal to it.
*/
const
setUrlInModal
=
()
=>
{
document
.
getElementById
(
'
calendar-link
'
).
innerText
=
`
${
window
.
location
.
protocol
}
//
${
window
.
location
.
hostname
}
/api/schedule?crns=
${
this
.
cart
.
_courses
.
join
(
'
,
'
)}
`
;
const
initSearchListeners
=
()
=>
{
const
courseCards
=
Array
.
from
(
document
.
querySelectorAll
(
'
.course-card
'
));
courseCards
.
forEach
(
card
=>
{
card
.
onclick
=
()
=>
toggleSections
(
card
);
});
const
sectionItems
=
Array
.
from
(
document
.
querySelectorAll
(
'
.section-item
'
));
sectionItems
.
forEach
(
item
=>
(
item
.
onclick
=
event
=>
addOrRemoveFromCart
(
event
,
item
)));
};
document
.
addEventListener
(
'
DOMContentLoaded
'
,
initSearchListeners
);
schedules/app/assets/stylesheets/application.scss
View file @
f444af2e
...
...
@@ -10,7 +10,9 @@
* files in this directory. Styles in this file should be added after the last require_* statement.
* It is generally better to create a new file per style scope.
*
*= require_tree .
* require_tree .
*= require cart
*= require navbar
*= require_self
*/
...
...
@@ -32,26 +34,24 @@ body {
display
:
flex
;
flex-direction
:
column
;
}
.card-body
{
.attr-list
{
display
:
flex
;
flex-direction
:
row
;
}
.attr
{
.icon
{
padding-right
:
4px
;
}
align-items
:
center
;
display
:
inline-flex
;
white-space
:
nowrap
;
}
}
.attr-list
{
display
:
flex
;
flex-direction
:
row
;
.attr
{
.icon
{
padding-right
:
4px
;
}
align-items
:
center
;
display
:
inline-flex
;
white-space
:
nowrap
;
}
}
}
.unpadded
{
padding
:
0px
;
padding
:
0px
;
}
/* On mouse-over, add a deeper shadow */
...
...
@@ -59,25 +59,6 @@ body {
box-shadow
:
0
0
20px
rgba
(
0
,
0
,
0
,
0
.4
);
}
.list-group-item
:hover
{
transition
:
0
.15s
;
background-color
:
lightgray
;
}
.list-group-item.selected
{
background-color
:
lightgreen
;
}
.list-group-item.selected
:hover
{
transition
:
0
.15s
;
background-color
:
red
;
}
.schedule-section-card
:hover
{
transition
:
0
.15s
;
background-color
:
red
;
}
.align-vertical
{
display
:
flex
;
align-items
:
center
;
...
...
schedules/app/assets/stylesheets/cart.scss
View file @
f444af2e
.cart-course
{
display
:
flex
;
justify-content
:
space-between
;
.title
{
min-width
:
15%
;
}
.crns
{
color
:
gray
;
font-size
:
10pt
;
}
}
#cart
{
display
:
none
;
}
...
...
schedules/app/assets/stylesheets/schedule.scss
→
schedules/app/assets/stylesheets/schedule
s
.scss
View file @
f444af2e
...
...
@@ -2,3 +2,11 @@
background-color
:
white
;
padding
:
16px
;
}
.section-item.selected
{
background-color
:
white
;
}
.section-item.selected
:hover
{
background-color
:
red
;
}
schedules/app/assets/stylesheets/search.scss
View file @
f444af2e
// Place all the styles related to the search controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
.section-item
:hover
{
transition
:
0
.15s
;
background-color
:
lightgray
;
}
.section-item.selected
{
background-color
:
lightgreen
;
}
.section-item.selected
:hover
{
transition
:
0
.15s
;
background-color
:
red
;
}
.section-item
:hover
{
transition
:
0
.15s
;
background-color
:
red
;
}
schedules/app/controllers/api/schedules_controller.rb
View file @
f444af2e
...
...
@@ -5,10 +5,10 @@ class API::SchedulesController < ApplicationController
# Render an iCal file containing the schedules of all the
# course sections with the given CRNs.
api
:GET
,
'/schedules'
,
'Generate an iCal file with events for the given CRNs'
param
:
crn
s
,
String
,
desc:
'Comma separated list of
CRN
s to include as events in the calendar'
,
required:
true
param
:
section_id
s
,
String
,
desc:
'Comma separated list of
section id
s to include as events in the calendar'
,
required:
true
def
index
crn
s
=
params
[
"
crn
s"
].
split
','
@schedule
=
Schedule
.
new
crn
s
id
s
=
params
[
"
section_id
s"
].
split
','
@schedule
=
Schedule
.
new
id
s
render
plain:
@schedule
.
to_ical
# render a plaintext iCal file
end
end
schedules/app/controllers/application_controller.rb
View file @
f444af2e
...
...
@@ -7,7 +7,9 @@ class ApplicationController < ActionController::Base
@semester
=
if
cookies
.
key?
(
:semester_id
)
Semester
.
find_by
(
id:
cookies
[
:semester_id
])
else
Semester
.
find_by
(
season:
'Spring'
,
year:
'2019'
)
sem
=
Semester
.
find_by
(
season:
'Spring'
,
year:
'2019'
)
cookies
[
:semester_id
]
=
sem
.
id
sem
end
end
...
...
schedules/app/controllers/courses_controller.rb
0 → 100644
View file @
f444af2e
class
CoursesController
<
ApplicationController
before_action
:set_course
def
show
end
private
def
set_course
@course
=
Course
.
find_by_id
params
[
:id
]
end
end
schedules/app/helpers/courses_helper.rb
0 → 100644
View file @
f444af2e
module
CoursesHelper
end
schedules/app/models/course.rb
View file @
f444af2e
...
...
@@ -12,6 +12,10 @@ class Course < ApplicationRecord
validates
:subject
,
presence:
true
validates
:semester_id
,
presence:
true
def
full_name
"
#{
subject
}
#{
course_number
}
"
end
def
self
.
from_subject
(
base_query
,
subject
)
base_query
.
where
(
"courses.subject = ?"
,
subject
.
upcase
)
end
...
...
schedules/app/models/schedule.rb
View file @
f444af2e
require
'icalendar'
require
'time'
# Creates a iCal object given a list of
CRN
s
# Creates a iCal object given a list of
section id
s
class
Schedule
def
initialize
(
crn
s
)
def
initialize
(
id
s
)
@cal
=
Icalendar
::
Calendar
.
new
@cal
.
x_wr_calname
=
'GMU Fall 2018'
@course_sections
=
crns
.
map
do
|
crn
|
CourseSection
.
find_by
crn:
crn
end
@course_sections
=
ids
.
map
{
|
id
|
CourseSection
.
find_by_id
id
}
@course_sections
.
compact!
load_events
...
...
schedules/app/views/courses/show.html.erb
0 → 100644
View file @
f444af2e
<div
class=
"row"
>
<div
class=
"col-5"
>
<h1>
<%=
@course
.
full_name
%>
</h1>
<h4>
<%=
@course
.
title
%>
</h4>
<div
class=
"d-flex"
>
<div
class=
"attr-list justify-content-start"
>
<div
class=
"attr"
>
<div
class=
"icon"
>
<i
class=
"fa fa-book"
></i>
</div>
3 credits
</div>
<div
class=
"attr"
>
<div
class=
"icon"
>
<i
class=
"fa fa-bars"
></i>
</div>
<!-- TODO: FIX THIS -->
<%#= "#{course.section_count}" %>
3 sections
</div>
</div>
</div>
<p>
<%=
@course
.
description
%>
</p>
</div>
<div
class =
"col-7"
>
<%=
render
partial:
'shared/section'
,
collection:
@course
.
course_sections
%>
</div>
</div>
schedules/app/views/layouts/application.html.erb
View file @
f444af2e
...
...
@@ -5,13 +5,9 @@
<%=
csrf_meta_tags
%>
<%=
javascript_include_tag
'masonstrap.min'
%>
<%=
javascript_include_tag
'moment.min'
%>
<%=
javascript_include_tag
'fullcalendar.min'
%>
<%=
javascript_include_tag
'FileSaver'
%>
<%=
javascript_include_tag
'application'
%>
<%=
stylesheet_link_tag
'masonstrap.min'
%>
<%=
stylesheet_link_tag
'fullcalendar.min'
%>
<%=
stylesheet_link_tag
'application'
%>
</head>
...
...
schedules/app/views/schedules/show.html.erb
View file @
f444af2e
<!-- <button onclick="nextSchedule()">Next</button>
<button onclick="prevSchedule()">Prev</button>
<span id="currentSchedule">1</span> / <span id="numSchedules">1</span> -->
<%=
javascript_include_tag
'schedules'
%>
<%=
stylesheet_link_tag
'schedules'
%>
<button
type=
"button"
class=
"btn btn-primary"
data-toggle=
"modal"
data-target=
"#exportModal"
onclick=
"setUrlInModal()"
>
<%=
javascript_include_tag
'moment.min'
%>
<%=
javascript_include_tag
'FileSaver'
%>
<%=
javascript_include_tag
'fullcalendar.min'
%>
<%=
stylesheet_link_tag
'fullcalendar.min'
%>
<button
id=
"open-modal-btn"
type=
"button"
class=
"btn btn-primary"
data-toggle=
"modal"
data-target=
"#exportModal"
>
Generate Schedule
</button>
<div
id=
"calendar"
></div>
...
...
@@ -46,12 +51,9 @@
To download a .ics file containing your schedule, click the "Download calendar file" button below.
</div>
<div
class=
"modal-footer"
>
<button
type=
"button"
class=
"btn btn-secondary"
onclick=
"downloadIcs()"
>
Download calendar file
</button>
<button
type=
"button"
class=
"btn btn-primary"
onclick=
"addToSystemCalendar()"
>
Add to system calendar
</button>
<button
id=
"download-ics"
type=
"button"
class=
"btn btn-secondary"
>
Download calendar file
</button>
<button
id=
"add-to-system"
type=
"button"
class=
"btn btn-primary"
>
Add to system calendar
</button>
</div>
</div>
</div>
</div>
schedules/app/views/search/index.html.erb
View file @
f444af2e
...
...
@@ -21,3 +21,5 @@
<%
end
%>
<%=
javascript_include_tag
'search'
%>
<%=
stylesheet_link_tag
'search'
%>
schedules/app/views/shared/_course.html.erb
View file @
f444af2e
<%
expanded
=
false
unless
defined?
expanded
%>
<div
class=
"card"
id=
"course-
<%=
course
.
id
%>
"
onclick=
"toggleSections(this)"
>
<div
class=
"card
course-card
"
id=
"course-
<%=
course
.
id
%>
"
>
<div
class=
"card-header"
>
<div
class=
"row"
>
<div
class=
"col"
>
...
...
schedules/app/views/shared/_navbar.html.erb
View file @
f444af2e
...
...
@@ -7,7 +7,7 @@
Schedules
</a>
<select
onchange
=
"se
tSe
mester
(this)
"
>
<select
id
=
"semester
-select
"
>
<%
Semester
.
all
.
each
do
|
semester
|
%>
<option
value=
"
<%=
semester
.
id
%>
"
<%
if
@semester
==
semester
%>
selected
<%
end
%>
>
<%=
"
#{
semester
.
season
}
#{
semester
.
year
}
"
%>
...
...
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment