Skip to content

Commit 59d7c84

Browse files
authored
Merge pull request #16 from iTrace-Dev/development
Merge for release
2 parents 3a36b85 + 4ff3aca commit 59d7c84

20 files changed

+29612
-2
lines changed
Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
/****************************************************************************************************************************
2+
****************************
3+
* @file FILE.EXT
4+
*
5+
* @copyright (C) 2022 i-trace.org
6+
*
7+
* This file is part of iTrace Infrastructure http://www.i-trace.org/.
8+
* iTrace Infrastructure is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
9+
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
10+
* version.
11+
*
12+
* iTrace Infrastructure is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
13+
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License along with iTrace Infrastructure. If not, see
17+
* https://www.gnu.org/licenses/.
18+
************************************************************************************************************************
19+
********************************/
20+
21+
// main JavaScript driver for the iTrace-Chrome plugin, all data will be handled here
22+
window.iTraceChrome = {
23+
24+
// this function takes the x and y coordinates from the screen and the browser
25+
// to get the offset, which then returns the translated coordinates based off if the user
26+
// is looking in or outside the viewport
27+
translateCoordinates: function (x, y) {
28+
// screen dimensions
29+
var screenX = screen.height;
30+
var screenY = screen.width;
31+
32+
var offsetX = screenX - iTraceChrome.browserX;
33+
var offsetY = screenY - iTraceChrome.browserY;
34+
35+
if (x < offsetX || y < offsetY) {
36+
// user is looking outside of the broswer viewport, most likely at the broswer's shell
37+
return null;
38+
} else {
39+
// user is looking in the broswer viewport, return the translated coordinates
40+
return { x: x - offsetY, y: y - offsetX };
41+
}
42+
},
43+
44+
// this function groups files by their name, param data are the files
45+
groupByFilename: function (data) {
46+
return data.reduce(function (objectsByKeyValue, obj) {
47+
var value = obj.filename;
48+
objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj);
49+
return objectsByKeyValue;
50+
}, {});
51+
},
52+
53+
// this function converts a JSON formatted file to an XML formatted file
54+
json2xml: function (o, tab) {
55+
var toXml = function (v, name, ind) {
56+
var xml = "";
57+
if (v instanceof Array) {
58+
for (var i = 0, n = v.length; i < n; i++)
59+
xml += ind + toXml(v[i], name, ind + "\t") + "\n";
60+
}
61+
else if (typeof (v) == "object") {
62+
var hasChild = false;
63+
xml += ind + "<" + name;
64+
for (var m in v) {
65+
if (m.charAt(0) == "@")
66+
xml += " " + m.substr(1) + "=\"" + String(v[m]);
67+
else
68+
hasChild = true;
69+
}
70+
xml += hasChild ? ">" + "\n" : "/>";
71+
if (hasChild) {
72+
for (var m in v) {
73+
if (m == "#text")
74+
xml += v[m] + "\n";
75+
else if (m == "#cdata")
76+
xml += "<![CDATA[" + v[m] + "]]>";
77+
else if (m.charAt(0) != "@")
78+
xml += toXml(v[m], m, "\t") + "\n";
79+
}
80+
xml += (xml.charAt(xml.length - 1) == "\n" ? ind : "") + "</" + name + ">";
81+
}
82+
}
83+
else {
84+
xml += ind + "<" + name + ">" + String(v) + "</" + name + ">";
85+
}
86+
return xml;
87+
}, xml = "";
88+
for (var m in o)
89+
xml += toXml(o[m], m, "") + "\n";
90+
return xml;
91+
},
92+
93+
// this function takes the data from the session and adds it to the iTraceChrome's sessionData attribute
94+
// and stores it in objectStore
95+
printResults: function (response) {
96+
chrome.tabs.getSelected(null, function (tab) {
97+
this.currentUrl = tab.url;
98+
}.bind(iTraceChrome));
99+
100+
// user is looking off screen
101+
if (response == null) {
102+
return;
103+
}
104+
var sessionDataItem = { filename: iTraceChrome.fileLocation, timestamp: response.time, current_timestamp: new Date().getTime(), x: response.x, y: response.y, area: response.result, line: response.line, word: response.word, tagname: response.tagname, id: response.id, url: iTraceChrome.currentUrl };
105+
iTraceChrome.sessionData.push(sessionDataItem);
106+
107+
if (iTraceChrome.db != null) {
108+
var transaction = iTraceChrome.db.transaction(["sessionData"], "readwrite");
109+
110+
var objectStore = transaction.objectStore("sessionData");
111+
objectStore.add(sessionDataItem)
112+
}
113+
},
114+
115+
// writes the sessionData in XML and downloads the file, then resets sessionData and clears objectStore
116+
writeXMLData: function () {
117+
if (iTraceChrome.websocket != null) {
118+
iTraceChrome.websocket.close();
119+
}
120+
121+
var sessionsData = iTraceChrome.groupByFilename(iTraceChrome.sessionData);
122+
123+
for (var file in sessionsData) {
124+
// call method to parse JSON to xml string, then write to file
125+
var xmlString = iTraceChrome.json2xml(sessionsData[file]);
126+
127+
// create blob with url for chrome.downloads api
128+
var xmlBlob = new Blob([xmlString], { type: "text/xml" });
129+
var url = URL.createObjectURL(xmlBlob);
130+
131+
var filePath = "chrome_plugin_data.xml";
132+
if (file != "") {
133+
filePath = "itrace_chrome_" + file + ".xml";
134+
}
135+
// download file
136+
// currently defaults to downloading to the device's download folder
137+
// can be changed to any path in local storage
138+
chrome.downloads.download({
139+
url: url,
140+
filename: filePath
141+
});
142+
}
143+
144+
iTraceChrome.sessionData = [];
145+
iTraceChrome.fileLocation = "";
146+
147+
if (iTraceChrome.db) {
148+
// objectStore is the (temporary) bridge that allows us to get the local data that is locally stored
149+
// in the iTraceChrome object
150+
var objectStore = iTraceChrome.db.transaction(["sessionData"], "readwrite").objectStore("sessionData");
151+
objectStore.clear();
152+
}
153+
},
154+
155+
// if database data and sessionData are empty, this function will load the
156+
// indexed database data
157+
loadIndexedDBData: function (callback) {
158+
if (iTraceChrome.db && iTraceChrome.sessionData.length == 0) {
159+
var objectStore = iTraceChrome.db.transaction("sessionData").objectStore("sessionData");
160+
objectStore.getAll().onsuccess = function (event) {
161+
iTraceChrome.sessionData = event.target.result;
162+
callback();
163+
}
164+
}
165+
},
166+
167+
// this function deals with incoming eyegaze data
168+
webSocketHandler: function (e) {
169+
var eyeGazeData = e.data;
170+
171+
// sets the file's location upon session start
172+
if (eyeGazeData.substring(0, eyeGazeData.indexOf(',')) == 'session_start') {
173+
var tmp = eyeGazeData.substring(eyeGazeData.indexOf(',') + 1);
174+
tmp = tmp.substring(tmp.indexOf(',') + 1);
175+
iTraceChrome.fileLocation = tmp.substring(0, tmp.indexOf(','));
176+
return;
177+
}
178+
// if session is no longer active, then set iTraceChrome's active status to false
179+
else if (eyeGazeData.substring(0, eyeGazeData.indexOf(',')) == "session_end") {
180+
iTraceChrome.isActive = false;
181+
}
182+
var timeStampAndCoords = eyeGazeData.substring(eyeGazeData.indexOf(',') + 1);
183+
var timeStamp = timeStampAndCoords.substring(0, timeStampAndCoords.indexOf(','));
184+
var coordString = timeStampAndCoords.substring(timeStampAndCoords.indexOf(',') + 1);
185+
186+
var x = coordString.substring(0, coordString.indexOf(','));
187+
var y = coordString.substring(coordString.indexOf(',') + 1, coordString.length);
188+
189+
// parse values
190+
x = parseInt(x);
191+
y = parseInt(y);
192+
193+
// get translated coordinates
194+
var coords = iTraceChrome.translateCoordinates(x, y);
195+
196+
if (!coords || isNaN(x) || isNaN(y)) {
197+
// user is not looking in the html viewport
198+
} else {
199+
// user is looking in the html viewport
200+
// need to check which website the user is looking at
201+
chrome.tabs.query({ 'active': true }, function (tabs) {
202+
var url = iTraceChrome.tab.url;
203+
if (url.includes('stackoverflow.com/questions/')) {
204+
chrome.tabs.sendMessage(iTraceChrome.id, { text: 'get_so_coordinate', x: coords.x, y: coords.y, time: timeStamp, url: url }, iTraceChrome.printResults);
205+
}
206+
if (url.includes('https://bug')) { // NOTE: This include may be incorect, will need to do some more research
207+
chrome.tabs.sendMessage(iTraceChrome.id, { text: 'get_bz_coordinate', x: coords.x, y: coords.y, time: timeStamp, url: url }, iTraceChrome.printResults);
208+
}
209+
if (url.includes('stackoverflow.com/search')) {
210+
chrome.tabs.sendMessage(iTraceChrome.id, { text: 'get_search_coordinate', x: coords.x, y: coords.y, time: timeStamp, url: url }, iTraceChrome.printResults);
211+
}
212+
if (url.includes('google.com')) {
213+
chrome.tabs.sendMessage(iTraceChrome.id, { text: 'get_google_coordinate', x: coords.x, y: coords.y, time: timeStamp, url: url }, iTraceChrome.printResults);
214+
}
215+
if (url.includes('github.com/*/* /issues')) {
216+
chrome.tabs.sendMessage(iTraceChrome.id, { text: 'get_github_issues_coordinate', x: coords.x, y: coords.y, time: timeStamp, url: url }, iTraceChrome.printResults);
217+
}
218+
if (url.includes('github.com/*/*/pulls')) {
219+
chrome.tabs.sendMessage(iTraceChrome.id, { text: 'get_github_prlist_coordinate', x: coords.x, y: coords.y, time: timeStamp, url: url }, iTraceChrome.printResults);
220+
}
221+
if (url.includes('github.com/*/*/pull')) {
222+
chrome.tabs.sendMessage(iTraceChrome.id, { text: 'get_github_pr_coordinate', x: coords.x, y: coords.y, time: timeStamp, url: url }, iTraceChrome.printResults);
223+
}
224+
if (url.includes('github.com') && url.includes('pull')) {
225+
chrome.tabs.sendMessage(iTraceChrome.id, { text: 'get_github_pr_coordinate', x: coords.x, y: coords.y, time: timeStamp, url: url }, iTraceChrome.printResults);
226+
}
227+
if (url.includes('github.com/')) {
228+
chrome.tabs.sendMessage(iTraceChrome.id, { text: 'get_github_dev_profile_coordinate', x: coords.x, y: coords.y, time: timeStamp, url: url }, iTraceChrome.printResults);
229+
}
230+
});
231+
}
232+
},
233+
234+
// this retrieve's the browser's x coordinate
235+
getBrowserX: function (result) {
236+
console.log('browserX');
237+
console.log(result);
238+
this.browserX = result[0];
239+
},
240+
241+
// this retrieve's the browser's y coordinate
242+
getBrowserY: function (result) {
243+
console.log('browserY');
244+
console.log(result);
245+
this.browserY = result[0];
246+
},
247+
248+
// this function begins a session, which binds the browser's x and y coordinates, initializes and
249+
// binds new websocket, sets status to active then listens for eye gaze data from the server
250+
startSession: function (tabs, callback) {
251+
iTraceChrome.tab = tabs[0];
252+
console.log('START SESSION');
253+
254+
chrome.tabs.executeScript({
255+
'code': 'window.innerHeight'
256+
}, iTraceChrome.getBrowserX.bind(iTraceChrome));
257+
258+
chrome.tabs.executeScript({
259+
'code': 'window.innerWidth'
260+
}, iTraceChrome.getBrowserY.bind(iTraceChrome));
261+
262+
iTraceChrome.id = iTraceChrome.tab.id;
263+
264+
iTraceChrome.websocket = new WebSocket('ws://localhost:7007');
265+
266+
// listen for eye gaze data coming from the server
267+
iTraceChrome.websocket.onmessage = iTraceChrome.webSocketHandler.bind(iTraceChrome);
268+
iTraceChrome.isActive = true;
269+
callback(iTraceChrome.websocket);
270+
},
271+
272+
// this functions opens the iTrace database, upon successfully opening the database it
273+
// calls writeXMLData based on the current state of sessionData that's in objectStore
274+
initializeIndxedDB: function () {
275+
if (!window.indexedDB || iTraceChrome.db) {
276+
return;
277+
}
278+
var request = window.indexedDB.open("iTraceDB", 3);
279+
request.onerror = function (event) {
280+
console.log("Couldn't open indexedDB instance. Won't back up along the way");
281+
}
282+
request.onupgradeneeded = function (event) {
283+
var db = event.target.result;
284+
db.createObjectStore("sessionData", { keyPath: "timestamp" });
285+
}
286+
request.onsuccess = function (event) {
287+
iTraceChrome.db = event.target.result;
288+
289+
var objectStore = iTraceChrome.db.transaction("sessionData").objectStore("sessionData");
290+
var countRequest = objectStore.count();
291+
countRequest.onsuccess = function () {
292+
if (countRequest.result > 0) {
293+
console.log("PREVIOUS RESULTS FOUND AND BEING WRITTEN");
294+
295+
objectStore.getAll().onsuccess = function (event) {
296+
iTraceChrome.sessionData = event.target.result;
297+
iTraceChrome.writeXMLData();
298+
}
299+
}
300+
}
301+
}
302+
},
303+
304+
// initializing iTraceChrome
305+
initialize: function () {
306+
if (iTraceChrome.isInitialized) {
307+
return;
308+
}
309+
310+
iTraceChrome.initializeIndxedDB();
311+
iTraceChrome.isInitialized = true;
312+
},
313+
isInitialized: false,
314+
fileLocation: "",
315+
isActive: false,
316+
sessionData: [],
317+
currentUrl: "",
318+
db: null
319+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/****************************************************************************************************************************
2+
****************************
3+
* @file FILE.EXT
4+
*
5+
* @copyright (C) 2022 i-trace.org
6+
*
7+
* This file is part of iTrace Infrastructure http://www.i-trace.org/.
8+
* iTrace Infrastructure is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
9+
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
10+
* version.
11+
*
12+
* iTrace Infrastructure is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
13+
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License along with iTrace Infrastructure. If not, see
17+
* https://www.gnu.org/licenses/.
18+
************************************************************************************************************************
19+
********************************/
20+
21+
console.log('Get BZ Coordinates Script Started');
22+
23+
// listens for data of the different BZ columns and the data associated with and logs it
24+
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
25+
var elements = document.elementsFromPoint(msg.x, msg.y);
26+
27+
var sentResult = false;
28+
for (element of elements) {
29+
if (element.classList.contains('bz_show_bug_column_1')) {
30+
console.log('question info - 1');
31+
sentResult = true;
32+
sendResponse({ result: 'question info - 1', x: msg.x, y: msg.y, time: msg.time, tagname: element.tagName, id: element.id, url: msg.url });
33+
return;
34+
}
35+
36+
if (element.classList.contains('bz_show_bug_column_2')) {
37+
console.log('question info - 1');
38+
sentResult = true;
39+
sendResponse({ result: 'question info - 2', x: msg.x, y: msg.y, time: msg.time, tagname: element.tagName, id: element.id, url: msg.url });
40+
return;
41+
}
42+
43+
if (element.classList.contains('bz_comment')) {
44+
console.log('answer info');
45+
sentResult = true;
46+
sendResponse({ result: 'answer info', x: msg.x, y: msg.y, time: msg.time, tagname: element.tagName, id: element.id, url: msg.url });
47+
return;
48+
}
49+
50+
if (element.tagName == 'TR') {
51+
console.log('attachment info');
52+
sentResult = true;
53+
sendResponse({ result: 'attachment info', x: msg.x, y: msg.y, time: msg.time, tagname: element.tagName, id: element.id, url: msg.url });
54+
return;
55+
}
56+
}
57+
58+
if (!sentResult) {
59+
sendResponse(null);
60+
}
61+
});

0 commit comments

Comments
 (0)