-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinternals.html
154 lines (127 loc) · 10.3 KB
/
internals.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
<html>
<head>
<title> PAL: Internals</title>
</head>
<body>
<h2> General Setup and Environment </h2>
<p>The only real tools we used to develop PAL were emacs, Chrome itself, and git.
No additional frameworks or development environments were necessary for the development of PAL. Chrome Extensions
are entirely written in Javascript so we just used emacs to write our code. We originally tried to use
a Javascript version of Eclipse, but Eclipse didn't play well with git so abandoned it.</p>
<p>Chrome provides the following set of Developer Tools which proved to be immensely helpful:
<ul>
<li> <b>Elements</b>. This particular tool allowed us to inspect all the HTML elements in the visible
page which allowed us to accurately tune our code in both the mining and rendering processes. In mining,
knowledge of Blackboard's internal formatting was essential to our success. In rendering, verifying that
our Javascript was correctly forming the page was very helpful for debugging.
</li>
<li> <b>Console</b>. The console provided by Chrome allowed us to interact with existing pages and
try out snippets of Javascript code without needing to load a full extension first. This was essential
during our initial steps in order to become familiar with Javascript and its built-in features.
</li>
</ul>
<p>We used git and GitHub to organize, share, back-up, and separate our code. It was immensely helpful as there were a
couple of times when a group member accidentally ran <tt>rm *</tt> when trying to <tt>rm *~</tt>.
</p>
<h2> Backend </h2>
<h4> Separation of Background Page from Content Page </h4>
<p>Chrome extensions have the option of having a "background page" (Google's term) which is a virtual
web page that exists from when Chrome opens to when Chrome is terminated. This virtual page was useful in
simulating a backend for the extension since it acted as a centralized location for data to be distributed
from and stored to. It was responsible for storing information in local storage (simulating a database); for
detecting differences between the existing set of information and newly mined information. The injected
content scripts were instead responsible for processing user input and for rendering the page to the user.
</p>
<h4> Data Storage </h4>
<p>Chrome Extensions have permission to store string in Chrome's local storage. Since javascript
has JSON translation built-in, we decided to take advantage of it to store our custom objects
in the browser. Unfortunately, JSON storage and parsing does not preserve prototypes of non-standard
objects so a separate function was needed to truly reverse the process of storing information in
the browser.</p>
<p>Since it was conceivable that multiple users would use the same instance of Chrome to access
Blackboard, we stored a user's set of course information under their name (retrievable from the
original Blackboard page that gets wiped clean) in local storage so that different user's won't see
each other's courses.</p>
<h4> Data Organization </h4>
<p>Even though we collected a fair amount of information, there was no simple way of using an
existing database system inside of an extension so we opted to not formally use any database. However, we did take advantage
of Javascript's flexibility in accessing information within Objects to store a user's course
information in a tree. Our Courses object first divided courses by their semester and then by their
actual name in order to match our final representation to the user in PAL.
</p>
<p>Each Course object contains a set of pre-defined entries for attributes used in all courses (e.g. Tools)
and those used most often by courses (e.g. Course Materials, Assignments, Announcements, Syllabus). There is
also an entry (otherLinks) for storing information from either professor-made custom pages (courses with
large lab components will often have a Lab page). Most of the time, these custom pages had the same formatting
as another standard page and thus we were able to use the same mining and rendering proceses to collect and
show the information in customized pages.
</p>
<h4> Mining </h4>
<p>We started the mining process from the Courses tab of Blackboard in order to get URLs to every course
of the current user. Once we had the URLs, the page is wiped to inform the user that PAL is active and in the
process of mining. From there, each course used a series of XMLHttpRequests to get the content-containing
pages (e.g. the Course Materials page, the Announcements page) and scrape the information from them. The collected
information is packaged into Objects we defined (in structures.js) and stored in the appropriate Course object.
We found that customized pages often shared the same formatting as other "standard" pages and thus we were
fortunate in not needing to write a customized miner for each page a professor decided to create. The mining process
occurs periodidically in order to keep PAL up to date with the information on Blackboard.
</p>
<h2> Frontend </h2>
<h4> CSS and HTML </h4>
<p>Because many of the PAL HTML elements feature similar HTML properties, we chose to use CSS and a minimal HTML template
(dividing the page into a side bar, tab bar with a tab table, and main element) which is then populated with
Javascript scripts. The CSS, moreover, is divided into a CSS color file and a general CSS file in order to make
changing colors easier (thus allowing for easier color customizability, should PAL evolve to include such a feature). </p>
<h4> Tabs, Adding and Removing Tabs </h4>
<p>PAL allows the user to add and remove tabs, which, upon intial mining, consist of all of the tabs present in
Blackboard for a given course. Each tab element in the tab bar features an event listener (applied to the whole
tab), which populates the main element with the appropriate content when clicked. Popular tabs, including
"Course Materials", "Assignments", "Contacts", "Syllabus", "Tools", and "Announcements" have their own specified
populate functions, while course-specific tabs, such as "Cool Stuff" for ENG385, use an iFrame
to include the actual Blackboard page. </p>
<p>Each tab includes an "X" button with its own event listener, which, when clicked, first disables the event listener
which would otherwise populate the main window, and then removes the tab. Each Course object contains an array of
removed tabs and an array of currently displayed tabs, and the element is then moved from the current tab array
into the removed tab array. The PAL code, moreover, includes functions for checking whether a tab is removed. The
removed tabs, then appear in a list under the "+" element, and can be added back in (thus moved to the current tab list)
through a click event. Currently, the tab is added to the end of the displayed tabs, as it is popped onto the array</p>
<h4> Adding and Removing Tools </h4>
<p>Adding and removing tools is slightly different than adding and removing tabs because tabs built from tools under
"Tools" should be allowed to be permanently deleted. Thus, the "Tools" tab populates the main element with a list of
tools, featuring up and down arrows which indicate whether the tool is currently in the tab bar (up) or not (down). When an
up arrow is clicked, the tool is added to the list of current tabs, and the tab bar is repopulated to include this
new tab (like with the other tabs the "X" allows this tab to be added to the list of removed tabs). The up arrow is then
rendered as a down arrow. On the other hand, when a down arrow is clicked, the tool is searched for in both the current
tab list and the removed tab list, is removed, and the tab bar is repopulated so that it does not include this tool.</p>
<h4> Populating Frames </h4>
<p>Currently, PAL offers direct access to ICE, Piazza, Score. This is made possible through the use of iFrames. When a
function is called through an event listener, the main window (the area which is not the sidebar, the tab bar, or the
title bar) is cleared of inner HTML and is populated with an iFrame which displays the webpages specified by the urls.
For Score, we chose to populate the iFrame with the actual Score login page, rather than the registrar page with a link
to the Score login in order to make one step of the Score process easier for users. </p>
<p>The Course Description link, likewise, populates the main window with an iFrame containing the webpage from the
Registrar with the course description. The Syllabus tab, similarly, when clicked, calls a function which checks if
the Syllabus is a PDF document, and, if so, populates the window with the PDF (if not, either a link to the syllabus is
provided or a download of the syllabus begins). Checking if documents are PDFs, however, is an expensive call since it
requires a synchronous XMLHTTPRequest, and thus we only check using event listeners when demand for a course element is
present. </p>
<p>While a similar mechanism may be set up for opening course materials and assignments that are PDFs, we chose not to
do this so that the user can open multiple PDFs at a time without running PAL or Blackboard in each open file. However,
should the need for such population arise in the future, the PAL Javascript code includes generic functions to populate
the frame (these accept a link as an argument) and populate the frame with the currently selected tab as a backlink. </p>
<h4> Use of Event Listeners</h4>
<p>We use Event Listeners in order to modify the page as the user interacts with it. This decision was forced from our
choice of implementation in another area, namely the choice of having our extension be a collection of "content scripts"
(as Google chooses to call them). Content scripts of Chrome Extensions run in a different scope from a page's
scripts; this helps with security and to prevent unanticipated interactions between web pages and extensions. However,
this also means that scripts we inject into the page no longer have access to the information stored in our trees
and in the background page.
</p>
<p>We needed a way for the script called upon a click event to have access to the necessary information. The only way
for this to happen without excessive duplication of information
and given our other choices was to attach Event Listeners to elements of the page as we built it.
Content scripts can attach their own Listeners to elements on the DOM and those Listeners will run in the content
scripts' context, solving our issues of scope.
</p>
</body>
</html>