@@ -102,54 +102,35 @@ function getSelectedText() {
102102 }
103103}
104104
105- /**
106- * Fetches the recommendations for the given text.
107- *
108- * @param {Array<String> } text for which the recommendations should be fetched
109- * @return {String } The response as JSON string.
110- */
111- function fetchRecommendations ( text ) {
112- return callProxy ( getTerms ( text ) ) ;
113- }
114-
115- /**
116- * Gets the recommendations from the selected user text.
117- *
118- * @param {Array<String> } text The text entered by the user as array.
119- *
120- * @return {Array<String> } The terms as an array.
121- */
122- function getTerms ( text ) {
123- var terms = [ ] ;
124-
125- // Split the text into terms
126- for ( t in text ) {
127- var tmp = text [ t ] . split ( " " ) ;
128- for ( i in tmp ) {
129- // Replace multiple whitespaces and punctuation marks from the terms
130- terms . push ( tmp [ i ] . replace ( / \s / g, "" ) . replace ( / [ \. , # -\/ ! $ % \^ & \* ; : { } = \- _ ` ~ ( ) ] / g, "" ) ) ;
131- }
132- }
133-
134- return terms ;
135- }
105+ var serverUrl = "https://eexcess.joanneum.at/eexcess-privacy-proxy-issuer-1.0-SNAPSHOT/issuer/" ;
106+ var origin = {
107+ "clientType" : "EEXCESS - Google Docs AddOn" ,
108+ "clientVersion" : "8.0" , //the deployment version in the webstore
109+ "module" : "Sidebar" ,
110+ "userID" : Utilities . computeDigest ( Utilities . DigestAlgorithm . SHA_256 , Session . getActiveUser ( ) . getEmail ( ) ) . toString ( ) // hash value of uid here: MD5(User-Mail)
111+ } ;
136112
137113/**
138- * Calls the privacy proxy
114+ * Calls the privacy proxy for fetching the recommendations for the given keywords.
139115 *
140- * @param {Array<String> } terms The single terms .
116+ * @param {Array<String> } keywords The single keywords .
141117 *
142118 * @return {String } The response as JSON string.
143119 */
144- function callProxy ( terms ) {
120+ function fetchRecommendations ( keywords ) {
145121 // privacy proxy URL
146- var url = "http://eexcess-dev.joanneum.at/eexcess-privacy-proxy-1.0-SNAPSHOT/api/v1/ recommend";
122+ var url = serverUrl + " recommend";
147123
148124 // get result number
149125 var numResults = getResultNumber ( ) ;
150126
151127 // POST payload
152- var data = { "numResults" : numResults , "partnerList" : [ ] , "contextKeywords" : [ ] } ;
128+ var data = {
129+ "numResults" : numResults ,
130+ "partnerList" : [ ] ,
131+ "contextKeywords" : [ ] ,
132+ "origin" : origin
133+ } ;
153134
154135 // set partners
155136 var partners = getPartnerSettings ( ) ;
@@ -163,15 +144,14 @@ function callProxy(terms) {
163144 }
164145
165146 // Fill the context array
166- for ( i in terms ) {
167- data [ "contextKeywords" ] . push ( { "weight" : 1.0 / terms . length , " text" : terms [ i ] } ) ;
147+ for ( i in keywords ) {
148+ data [ "contextKeywords" ] . push ( { "text" : keywords [ i ] } ) ;
168149 }
169150
170151 // Options object, that specifies the method, content type and payload of the HTTPRequest
171152 var options = {
172153 "method" : "POST" ,
173154 "contentType" : "application/json" ,
174- "origin" : "gdocs" ,
175155 "headers" : {
176156 "Accept" : "application/json"
177157 } ,
@@ -185,28 +165,46 @@ function callProxy(terms) {
185165 }
186166}
187167
168+ var DEFAULT_LOCALE = 'en' ;
169+
188170/**
189- * Returns the internationalized message corresponding to the given key. Default language English will be chosen if
190- * user's locale is not supported.
171+ * Returns the user's current locale. If his locale is not supported the DEFAULT_LOCALE will be chosen.
172+ *
173+ * @returns {String } user's locale
174+ */
175+ function getLocale ( ) {
176+ var locale = Session . getActiveUserLocale ( ) ;
177+
178+ if ( locale === 'de' ) {
179+ return locale ;
180+ } else { // return default locale
181+ return DEFAULT_LOCALE ;
182+ }
183+ }
184+
185+ var messages ;
186+ var defaultMessages ;
187+
188+ /**
189+ * Returns the internationalized message corresponding to the given key. DEFAULT_LOCALE will be chosen if no translation
190+ * is available for the user's locale.
191191 *
192192 * @param key message's key
193193 * @returns {String } internationalized message
194194 */
195195function msg ( key ) {
196- if ( ! this . messages ) {
197- var locale = Session . getActiveUserLocale ( ) ;
198- var file ;
199-
200- if ( locale == 'de' ) {
201- file = 'messages_de' ;
202- } else { // use default locale 'en'
203- file = 'messages'
204- }
196+ if ( ! messages ) {
197+ messages = JSON . parse ( HtmlService . createTemplateFromFile ( 'messages_' + getLocale ( ) ) . evaluate ( ) . getContent ( ) ) ;
198+ defaultMessages = JSON . parse ( HtmlService . createTemplateFromFile ( 'messages_' + DEFAULT_LOCALE ) . evaluate ( ) . getContent ( ) ) ;
199+ }
200+
201+ var msg = messages [ key ] ;
205202
206- this . messages = JSON . parse ( HtmlService . createTemplateFromFile ( file ) . evaluate ( ) . getContent ( ) ) ;
203+ if ( ! msg ) {
204+ msg = defaultMessages [ key ] ;
207205 }
208206
209- return this . messages [ key ] ;
207+ return msg
210208}
211209
212210/**
@@ -224,14 +222,22 @@ function openSettingsDialog() {
224222/**
225223 * Fetches the supported providers from the privacy proxy.
226224 *
227- * @returns {* } supported providers
225+ * @returns {String } supported providers
228226 */
229227function fetchProviders ( ) {
230228 // privacy proxy URL
231- var url = "http://eexcess-dev.joanneum.at/eexcess-privacy-proxy-1.0-SNAPSHOT/api/v1/getRegisteredPartners" ;
229+ var url = serverUrl + "getRegisteredPartners" ;
230+
231+ // Options object, that specifies the method and accepted response type of the HTTPRequest
232+ var options = {
233+ "method" : "GET" ,
234+ "headers" : {
235+ "Accept" : "application/json"
236+ }
237+ } ;
232238
233239 try {
234- var response = UrlFetchApp . fetch ( url ) ;
240+ var response = UrlFetchApp . fetch ( url , options ) ;
235241 return response . getContentText ( ) ;
236242 } catch ( err ) {
237243 throw msg ( 'ERROR' ) ;
@@ -288,6 +294,8 @@ function setProperty(key, value) {
288294
289295/**
290296 * Returns the partner settings.
297+ *
298+ * @returns {String } partner settings
291299 */
292300function getPartnerSettings ( ) {
293301 // get all available partners
@@ -347,54 +355,79 @@ function inArray( elem, arr, arrKey) {
347355 return - 1 ;
348356}
349357
350- function insertLink ( link , displayName ) {
358+ /**
359+ * Inserts a link right after the current cursor position/selection and logs this event.
360+ *
361+ * @param displayName link's name to display
362+ * @param documentBadge documentBadge needed for logging containing the link's uri
363+ * @param queryID current query's id needed for logging
364+ */
365+ function insertLink ( displayName , documentBadge , queryID ) {
366+ var uri = documentBadge . uri ;
367+
351368 var doc = DocumentApp . getActiveDocument ( ) ;
352- var body = doc . getBody ( ) ;
353- var paragraphIndex ;
354369
355370 var cursor = doc . getCursor ( ) ;
356371 var paragraph ;
357372
358373 if ( cursor ) {
359- paragraph = cursor . getElement ( ) ;
374+ var surroundingText = cursor . getSurroundingText ( ) . getText ( ) ;
375+ var surroundingTextOffset = cursor . getSurroundingTextOffset ( ) ;
376+
377+ cursor . insertText ( ' ' ) ;
378+
379+ var element = cursor . insertText ( displayName ) ;
380+ element . setLinkUrl ( uri ) ;
381+
382+ // If the cursor follows a non-space character, insert a space and then the link.
383+ if ( surroundingTextOffset > 0 && surroundingText . charAt ( surroundingTextOffset - 1 ) != ' ' )
384+ cursor . insertText ( ' ' ) ;
385+
386+ return ;
360387 }
361388
362389 var selection = doc . getSelection ( ) ;
363390
364391 if ( selection ) {
365- var selectedElements = selection . getSelectedElements ( ) ;
366- var selectedElement = selectedElements [ 0 ] ;
392+ var elements = selection . getRangeElements ( ) ;
393+ var element = elements [ elements . length - 1 ] ;
367394
368- //holds the paragraph
369- var paragraph = selectedElement . getElement ( ) ;
370- }
395+ var text = element . getElement ( ) . editAsText ( ) ;
371396
372- if ( paragraph ) {
373- while ( paragraph . getType ( ) !== DocumentApp . ElementType . PARAGRAPH ) {
374- paragraph = paragraph . getParent ( ) ;
375- }
376-
377- //get the index of the paragraph in the body
378- paragraphIndex = body . getChildIndex ( paragraph ) + 1 ;
397+ if ( text ) {
398+ var offset = element . getEndOffsetInclusive ( ) + 1 ;
379399
380- body . insertParagraph ( paragraphIndex , '' ) . appendText ( displayName ) . setLinkUrl ( link ) ;
400+ text . insertText ( offset , ' ' + displayName ) ;
401+ text . setLinkUrl ( offset + 1 , offset + displayName . length , uri ) ;
402+ }
381403 }
404+
405+ logItemCitedAsHyperlink ( documentBadge , queryID ) ;
382406}
383407
384- function insertImage ( uri ) {
408+ /**
409+ * Inserts an image specified by its uri to a new paragraph after the current cursor position/selection and logs this
410+ * event.
411+ *
412+ * @param date current date for image citation string
413+ * @param image image's uri
414+ * @param documentBadge documentBadge needed for logging
415+ * @param queryID current query's id needed for logging
416+ */
417+ function insertImage ( date , image , documentBadge , queryID ) {
385418 var doc = DocumentApp . getActiveDocument ( ) ;
386- var body = doc . getBody ( ) ;
387- var img = UrlFetchApp . fetch ( uri ) . getBlob ( ) ;
388- var paragraphIndex ;
389-
390419 var cursor = doc . getCursor ( ) ;
391420 var paragraph ;
392421
393422 if ( cursor ) {
394423 paragraph = cursor . getElement ( ) ;
395424 }
396425
397- var selection = doc . getSelection ( ) ;
426+ var selection ;
427+
428+ if ( ! paragraph ) {
429+ selection = doc . getSelection ( ) ;
430+ }
398431
399432 if ( selection ) {
400433 var selectedElements = selection . getSelectedElements ( ) ;
@@ -410,8 +443,84 @@ function insertImage(uri) {
410443 }
411444
412445 //get the index of the paragraph in the body
413- paragraphIndex = body . getChildIndex ( paragraph ) + 1 ;
446+ var body = doc . getBody ( ) ;
447+ var paragraphIndex = body . getChildIndex ( paragraph ) + 1 ;
448+
449+ // insert image
450+ var insertedParagraph = body . insertParagraph ( paragraphIndex , '' ) ;
451+ var img = UrlFetchApp . fetch ( image ) . getBlob ( ) ;
452+ insertedParagraph . appendInlineImage ( img ) ;
453+
454+ // insert citation with current date
455+ insertedParagraph . appendText ( '\r' + msg ( 'CITATION_IMAGE_RETRIEVED' ) + " " + date + " " + msg ( 'CITATION_IMAGE_AT' ) + " " ) ;
456+ insertedParagraph . appendText ( image ) . setLinkUrl ( image ) ;
457+ }
458+
459+ logItemCitedAsImage ( documentBadge , queryID ) ;
460+ }
461+
462+ /**
463+ * Logs that the given item was opened by the user.
464+ *
465+ * @param documentBadge item's document badge
466+ * @param queryID current query's id
467+ */
468+ function logItemOpened ( documentBadge , queryID ) {
469+ logEvent ( "itemOpened" , documentBadge , queryID ) ;
470+ }
471+
472+ /**
473+ * Logs that the given item was cited in a document as image.
474+ *
475+ * @param documentBadge item's document badge
476+ * @param queryID current query's id
477+ */
478+ function logItemCitedAsImage ( documentBadge , queryID ) {
479+ logEvent ( "itemCitedAsImage" , documentBadge , queryID ) ;
480+ }
481+
482+ /**
483+ * Logs that the given item was cited in a document as hyperlink.
484+ *
485+ * @param documentBadge item's document badge
486+ * @param queryID current query's id
487+ */
488+ function logItemCitedAsHyperlink ( documentBadge , queryID ) {
489+ logEvent ( "itemCitedAsHyperlink" , documentBadge , queryID ) ;
490+ }
491+
492+ /**
493+ * Logs a given event for a specified item.
494+ *
495+ * @param event event's name to complete the server url
496+ * @param documentBadge item's document badge
497+ * @param queryID current query's id
498+ */
499+ function logEvent ( event , documentBadge , queryID ) {
500+ // privacy proxy URL
501+ var url = serverUrl + "log/" + event ;
502+
503+ // POST payload
504+ var data = {
505+ "content" : {
506+ "documentBadge" : documentBadge
507+ } ,
508+ "origin" : origin ,
509+ "queryID" : queryID
510+ } ;
414511
415- body . insertParagraph ( paragraphIndex , '' ) . appendInlineImage ( img ) ;
512+ // Options object, that specifies the method, content type and payload of the HTTPRequest
513+ var options = {
514+ "method" : "POST" ,
515+ "contentType" : "application/json" ,
516+ "headers" : {
517+ "Accept" : "application/json"
518+ } ,
519+ "payload" : JSON . stringify ( data )
520+ } ;
521+ try {
522+ UrlFetchApp . fetch ( url , options ) ;
523+ } catch ( err ) {
524+ // suppress error -> not relevant for end user
416525 }
417526}
0 commit comments