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
69e7ffaa
Commit
69e7ffaa
authored
Oct 10, 2018
by
Zac Wood
Browse files
Merge branch 'calendar-view' into 'dev-v2'
Calendar view See merge request
!31
parents
a09028af
a4018412
Pipeline
#3210
passed with stage
in 2 minutes and 16 seconds
Changes
20
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
schedules/app/assets/javascripts/application.js
View file @
69e7ffaa
...
...
@@ -27,12 +27,12 @@ document.addEventListener('DOMContentLoaded', () => {
this
.
schedule
=
new
Schedule
();
});
/** Loads FontAwesome icons on load; fixes weird flickering */
document
.
addEventListener
(
'
turbolinks:load
'
,
()
=>
{
FontAwesome
.
dom
.
i2svg
();
});
const
setSemester
=
async
select
=>
{
const
resp
=
await
fetch
(
`/sessions/update?semester_id=
${
select
.
value
}
`
);
location
.
reload
(
true
);
};
/** Loads FontAwesome icons on load; fixes weird flickering */
document
.
addEventListener
(
'
turbolinks:load
'
,
()
=>
{
FontAwesome
.
dom
.
i2svg
();
});
schedules/app/assets/javascripts/schedule.js
View file @
69e7ffaa
class
Schedule
{
constructor
()
{
this
.
isOpen
=
false
;
this
.
_courses
=
{};
// {title, id, sections: {id, crn}}
const
cartData
=
document
.
querySelector
(
'
#cart-data
'
);
const
courses
=
Array
.
from
(
cartData
.
content
.
children
);
for
(
const
course
of
courses
)
{
const
{
id
,
title
}
=
course
.
dataset
;
const
sections
=
Array
.
from
(
course
.
children
).
map
(
node
=>
({
...
node
.
dataset
}));
this
.
_courses
[
id
]
=
{
id
,
title
,
sections
};
}
document
.
getElementById
(
'
course-counter
'
).
innerText
=
Object
.
keys
(
this
.
_courses
).
length
;
this
.
_ids
=
Array
.
from
(
document
.
getElementById
(
'
schedule
'
).
children
).
map
(
e
=>
e
.
dataset
.
crn
);
}
get
ids
()
{
return
this
.
_ids
;
get
crns
()
{
return
Object
.
keys
(
this
.
_courses
)
.
map
(
cid
=>
this
.
_courses
[
cid
].
sections
.
map
(
s
=>
s
.
crn
))
.
reduce
((
prev
,
curr
)
=>
[...
prev
,
...
curr
],
[]);
}
set
ids
(
ids
)
{
this
.
_ids
=
ids
;
document
.
getElementById
(
'
course-counter
'
).
innerText
=
ids
.
length
;
fetch
(
'
/sessions/update?crns=
'
+
ids
.
join
(
'
,
'
),
{
cache
:
'
no-store
'
});
get
ids
()
{
return
Object
.
keys
(
this
.
_courses
)
.
map
(
cid
=>
this
.
_courses
[
cid
].
sections
.
map
(
s
=>
s
.
id
))
.
reduce
((
prev
,
curr
)
=>
[...
prev
,
...
curr
],
[]);
}
toggle
()
{
...
...
@@ -30,36 +42,111 @@ class Schedule {
this
.
isOpen
=
!
this
.
isOpen
;
}
addToSchedule
(
section
)
{
if
(
this
.
ids
.
includes
(
section
.
dataset
.
crn
))
return
;
addCourse
(
course
)
{
this
.
_courses
[
course
.
id
]
=
course
;
const
parent
=
document
.
querySelector
(
'
#schedule
'
);
const
current
=
parent
.
querySelector
(
`#schedule-
${
course
.
id
}
`
);
const
newNode
=
this
.
_constructCourseNode
(
course
);
if
(
current
!==
null
)
parent
.
replaceChild
(
newNode
,
current
);
else
parent
.
appendChild
(
newNode
);
document
.
getElementById
(
'
course-counter
'
).
innerText
=
Object
.
keys
(
this
.
_courses
).
length
;
fetch
(
`/sessions/update?section_ids=
${
this
.
ids
.
join
(
'
,
'
)}
`
,
{
cache
:
'
no-store
'
});
}
removeCourse
(
id
)
{
const
sectionIds
=
this
.
_courses
[
id
].
sections
.
map
(
s
=>
s
.
id
);
for
(
const
sectionId
of
sectionIds
)
{
const
sectionCard
=
document
.
querySelector
(
`#section-
${
sectionId
}
`
);
sectionCard
&&
sectionCard
.
classList
.
remove
(
'
selected
'
);
}
delete
this
.
_courses
[
id
];
const
parent
=
document
.
querySelector
(
'
#schedule
'
);
const
current
=
parent
.
querySelector
(
`#schedule-
${
id
}
`
);
parent
.
removeChild
(
current
);
document
.
getElementById
(
'
course-counter
'
).
innerText
=
Object
.
keys
(
this
.
_courses
).
length
;
fetch
(
`/sessions/update?section_ids=
${
this
.
ids
.
join
(
'
,
'
)}
`
,
{
cache
:
'
no-store
'
});
}
courseContainingSection
(
id
)
{
for
(
const
courseId
in
this
.
_courses
)
{
const
course
=
this
.
_courses
[
courseId
];
for
(
const
section
of
course
.
sections
)
{
if
(
section
.
id
==
id
)
return
course
;
}
}
return
undefined
;
}
includesSection
(
id
)
{
return
!!
this
.
courseContainingSection
(
id
);
}
// section: { id, crn }
addSection
(
section
)
{
const
course
=
this
.
_courses
[
section
.
cid
];
if
(
course
)
{
course
.
sections
.
push
(
section
);
this
.
ids
=
[...
this
.
ids
,
section
.
dataset
.
crn
];
const
courseNode
=
document
.
querySelector
(
'
#schedule
'
).
querySelector
(
`#schedule-
${
course
.
id
}
`
);
const
crnList
=
courseNode
.
querySelector
(
'
.crns
'
);
crnList
.
innerText
=
course
.
sections
.
map
(
s
=>
`#
${
s
.
crn
}
`
);
section
.
classList
.
remove
(
'
section-item
'
);
section
.
classList
.
remove
(
'
selected
'
);
section
.
classList
.
add
(
'
schedule-
section
-card
'
);
section
.
onclick
=
()
=>
removeFromSchedule
(
section
)
;
fetch
(
`/sessions/update?section_ids=
${
this
.
ids
.
join
(
'
,
'
)}
`
,
{
cache
:
'
no-store
'
}
);
}
else
{
const
courseCard
=
document
.
getElementById
(
`course-
${
section
.
cid
}
`
);
const
title
=
courseCard
.
querySelector
(
'
#title
'
).
innerText
;
document
.
getElementById
(
'
schedule
'
).
appendChild
(
section
);
this
.
addCourse
({
title
,
id
:
section
.
cid
,
sections
:
[
section
]
});
}
}
removeFromSchedule
(
id
)
{
const
cart
=
document
.
getElementById
(
'
schedule
'
);
const
section
=
cart
.
querySelector
(
`#section-
${
id
}
`
);
cart
.
removeChild
(
section
);
removeSection
(
section
)
{
const
course
=
this
.
courseContainingSection
(
section
.
id
);
course
.
sections
=
course
.
sections
.
filter
(
s
=>
s
.
id
!==
section
.
id
);
const
schedule
=
document
.
querySelector
(
'
#schedule
'
);
const
courseNode
=
schedule
.
querySelector
(
`#schedule-
${
course
.
id
}
`
);
const
crnList
=
courseNode
.
querySelector
(
'
.crns
'
);
if
(
course
.
sections
.
length
===
0
)
{
this
.
removeCourse
(
section
.
cid
);
}
else
{
crnList
.
innerText
=
course
.
sections
.
map
(
s
=>
`#
${
s
.
crn
}
`
);
}
this
.
ids
=
this
.
ids
.
filter
(
_id
=>
_id
!=
id
);
fetch
(
`/sessions/update?section_ids=
${
this
.
ids
.
join
(
'
,
'
)}
`
,
{
cache
:
'
no-store
'
}
);
}
async
downloadIcs
()
{
const
cal
=
await
fetch
(
`/api/schedules?crns=
${
this
.
id
s
.
join
(
'
,
'
)}
`
);
const
cal
=
await
fetch
(
`/api/schedules?crns=
${
this
.
crn
s
.
join
(
'
,
'
)}
`
);
const
text
=
await
cal
.
text
();
var
blob
=
new
Blob
([
text
],
{
type
:
'
text/calendar;charset=utf-8
'
});
saveAs
(
blob
,
'
test.ics
'
);
}
async
addToSystemCalendar
()
{
const
url
=
`webcal://
${
window
.
location
.
hostname
}
/api/schedule?crns=
${
this
.
id
s
.
join
(
'
,
'
)}
`
;
const
url
=
`webcal://
${
window
.
location
.
hostname
}
/api/schedule?crns=
${
this
.
crn
s
.
join
(
'
,
'
)}
`
;
window
.
open
(
url
,
'
_self
'
);
}
_constructCourseNode
(
course
)
{
let
html
=
`<li id="schedule-
${
course
.
id
}
" class="list-group-item schedule-section-card" onclick="removeCourse(
${
course
.
id
}
)">`
;
html
+=
`<div style="display: flex; justify-content: space-between;">`
;
html
+=
`<b style="min-width: 15%">
${
course
.
title
}
</b>`
;
html
+=
`<span class="crns" style="color: gray; font-size: 10pt;">`
;
html
+=
course
.
sections
.
map
(
s
=>
`#
${
s
.
crn
}
`
).
join
(
'
,
'
);
html
+=
`</span>`
;
html
+=
`</div>`
;
html
+=
`</li>`
;
return
elementFromString
(
html
);
}
}
const
removeCourse
=
id
=>
{
this
.
schedule
.
removeCourse
(
id
);
};
schedules/app/assets/javascripts/search.js
View file @
69e7ffaa
...
...
@@ -3,17 +3,30 @@
const
sectionWithCrn
=
crn
=>
document
.
getElementById
(
'
search-list
'
).
querySelector
(
`[data-crn="
${
crn
}
"]`
);
const
addCourse
=
(
event
,
id
)
=>
{
const
courseCard
=
document
.
getElementById
(
`course-
${
id
}
`
);
const
title
=
courseCard
.
querySelector
(
'
#title
'
).
innerText
;
const
sectionsItems
=
Array
.
from
(
courseCard
.
querySelectorAll
(
'
li
'
));
const
sections
=
sectionsItems
.
map
(
li
=>
({
...
li
.
dataset
}));
this
.
schedule
.
addCourse
({
title
,
id
,
sections
});
sectionsItems
.
forEach
(
s
=>
s
.
classList
.
add
(
'
selected
'
));
event
.
stopPropagation
();
};
/**
* Either adds or removes a section from the schedule depending on
* if it is currently in the schedule.
*/
const
addOrRemoveFromSchedule
=
(
event
,
section
)
=>
{
if
(
this
.
schedule
.
ids
.
includes
(
section
.
dataset
.
crn
))
{
this
.
schedule
.
removeFromSchedule
(
section
.
dataset
.
crn
);
section
.
classList
.
remove
(
'
selected
'
);
const
addOrRemoveFromSchedule
=
(
event
,
sectionNode
)
=>
{
const
section
=
{
...
sectionNode
.
dataset
};
if
(
this
.
schedule
.
includesSection
(
section
.
id
))
{
this
.
schedule
.
removeSection
(
section
);
sectionNode
.
classList
.
remove
(
'
selected
'
);
}
else
{
this
.
schedule
.
add
ToSchedule
(
section
.
cloneNode
(
true
)
);
section
.
classList
.
add
(
'
selected
'
);
this
.
schedule
.
add
Section
(
section
);
section
Node
.
classList
.
add
(
'
selected
'
);
}
event
.
stopPropagation
();
...
...
schedules/app/assets/stylesheets/application.scss
View file @
69e7ffaa
...
...
@@ -99,3 +99,12 @@ body {
margin-bottom
:
16px
;
padding
:
12px
;
}
#add-course-btn
:hover
{
background-color
:
rgba
(
0
,
0
,
0
,
0
.2
);
}
#calendar
{
background-color
:
white
;
padding
:
16px
;
}
schedules/app/controllers/application_controller.rb
View file @
69e7ffaa
...
...
@@ -12,15 +12,17 @@ class ApplicationController < ActionController::Base
end
def
set_cart
@cart
=
cookies
[
:crns
].
split
(
','
).
map
do
|
crn
|
s
=
CourseSection
.
find_by_crn
(
crn
)
s
if
s
.
course
.
semester
==
@semester
sections
=
cookies
[
:section_ids
].
split
(
','
).
map
do
|
id
|
CourseSection
.
find_by_id
(
id
)
end
@cart
.
compact!
@cart
=
sections
.
group_by
do
|
s
|
s
.
course
.
id
end
end
def
set_cookies
cookies
[
:crns
]
=
""
if
cookies
[
:crns
].
nil?
cookies
[
:section_ids
]
=
""
if
cookies
[
:section_ids
].
nil?
end
end
schedules/app/controllers/schedules_controller.rb
View file @
69e7ffaa
...
...
@@ -15,4 +15,19 @@ class SchedulesController < ApplicationController
@schedule
=
Schedule
.
new
crns
render
plain:
@schedule
.
to_ical
# render a plaintext iCal file
end
def
show
@events
=
@cart
.
map
do
|
_cid
,
sections
|
s
=
sections
.
first
formatted_date
=
Date
.
today
.
to_s
.
tr
(
'-'
,
''
)
formatted_time
=
Time
.
parse
(
s
.
start_time
).
strftime
(
"%H%M%S"
)
formatted_endtime
=
Time
.
parse
(
s
.
end_time
).
strftime
(
"%H%M%S"
)
{
title:
s
.
name
,
start:
"
#{
formatted_date
}
T
#{
formatted_time
}
"
,
end:
"
#{
formatted_date
}
#{
formatted_endtime
}
"
}
end
end
end
schedules/app/controllers/sessions_controller.rb
View file @
69e7ffaa
class
SessionsController
<
ApplicationController
def
update
update_cookie
:crns
update_cookie
:section_ids
update_cookie
:semester_id
head
:ok
...
...
schedules/app/helpers/application_helper.rb
View file @
69e7ffaa
module
ApplicationHelper
def
in_cart?
(
id
)
@cart
.
select
{
|
_cid
,
sections
|
sections
.
select
{
|
s
|
s
.
id
==
id
}.
count
.
positive?
}.
count
.
positive?
end
end
schedules/app/views/layouts/application.html.erb
View file @
69e7ffaa
...
...
@@ -5,10 +5,13 @@
<%=
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
'masonstrap.min'
%>
<%=
stylesheet_link_tag
'fullcalendar.min'
%>
<%=
stylesheet_link_tag
'application'
%>
</head>
...
...
schedules/app/views/schedules/show.html.erb
0 → 100644
View file @
69e7ffaa
<div
id=
"calendar"
></div>
<template
id=
"events"
data-events=
"
<%=
@events
.
to_json
%>
"
></template>
<script>
/* const cal = document.querySelector('#calendar');
* var calendar = new Calendar(cal, {
* defaultView: 'agendaWeek'
* }); */
document
.
addEventListener
(
'
DOMContentLoaded
'
,
()
=>
{
const
eventsJSON
=
document
.
querySelector
(
'
#events
'
).
dataset
.
events
;
const
events
=
JSON
.
parse
(
eventsJSON
);
console
.
log
(
events
);
$
(
'
#calendar
'
).
fullCalendar
({
defaultView
:
'
agendaWeek
'
,
header
:
{
right
:
'
next
'
},
events
:
events
});
});
</script>
schedules/app/views/search/index.html.erb
View file @
69e7ffaa
...
...
@@ -5,8 +5,3 @@
<p>
Please try again!
</p>
<%
end
%>
<%=
javascript_tag
do
%>
document.addEventListener('DOMContentLoaded', () => {
this.search = new Search();
});
<%
end
%>
schedules/app/views/shared/_cart.html.erb
View file @
69e7ffaa
...
...
@@ -4,10 +4,20 @@
<div
class=
"col order-1 order-lg-1"
id=
"cart"
>
<div
class=
"card"
>
<div
class=
"card-body"
>
<h3
class=
"card-title"
>
Your Schedule
</h3>
<h3
class=
"card-title"
>
<%=
link_to
'Your Schedule'
,
schedule_path
%>
</h3>
</div>
<ul
class=
"list-group list-group-flush"
id=
"schedule"
>
<%=
render
partial:
'shared/section'
,
collection:
@cart
,
locals:
{
in_cart:
true
}
%>
<%
@cart
.
each
do
|
cid
,
sections
|
%>
<%
course
=
Course
.
find_by_id
(
cid
)
%>
<li
id=
"schedule-
<%=
cid
%>
"
class=
"list-group-item schedule-section-card"
onclick=
"removeCourse(
<%=
cid
%>
)"
>
<div
style=
"display: flex; justify-content: space-between;"
>
<b
style=
"min-width: 15%"
>
<%=
"
#{
course
.
subject
}
#{
course
.
course_number
}
"
%>
</b>
<span
class=
"crns"
style=
"color: gray; font-size: 10pt;"
>
<%=
sections
.
map
{
|
s
|
"#
#{
s
.
crn
}
"
}.
join
(
', '
)
%>
</span>
</div>
</li>
<%
end
%>
</ul>
<div
class=
"card-body"
>
<button
type=
"button"
class=
"btn btn-primary"
data-toggle=
"modal"
data-target=
"#exportModal"
onclick=
"setUrlInModal()"
>
...
...
@@ -17,6 +27,16 @@
</div>
</div>
<template
id=
"cart-data"
>
<%
@cart
.
each
do
|
cid
,
sections
|
%>
<%
course
=
Course
.
find_by_id
cid
%>
<div
data-id=
"
<%=
cid
%>
"
data-title=
"
<%=
"
#{
course
.
subject
}
#{
course
.
course_number
}
"
%>
"
>
<%
sections
.
each
do
|
s
|
%>
<div
data-id=
"
<%=
s
.
id
%>
"
data-crn=
"
<%=
s
.
crn
%>
"
></div>
<%
end
%>
</div>
<%
end
%>
</template>
</div>
</div>
...
...
schedules/app/views/shared/_course.html.erb
View file @
69e7ffaa
<%
expanded
=
false
unless
defined?
expanded
%>
<div
class=
"card"
id=
"course-
<%=
course
.
id
%>
"
onclick=
"toggleSections(this)"
>
<div
class=
"card-body"
>
<div>
<h3
style=
"float: left"
>
<%=
"
#{
course
.
subject
}
#{
course
.
course_number
}
"
%>
</h3>
<h5
style=
"float: right"
><em>
<%=
course
.
title
%>
</em>
.
<%=
course
.
credits
%>
credits.
</h5>
</div>
<div
class=
"card-body"
>
<div
style=
"display: flex; justify-content: space-between"
>
<h3
id=
"title"
>
<%=
"
#{
course
.
subject
}
#{
course
.
course_number
}
"
%>
</h3>
<div
style=
"display: flex; flex-direction: column; justify-content: center;"
>
<div
style=
"display: flex"
>
<h5><em>
<%=
course
.
title
%>
</em>
.
<%=
course
.
credits
%>
credits.
</h5>
<h4
id=
"add-course-btn"
onclick=
"addCourse(event, '
<%=
course
.
id
%>
');"
>
<i
class=
"fas fa-plus"
style=
"color: green"
></i>
</h4>
</div>
</div>
</div>
<div
style=
"clear: both"
>
</div>
<div
style=
"clear: both"
>
</div>
<p
class=
"description"
>
<%=
course
.
description
%>
</p>
<p
class=
"description"
>
<%=
course
.
description
%>
</p>
<%
unless
course
.
prereqs
.
nil?
||
course
.
prereqs
.
empty?
%>
<%
first
,
rest
=
course
.
prereqs
.
split
(
':'
)
%>
<%
prereqs
,
note
=
rest
.
split
(
'.'
)
%>
<p><strong>
<%=
first
%>
:
</strong>
<%=
prereqs
%>
<sub>
<%=
note
%>
</sub></p>
<%
end
%>
<%
unless
course
.
prereqs
.
nil?
||
course
.
prereqs
.
empty?
%>
<%
first
,
rest
=
course
.
prereqs
.
split
(
':'
)
%>
<%
prereqs
,
note
=
rest
.
split
(
'.'
)
%>
<p><strong>
<%=
first
%>
:
</strong>
<%=
prereqs
%>
<sub>
<%=
note
%>
</sub></p>
<%
end
%>
<div
class=
"d-block"
style=
"text-align: center"
>
<p
style=
"margin-bottom:-4px; font-size: 10px;"
>
Expand
</p>
<i
class=
"fas fa-chevron-down"
></i>
</div>
<div
class=
"d-block"
style=
"text-align: center"
>
<p
style=
"margin-bottom:-4px; font-size: 10px;"
>
Expand
</p>
<i
class=
"fas fa-chevron-down"
></i>
</div>
<!-- List of Course Sections -->
<ul
class=
"list-group list-group-flush"
id=
"sections"
style=
"display:
<%=
expanded
?
"block"
:
"none"
%>
"
>
<%
if
defined?
(
@instructor
)
%>
<%=
render
partial:
'shared/section'
,
collection:
course
.
course_sections
.
where
(
instructor:
@instructor
),
locals:
{
in_cart:
fal
se
}
%>
<%
else
%>
<%=
render
partial:
'shared/section'
,
collection:
course
.
course_sections
,
locals:
{
in_cart:
fal
se
}
%>
<%
end
%>
</ul>
</div>
<!-- List of Course Sections -->
<ul
class=
"list-group list-group-flush"
id=
"sections"
style=
"display:
<%=
expanded
?
"block"
:
"none"
%>
"
>
<%
if
defined?
(
@instructor
)
%>
<%=
render
partial:
'shared/section'
,
collection:
course
.
course_sections
.
where
(
instructor:
@instructor
),
locals:
{
course:
cour
se
}
%>
<%
else
%>
<%=
render
partial:
'shared/section'
,
collection:
course
.
course_sections
,
locals:
{
course:
cour
se
}
%>
<%
end
%>
</ul>
</div>
</div>
schedules/app/views/shared/_navbar.html.erb
View file @
69e7ffaa
...
...
@@ -7,7 +7,7 @@
Schedules
</a>
<select
onchange=
"setSemester(this)"
>
<%
for
s
emester
in
S
emester
.
all
%>
<%
S
emester
.
all
.
each
do
|
s
emester
|
%>
<option
value=
"
<%=
semester
.
id
%>
"
<%
if
@semester
==
semester
%>
selected
<%
end
%>
>
<%=
"
#{
semester
.
season
}
#{
semester
.
year
}
"
%>
</option>
...
...
schedules/app/views/shared/_section.html.erb
View file @
69e7ffaa
<%
if
in_cart
%>
<li
id=
"section-
<%=
section
.
crn
%>
"
class=
"list-group-item schedule-section-card"
data-crn=
"
<%=
section
.
crn
%>
"
onclick=
"removeFromSchedule(this)"
>
<span
style=
"float:left"
><b
class=
"subj"
>
<%=
"
#{
section
.
name
}
"
%>
</b>
:
<%=
section
.
title
%>
</span>
<span
style=
"float:right"
><i
class=
"fas fa-map-marker-alt"
></i>
<%=
section
.
location
%>
</span>
<div
style=
"clear: both"
></div>
<span
style=
"float:left"
><i
class=
"fas fa-chalkboard-teacher"
></i>
<%=
link_to
section
.
instructor
.
name
,
instructor_path
(
section
.
instructor
)
%>
</span>
<span
style=
"float:right"
><i
class=
"fas fa-clock"
></i>
<%=
"
#{
section
.
days
}
,
#{
section
.
start_time
}
-
#{
section
.
end_time
}
"
%>
</span>
<div
style=
"clear: both"
></div>
</li>
<%
else
%>
<li
id=
"section-
<%=
section
.
crn
%>
"
class=
"list-group-item section-item
<%=
"selected"
if
@cart
.
include?
section
%>
"
data-crn=
"
<%=
section
.
crn
%>
"
onclick=
"addOrRemoveFromSchedule(event, this)"
>
<span
style=
"float:left"
><b
class=
"subj"
>
<%=
"
#{
section
.
name
}
"
%>
</b>
:
<%=
section
.
title
%>
</span>
<span
style=
"float:right"
><i
class=
"fas fa-map-marker-alt"
></i>
<%=
section
.
location
%>
</span>
<div
style=
"clear: both"
></div>
<span
style=
"float:left"
><i
class=
"fas fa-chalkboard-teacher"
></i>
<%=
link_to
section
.
instructor
.
name
,
instructor_path
(
section
.
instructor
)
%>
</span>
<span
style=
"float:right"
><i
class=
"fas fa-clock"
></i>
<%=
"
#{
section
.
days
}
,
#{
section
.
start_time
}
-
#{
section
.
end_time
}
"
%>
</span>
<div
style=
"clear: both"
></div>
</li>
<%
end
%>
<li
id=
"section-
<%=
section
.
id
%>
"
class=
"list-group-item section-item
<%=
"selected"
if
in_cart?
section
.
id
%>
"
data-crn=
"
<%=
section
.
crn
%>
"
data-id=
"
<%=
section
.
id
%>
"
data-cid=
"
<%=
course
.
id
%>
"
onclick=
"addOrRemoveFromSchedule(event, this)"
>
<span
style=
"float:left"
><b
class=
"subj"
>
<%=
"
#{
section
.
name
}
"
%>
</b>
:
<%=
section
.
title
%>
</span>
<span
style=
"float:right"
><i
class=
"fas fa-map-marker-alt"
></i>
<%=
section
.
location
%>
</span>
<div
style=
"clear: both"
></div>
<span
style=
"float:left"
><i
class=
"fas fa-chalkboard-teacher"
></i>
<%=
link_to
section
.
instructor
.
name
,
instructor_path
(
section
.
instructor
)
%>
</span>
<span
style=
"float:right"
><i
class=
"fas fa-clock"
></i>
<%=
"
#{
section
.
days
}
,
#{
section
.
start_time
}
-
#{
section
.
end_time
}
"
%>
</span>
<div
style=
"clear: both"
></div>
</li>
schedules/config/initializers/assets.rb
View file @
69e7ffaa
...
...
@@ -16,4 +16,7 @@ Rails.application.config.assets.precompile += %w(
schedule.js
masonstrap.min.css
masonstrap.min.js
moment.min.js
fullcalendar.min.js
fullcalendar.min.css
)
schedules/config/routes.rb
View file @
69e7ffaa
...
...
@@ -4,6 +4,7 @@ Rails.application.routes.draw do
get
'sessions/update'
,
as:
'update_session'
resources
:instructors
,
only:
[
:index
,
:show
]
get
'schedule'
,
to:
'schedules#show'
,
as:
'schedule'
scope
:api
do
# Register /api routes
resources
:courses
,
only:
[
:index
,
:show
]
...
...
schedules/lib/assets/javascripts/fullcalendar.min.js
0 → 100644
View file @
69e7ffaa
This source diff could not be displayed because it is too large. You can
view the blob
instead.
schedules/lib/assets/javascripts/moment.min.js
0 → 100644
View file @
69e7ffaa
!
function
(
e
,
t
){
"
object
"
==
typeof
exports
&&
"
undefined
"
!=
typeof
module
?
module
.
exports
=
t
():
"
function
"
==
typeof
define
&&
define
.
amd
?
define
(
t
):
e
.
moment
=
t
()}(
this
,
function
(){
"
use strict
"
;
var
e
,
i
;
function
c
(){
return
e
.
apply
(
null
,
arguments
)}
function
o
(
e
){
return
e
instanceof
Array
||
"
[object Array]
"
===
Object
.
prototype
.
toString
.
call
(
e
)}
function
u
(
e
){
return
null
!=
e
&&
"
[object Object]
"
===
Object
.
prototype
.
toString
.
call
(
e
)}
function
l
(
e
){
return
void
0
===
e
}
function
d
(
e
){
return
"
number
"
==
typeof
e
||
"
[object Number]
"
===
Object
.
prototype
.
toString
.
call
(
e
)}
function
h
(
e
){
return
e
instanceof
Date
||
"
[object Date]
"
===
Object
.
prototype
.
toString
.
call
(
e
)}
function
f
(
e
,
t
){
var
n
,
s
=
[];
for
(
n
=
0
;
n
<
e
.
length
;
++
n
)
s
.
push
(
t
(
e
[
n
],
n
));
return
s
}
function
m
(
e
,
t
){
return
Object
.
prototype
.
hasOwnProperty
.
call
(
e
,
t
)}
function
_
(
e
,
t
){
for
(
var
n
in
t
)
m
(
t
,
n
)
&&
(
e
[
n
]
=
t
[
n
]);
return
m
(
t
,
"
toString
"
)
&&
(
e
.
toString
=
t
.
toString
),
m
(
t
,
"
valueOf
"
)
&&
(
e
.
valueOf
=
t
.
valueOf
),
e
}
function
y
(
e
,
t
,
n
,
s
){
return
Ot
(
e
,
t
,
n
,
s
,
!
0
).
utc
()}
function
g
(
e
){
return
null
==
e
.
_pf
&&
(
e
.
_pf
=
{
empty
:
!
1
,
unusedTokens
:[],
unusedInput
:[],
overflow
:
-
2
,
charsLeftOver
:
0
,
nullInput
:
!
1
,
invalidMonth
:
null
,
invalidFormat
:
!
1
,
userInvalidated
:
!
1
,
iso
:
!
1
,
parsedDateParts
:[],
meridiem
:
null
,
rfc2822
:
!
1
,
weekdayMismatch
:
!
1
}),
e
.
_pf
}
function
p
(
e
){
if
(
null
==
e
.
_isValid
){
var
t
=
g
(
e
),
n
=
i
.
call
(
t
.
parsedDateParts
,
function
(
e
){
return
null
!=
e
}),
s
=!
isNaN
(
e
.
_d
.
getTime
())
&&
t
.
overflow
<
0
&&!
t
.
empty
&&!
t
.
invalidMonth
&&!
t
.
invalidWeekday
&&!
t
.
weekdayMismatch
&&!
t
.
nullInput
&&!
t
.
invalidFormat
&&!
t
.
userInvalidated
&&
(
!
t
.
meridiem
||
t
.
meridiem
&&
n
);
if
(
e
.
_strict
&&
(
s
=
s
&&
0
===
t
.
charsLeftOver
&&
0
===
t
.
unusedTokens
.
length
&&
void
0
===
t
.
bigHour
),
null
!=
Object
.
isFrozen
&&
Object
.
isFrozen
(
e
))
return
s
;
e
.
_isValid
=
s
}
return
e
.
_isValid
}
function
v
(
e
){
var
t
=
y
(
NaN
);
return
null
!=
e
?
_
(
g
(
t
),
e
):
g
(
t
).
userInvalidated
=!
0
,
t
}
i
=
Array
.
prototype
.
some
?
Array
.
prototype
.
some
:
function
(
e
){
for
(
var
t
=
Object
(
this
),
n
=
t
.
length
>>>
0
,
s
=
0
;
s
<
n
;
s
++
)
if
(
s
in
t
&&
e
.
call
(
this
,
t
[
s
],
s
,
t
))
return
!
0
;
return
!
1
};
var
r
=
c
.
momentProperties
=
[];
function
w
(
e
,
t
){
var
n
,
s
,
i
;
if
(
l
(
t
.
_isAMomentObject
)
||
(
e
.
_isAMomentObject
=
t
.
_isAMomentObject
),
l
(
t
.
_i
)
||
(
e
.
_i
=
t
.
_i
),
l
(
t
.
_f
)
||
(
e
.
_f
=
t
.
_f
),
l
(
t
.
_l
)
||
(
e
.
_l
=
t
.
_l
),
l
(
t
.
_strict
)
||
(
e
.
_strict
=
t
.
_strict
),
l
(
t
.
_tzm
)
||
(
e
.
_tzm
=
t
.
_tzm
),
l
(
t
.
_isUTC
)
||
(
e
.
_isUTC
=
t
.
_isUTC
),
l
(
t
.
_offset
)
||
(
e
.
_offset
=
t
.
_offset
),
l
(
t
.
_pf
)
||
(
e
.
_pf
=
g
(
t
)),
l
(
t
.
_locale
)
||
(
e
.
_locale
=
t
.
_locale
),
0
<
r
.
length
)
for
(
n
=
0
;
n
<
r
.
length
;
n
++
)
l
(
i
=
t
[
s
=
r
[
n
]])
||
(
e
[
s
]
=
i
);
return
e
}
var
t
=!
1
;
function
M
(
e
){
w
(
this
,
e
),
this
.
_d
=
new
Date
(
null
!=
e
.
_d
?
e
.
_d
.
getTime
():
NaN
),
this
.
isValid
()
||
(
this
.
_d
=
new
Date
(
NaN
)),
!
1
===
t
&&
(
t
=!
0
,
c
.
updateOffset
(
this
),
t
=!
1
)}
function
S
(
e
){
return
e
instanceof
M
||
null
!=
e
&&
null
!=
e
.
_isAMomentObject
}
function
D
(
e
){
return
e
<
0
?
Math
.
ceil
(
e
)
||
0
:
Math
.
floor
(
e
)}
function
k
(
e
){
var
t
=+
e
,
n
=
0
;
return
0
!==
t
&&
isFinite
(
t
)
&&
(
n
=
D
(
t
)),
n
}
function
a
(
e
,
t
,
n
){
var
s
,
i
=
Math
.
min
(
e
.
length
,
t
.
length
),
r
=
Math
.
abs
(
e
.
length
-
t
.
length
),
a
=
0
;
for
(
s
=
0
;
s
<
i
;
s
++
)(
n
&&
e
[
s
]
!==
t
[
s
]
||!
n
&&
k
(
e
[
s
])
!==
k
(
t
[
s
]))
&&
a
++
;
return
a
+
r
}
function
Y
(
e
){
!
1
===
c
.
suppressDeprecationWarnings
&&
"
undefined
"
!=
typeof
console
&&
console
.
warn
&&
console
.
warn
(
"
Deprecation warning:
"
+
e
)}
function
n
(
i
,
r
){
var
a
=!
0
;
return
_
(
function
(){
if
(
null
!=
c
.
deprecationHandler
&&
c
.
deprecationHandler
(
null
,
i
),
a
){
for
(
var
e
,
t
=
[],
n
=
0
;
n
<
arguments
.
length
;
n
++
){
if
(
e
=
""
,
"
object
"
==
typeof
arguments
[
n
]){
for
(
var
s
in
e
+=
"
\n
[
"
+
n
+
"
]
"
,
arguments
[
0
])
e
+=
s
+
"
:
"
+
arguments
[
0
][
s
]
+
"
,
"
;
e
=
e
.
slice
(
0
,
-
2
)}
else
e
=
arguments
[
n
];
t
.
push
(
e
)}
Y
(
i
+
"
\n
Arguments:
"
+
Array
.
prototype
.
slice
.
call
(
t
).
join
(
""
)
+
"
\n
"
+
(
new
Error
).
stack
),
a
=!
1
}
return
r
.
apply
(
this
,
arguments
)},
r
)}
var
s
,
O
=
{};
function
T
(
e
,
t
){
null
!=
c
.
deprecationHandler
&&
c
.
deprecationHandler
(
e
,
t
),
O
[
e
]
||
(
Y
(
t
),
O
[
e
]
=!
0
)}
function
x
(
e
){
return
e
instanceof
Function
||
"
[object Function]
"
===
Object
.
prototype
.
toString
.
call
(
e
)}
function
b
(
e
,
t
){
var
n
,
s
=
_
({},
e
);
for
(
n
in
t
)
m
(
t
,
n
)
&&
(
u
(
e
[
n
])
&&
u
(
t
[
n
])?(
s
[
n
]
=
{},
_
(
s
[
n
],
e
[
n
]),
_
(
s
[
n
],
t
[
n
])):
null
!=
t
[
n
]?
s
[
n
]
=
t
[
n
]:
delete
s
[
n
]);
for
(
n
in
e
)
m
(
e
,
n
)
&&!
m
(
t
,
n
)
&&
u
(
e
[
n
])
&&
(
s
[
n
]
=
_
({},
s
[
n
]));
return
s
}
function
P
(
e
){
null
!=
e
&&
this
.
set
(
e
)}
c
.
suppressDeprecationWarnings
=!
1
,
c
.
deprecationHandler
=
null
,
s
=
Object
.
keys
?
Object
.
keys
:
function
(
e
){
var
t
,
n
=
[];
for
(
t
in
e
)
m
(
e
,
t
)
&&
n
.
push
(
t
);
return
n
};
var
W
=
{};
function
H
(
e
,
t
){
var
n
=
e
.
toLowerCase
();
W
[
n
]
=
W
[
n
+
"
s
"
]
=
W
[
t
]
=
e
}
function
R
(
e
){
return
"
string
"
==
typeof
e
?
W
[
e
]
||
W
[
e
.
toLowerCase
()]:
void
0
}
function
C
(
e
){
var
t
,
n
,
s
=
{};
for
(
n
in
e
)
m
(
e
,
n
)
&&
(
t
=
R
(
n
))
&&
(
s
[
t
]
=
e
[
n
]);
return
s
}
var
F
=
{};
function
L
(
e
,
t
){
F
[
e
]
=
t
}
function
U
(
e
,
t
,
n
){
var
s
=
""
+
Math
.
abs
(
e
),
i
=
t
-
s
.
length
;
return
(
0
<=
e
?
n
?
"
+
"
:
""
:
"
-
"
)
+
Math
.
pow
(
10
,
Math
.
max
(
0
,
i
)).
toString
().
substr
(
1
)
+
s
}
var
N
=
/
(\[[^\[]
*
\])
|
(\\)?([
Hh
]
mm
(
ss
)?
|Mo|MM
?
M
?
M
?
|Do|DDDo|DD
?
D
?
D
?
|ddd
?
d
?
|do
?
|w
[
o|w
]?
|W
[
o|W
]?
|Qo
?
|YYYYYY|YYYYY|YYYY|YY|gg
(
ggg
?)?
|GG
(
GGG
?)?
|e|E|a|A|hh
?
|HH
?
|kk
?
|mm
?
|ss
?
|S
{1,9}
|x|X|zz
?
|ZZ
?
|.
)
/g
,
G
=
/
(\[[^\[]
*
\])
|
(\\)?(
LTS|LT|LL
?
L
?
L
?
|l
{1,4})
/g
,
V
=
{},
E
=
{};
function
I
(
e
,
t
,
n
,
s
){
var
i
=
s
;
"
string
"
==
typeof
s
&&
(
i
=
function
(){
return
this
[
s
]()}),
e
&&
(
E
[
e
]
=
i
),
t
&&
(
E
[
t
[
0
]]
=
function
(){
return
U
(
i
.
apply
(
this
,
arguments
),
t
[
1
],
t
[
2
])}),
n
&&
(
E
[
n
]
=
function
(){
return
this
.
localeData
().
ordinal
(
i
.
apply
(
this
,
arguments
),
e
)})}
function
A
(
e
,
t
){
return
e
.
isValid
()?(
t
=
j
(
t
,
e
.
localeData
()),
V
[
t
]
=
V
[
t
]
||
function
(
s
){
var
e
,
i
,
t
,
r
=
s
.
match
(
N
);
for
(
e
=
0
,
i
=
r
.
length
;
e
<
i
;
e
++
)
E
[
r
[
e
]]?
r
[
e
]
=
E
[
r
[
e
]]:
r
[
e
]
=
(
t
=
r
[
e
]).
match
(
/
\[[\s\S]
/
)?
t
.
replace
(
/^
\[
|
\]
$/g
,
""
):
t
.
replace
(
/
\\
/g
,
""
);
return
function
(
e
){
var
t
,
n
=
""
;
for
(
t
=
0
;
t
<
i
;
t
++
)
n
+=
x
(
r
[
t
])?
r
[
t
].
call
(
e
,
s
):
r
[
t
];
return
n
}}(
t
),
V
[
t
](
e
)):
e
.
localeData
().
invalidDate
()}
function
j
(
e
,
t
){
var
n
=
5
;
function
s
(
e
){
return
t
.
longDateFormat
(
e
)
||
e
}
for
(
G
.
lastIndex
=
0
;
0
<=
n
&&
G
.
test
(
e
);)
e
=
e
.
replace
(
G
,
s
),
G
.
lastIndex
=
0
,
n
-=
1
;
return
e
}
var
Z
=
/
\d
/
,
z
=
/
\d\d
/
,
$
=
/
\d{3}
/
,
q
=
/
\d{4}
/
,
J
=
/
[
+-
]?\d{6}
/
,
B
=
/
\d\d?
/
,
Q
=
/
\d\d\d\d?
/
,
X
=
/
\d\d\d\d\d\d?
/
,
K
=
/
\d{1,3}
/
,
ee
=
/
\d{1,4}
/
,
te
=
/
[
+-
]?\d{1,6}
/
,
ne
=
/
\d
+/
,
se
=
/
[
+-
]?\d
+/
,
ie
=
/Z|
[
+-
]\d\d
:
?\d\d
/gi
,
re
=
/Z|
[
+-
]\d\d(?:
:
?\d\d)?
/gi
,
ae
=
/
[
0-9
]{0,256}[
'a-z
\u
00A0-
\u
05FF
\u
0700-
\u
D7FF
\u
F900-
\u
FDCF
\u
FDF0-
\u
FF07
\u
FF10-
\u
FFEF
]{1,256}
|
[\u
0600-
\u
06FF
\/]{1,256}(\s
*
?[\u
0600-
\u
06FF
]{1,256}){1,2}
/i
,
oe
=
{};
function
ue
(
e
,
n
,
s
){
oe
[
e
]
=
x
(
n
)?
n
:
function
(
e
,
t
){
return
e
&&
s
?
s
:
n
}}
function
le
(
e
,
t
){
return
m
(
oe
,
e
)?
oe
[
e
](
t
.
_strict
,
t
.
_locale
):
new
RegExp
(
de
(
e
.
replace
(
"
\\
"
,
""
).
replace
(
/
\\(\[)
|
\\(\])
|
\[([^\]\[]
*
)\]
|
\\(
.
)
/g
,
function
(
e
,
t
,
n
,
s
,
i
){
return
t
||
n
||
s
||
i
})))}
function
de
(
e
){
return
e
.
replace
(
/
[
-
\/\\
^$*+?.()|[
\]
{}
]
/g
,
"
\\
$&
"
)}
var
he
=
{};
function
ce
(
e
,
n
){
var
t
,
s
=
n
;
for
(
"
string
"
==
typeof
e
&&
(
e
=
[
e
]),
d
(
n
)
&&
(
s
=
function
(
e
,
t
){
t
[
n
]
=
k
(
e
)}),
t
=
0
;
t
<
e
.
length
;
t
++
)
he
[
e
[
t
]]
=
s
}
function
fe
(
e
,
i
){
ce
(
e
,
function
(
e
,
t
,
n
,
s
){
n
.
_w
=