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 @@
...
@@ -10,13 +10,14 @@
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
// about supported directives.
//
//
//= require rails-ujs
// require turbolinks
//= require FileSaver
//= require FileSaver
//= require_tree .
//= require cart
// require_tree .
// require jquery3
// require jquery3
// require popper
// require popper
// require bootstrap-sprockets
// require bootstrap-sprockets
// require rails-ujs
const
elementFromString
=
string
=>
{
const
elementFromString
=
string
=>
{
const
html
=
new
DOMParser
().
parseFromString
(
string
,
'
text/html
'
);
const
html
=
new
DOMParser
().
parseFromString
(
string
,
'
text/html
'
);
...
@@ -25,7 +26,7 @@ const elementFromString = string => {
...
@@ -25,7 +26,7 @@ const elementFromString = string => {
document
.
addEventListener
(
'
DOMContentLoaded
'
,
()
=>
{
document
.
addEventListener
(
'
DOMContentLoaded
'
,
()
=>
{
this
.
cart
=
new
Cart
();
this
.
cart
=
new
Cart
();
FontAwesome
.
dom
.
i2svg
();
initGlobalListeners
();
});
});
const
setSemester
=
async
select
=>
{
const
setSemester
=
async
select
=>
{
...
@@ -33,8 +34,7 @@ const setSemester = async select => {
...
@@ -33,8 +34,7 @@ const setSemester = async select => {
location
.
reload
(
true
);
location
.
reload
(
true
);
};
};
/** Loads FontAwesome icons on load; fixes weird flickering */
const
initGlobalListeners
=
()
=>
{
FontAwesome
.
dom
.
watch
({
observeMutationsRoot
:
document
});
const
semesterSelect
=
document
.
getElementById
(
'
semester-select
'
);
// document.addEventListener('turbolinks:load', () => {
semesterSelect
.
onchange
=
()
=>
setSemester
(
semesterSelect
);
// FontAwesome.dom.i2svg();
};
// });
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', () => {
...
@@ -10,28 +10,42 @@ document.addEventListener('DOMContentLoaded', () => {
header
:
false
,
header
:
false
,
events
:
renderEvents
,
events
:
renderEvents
,
});
});
// document.getElementById('numSchedules').innerText = window.events.length;
}
}
});
// let i = 0;
initListeners
();
});
const
renderEvents
=
(
start
,
end
,
timezone
,
callback
)
=>
{
const
renderEvents
=
(
start
,
end
,
timezone
,
callback
)
=>
{
// document.getElementById('currentSchedule').innerText = i + 1;
callback
(
window
.
events
);
callback
(
window
.
events
);
};
};
// const nextSchedule = () => {
const
remove
=
async
item
=>
{
// if (i + 1 < window.events.length) i++;
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 = () => {
const
addToSystemCalendar
=
()
=>
{};
// if (i > 0) i--;
// $('#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 @@
...
@@ -3,20 +3,6 @@
const
sectionWithCrn
=
crn
=>
document
.
getElementById
(
'
search-list
'
).
querySelector
(
`[data-crn="
${
crn
}
"]`
);
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
* Either adds or removes a section from the cart depending on
* if it is currently in the cart.
* if it is currently in the cart.
...
@@ -46,10 +32,14 @@ const toggleSections = course => {
...
@@ -46,10 +32,14 @@ const toggleSections = course => {
}
}
};
};
/**
const
initSearchListeners
=
()
=>
{
* Generates a webcal:// URL for the current sections in the schedule
const
courseCards
=
Array
.
from
(
document
.
querySelectorAll
(
'
.course-card
'
));
* and sets the link in the modal to it.
courseCards
.
forEach
(
card
=>
{
*/
card
.
onclick
=
()
=>
toggleSections
(
card
);
const
setUrlInModal
=
()
=>
{
});
document
.
getElementById
(
'
calendar-link
'
).
innerText
=
`
${
window
.
location
.
protocol
}
//
${
window
.
location
.
hostname
}
/api/schedule?crns=
${
this
.
cart
.
_courses
.
join
(
'
,
'
)}
`
;
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 @@
...
@@ -10,7 +10,9 @@
* files in this directory. Styles in this file should be added after the last require_* statement.
* 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.
* It is generally better to create a new file per style scope.
*
*
*= require_tree .
* require_tree .
*= require cart
*= require navbar
*= require_self
*= require_self
*/
*/
...
@@ -32,26 +34,24 @@ body {
...
@@ -32,26 +34,24 @@ body {
display
:
flex
;
display
:
flex
;
flex-direction
:
column
;
flex-direction
:
column
;
}
}
}
.card-body
{
.attr-list
{
display
:
flex
;
flex-direction
:
row
;
.attr
{
.attr-list
{
.icon
{
display
:
flex
;
padding-right
:
4px
;
flex-direction
:
row
;
}
align-items
:
center
;
.attr
{
display
:
inline-flex
;
.icon
{
white-space
:
nowrap
;
padding-right
:
4px
;
}
}
}
align-items
:
center
;
display
:
inline-flex
;
white-space
:
nowrap
;
}
}
}
}
.unpadded
{
.unpadded
{
padding
:
0px
;
padding
:
0px
;
}
}
/* On mouse-over, add a deeper shadow */
/* On mouse-over, add a deeper shadow */
...
@@ -59,25 +59,6 @@ body {
...
@@ -59,25 +59,6 @@ body {
box-shadow
:
0
0
20px
rgba
(
0
,
0
,
0
,
0
.4
);
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
{
.align-vertical
{
display
:
flex
;
display
:
flex
;
align-items
:
center
;
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
{
#cart
{
display
:
none
;
display
:
none
;
}
}
...
...
schedules/app/assets/stylesheets/schedule.scss
→
schedules/app/assets/stylesheets/schedule
s
.scss
View file @
f444af2e
...
@@ -2,3 +2,11 @@
...
@@ -2,3 +2,11 @@
background-color
:
white
;
background-color
:
white
;
padding
:
16px
;
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.
// Place all the styles related to the search controller here.
// They will automatically be included in application.css.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
// 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
...
@@ -5,10 +5,10 @@ class API::SchedulesController < ApplicationController
# Render an iCal file containing the schedules of all the
# Render an iCal file containing the schedules of all the
# course sections with the given CRNs.
# course sections with the given CRNs.
api
:GET
,
'/schedules'
,
'Generate an iCal file with events for 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
def
index
crn
s
=
params
[
"
crn
s"
].
split
','
id
s
=
params
[
"
section_id
s"
].
split
','
@schedule
=
Schedule
.
new
crn
s
@schedule
=
Schedule
.
new
id
s
render
plain:
@schedule
.
to_ical
# render a plaintext iCal file
render
plain:
@schedule
.
to_ical
# render a plaintext iCal file
end
end
end
end
schedules/app/controllers/application_controller.rb
View file @
f444af2e
...
@@ -7,7 +7,9 @@ class ApplicationController < ActionController::Base
...
@@ -7,7 +7,9 @@ class ApplicationController < ActionController::Base
@semester
=
if
cookies
.
key?
(
:semester_id
)
@semester
=
if
cookies
.
key?
(
:semester_id
)
Semester
.
find_by
(
id:
cookies
[
:semester_id
])
Semester
.
find_by
(
id:
cookies
[
:semester_id
])
else
else
Semester
.
find_by
(
season:
'Spring'
,
year:
'2019'
)
sem
=
Semester
.
find_by
(
season:
'Spring'
,
year:
'2019'
)
cookies
[
:semester_id
]
=
sem
.
id
sem
end
end
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
...
@@ -12,6 +12,10 @@ class Course < ApplicationRecord
validates
:subject
,
presence:
true
validates
:subject
,
presence:
true
validates
:semester_id
,
presence:
true
validates
:semester_id
,
presence:
true
def
full_name
"
#{
subject
}
#{
course_number
}
"
end
def
self
.
from_subject
(
base_query
,
subject
)
def
self
.
from_subject
(
base_query
,
subject
)
base_query
.
where
(
"courses.subject = ?"
,
subject
.
upcase
)
base_query
.
where
(
"courses.subject = ?"
,
subject
.
upcase
)
end
end
...
...
schedules/app/models/schedule.rb
View file @
f444af2e
require
'icalendar'
require
'icalendar'
require
'time'
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
class
Schedule
def
initialize
(
crn
s
)
def
initialize
(
id
s
)
@cal
=
Icalendar
::
Calendar
.
new
@cal
=
Icalendar
::
Calendar
.
new
@cal
.
x_wr_calname
=
'GMU Fall 2018'
@cal
.
x_wr_calname
=
'GMU Fall 2018'
@course_sections
=
crns
.
map
do
|
crn
|
@course_sections
=
ids
.
map
{
|
id
|
CourseSection
.
find_by_id
id
}
CourseSection
.
find_by
crn:
crn
end
@course_sections
.
compact!
@course_sections
.
compact!
load_events
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 @@
...
@@ -5,13 +5,9 @@
<%=
csrf_meta_tags
%>
<%=
csrf_meta_tags
%>
<%=
javascript_include_tag
'masonstrap.min'
%>
<%=
javascript_include_tag
'masonstrap.min'
%>
<%=
javascript_include_tag
'moment.min'
%>
<%=
javascript_include_tag
'fullcalendar.min'
%>
<%=
javascript_include_tag
'FileSaver'
%>
<%=
javascript_include_tag
'application'
%>
<%=
javascript_include_tag
'application'
%>
<%=
stylesheet_link_tag
'masonstrap.min'
%>
<%=
stylesheet_link_tag
'masonstrap.min'
%>
<%=
stylesheet_link_tag
'fullcalendar.min'
%>
<%=
stylesheet_link_tag
'application'
%>
<%=
stylesheet_link_tag
'application'
%>
</head>
</head>
...
...
schedules/app/views/schedules/show.html.erb
View file @
f444af2e
<!-- <button onclick="nextSchedule()">Next</button>
<%=
javascript_include_tag
'schedules'
%>
<button onclick="prevSchedule()">Prev</button>
<%=
stylesheet_link_tag
'schedules'
%>
<span id="currentSchedule">1</span> / <span id="numSchedules">1</span> -->
<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
Generate Schedule
</button>
</button>
<div
id=
"calendar"
></div>
<div
id=
"calendar"
></div>
...
@@ -46,12 +51,9 @@
...
@@ -46,12 +51,9 @@
To download a .ics file containing your schedule, click the "Download calendar file" button below.
To download a .ics file containing your schedule, click the "Download calendar file" button below.
</div>
</div>
<div
class=
"modal-footer"
>
<div
class=
"modal-footer"
>
<button
type=
"button"
class=
"btn btn-secondary"
onclick=
"downloadIcs()"
>
Download calendar file
</button>
<button
id=
"download-ics"
type=
"button"
class=
"btn btn-secondary"
>
Download calendar file
</button>
<button
type=
"button"
class=
"btn btn-primary"
onclick=
"addToSystemCalendar()"
>
Add to system calendar
</button>
<button
id=
"add-to-system"
type=
"button"
class=
"btn btn-primary"
>
Add to system calendar
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
schedules/app/views/search/index.html.erb
View file @
f444af2e
...
@@ -21,3 +21,5 @@
...
@@ -21,3 +21,5 @@
<%
end
%>
<%
end
%>
<%=
javascript_include_tag
'search'
%>
<%=
stylesheet_link_tag
'search'
%>
schedules/app/views/shared/_course.html.erb
View file @
f444af2e
<%
expanded
=
false
unless
defined?
expanded
%>
<%
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=
"card-header"
>
<div
class=
"row"
>
<div
class=
"row"
>
<div
class=
"col"
>
<div
class=
"col"
>
...
...
schedules/app/views/shared/_navbar.html.erb
View file @
f444af2e
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
Schedules
Schedules
</a>
</a>
<select
onchange
=
"se
tSe
mester
(this)
"
>
<select
id
=
"semester
-select
"
>
<%
Semester
.
all
.
each
do
|
semester
|
%>
<%
Semester
.
all
.
each
do
|
semester
|
%>
<option
value=
"
<%=
semester
.
id
%>
"
<%
if
@semester
==
semester
%>
selected
<%
end
%>
>
<option
value=
"
<%=
semester
.
id
%>
"
<%
if
@semester
==
semester
%>
selected
<%
end
%>
>
<%=
"
#{
semester
.
season
}
#{
semester
.
year
}
"
%>
<%=
"
#{
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