1+ < script src ="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js "> </ script >
2+
3+ < script >
4+ // constants
5+ var REFRESH_INTERVAL = 1000 ; // update selected text inspector every 1 second
6+ var TIMEOUT = 20000 ; // timout of 20s for fetching recommendations
7+
8+ // global variables
9+ var lastSelectedText ;
10+ var lastSearchedText ;
11+
12+ /**
13+ * On document load.
14+ */
15+ $ ( function ( ) {
16+ // init search bar
17+ $ ( "#eexcess-search" ) . keyup ( function ( e ) {
18+ if ( e . keyCode == 13 ) { // Enter keycode
19+ $ ( '#btn-search' ) . click ( ) ;
20+ }
21+ } ) ;
22+
23+ $ ( '#btn-search' ) . click ( getRecommendationsFromInput ) ;
24+
25+ inspectSelectedText ( ) ;
26+ } ) ;
27+
28+ /**
29+ * Runs a server-side function to get the recommendations for the user-entered text and update
30+ * the sidebar UI with the results from the privacy proxy.
31+ */
32+ function getRecommendationsFromInput ( ) {
33+ removeInfo ( ) ;
34+ removeError ( ) ;
35+
36+ var keyword = $ ( "#eexcess-search" ) . val ( ) ;
37+ if ( keyword == "" ) {
38+ showError ( "Please enter some text." ) ;
39+ } else {
40+ this . disabled = true ;
41+ fetchAndDisplayRecommendations ( keyword , this ) ;
42+ }
43+ }
44+
45+ function inspectSelectedText ( ) {
46+ google . script . run
47+ . withSuccessHandler (
48+ function ( selectedText ) {
49+ if ( selectedText . length > 0 && ! arraysEqual ( selectedText , lastSelectedText ) ) {
50+ lastSelectedText = selectedText ;
51+ $ ( "#eexcess-search" ) . val ( selectedText ) ;
52+ $ ( '#btn-search' ) . click ( ) ;
53+ }
54+ } )
55+ . withFailureHandler (
56+ function ( ) {
57+ // ignore errors
58+ } )
59+ . getSelectedText ( ) ;
60+
61+ window . setTimeout ( inspectSelectedText , REFRESH_INTERVAL ) ;
62+ }
63+
64+ /**
65+ * Runs a server-side function to fetch the recommendations for the given text and updates the sidebar UI with the
66+ * results from the privacy proxy or displays and error message in the sidebar.
67+ *
68+ * @param {String } or {Array<String>} text text for which the recommendations should be fetched
69+ * @param button disabled button which triggered the action or undefined if action was not triggered by a button
70+ */
71+ function fetchAndDisplayRecommendations ( text , button ) {
72+ // Remove error messages TODO remove after error messages displayed in recommendations list
73+ removeError ( ) ;
74+
75+ // Clear previously loaded recommendations and displayed errors
76+ $ ( "#eexcess-recommendations-list" ) . empty ( ) ;
77+
78+ // Insert Ajax loader icon
79+ showAjaxLoader ( ) ;
80+
81+ var responded = false ;
82+ var timeout = false ;
83+ lastSearchedText = text ;
84+
85+ setTimeout ( function ( ) {
86+ if ( ! responded ) {
87+ timeout = true ;
88+ removeAjaxLoader ( ) ;
89+
90+ if ( lastSearchedText == text )
91+ showError ( "The server timed out waiting for the request." ) ;
92+
93+ if ( button )
94+ button . disabled = false ;
95+ }
96+ } , TIMEOUT ) ;
97+
98+ google . script . run
99+ . withSuccessHandler (
100+ function ( recommendations , button ) {
101+ if ( ! timeout && lastSearchedText == text ) {
102+ responded = true ;
103+ removeAjaxLoader ( ) ;
104+ // Display Results
105+ showResultList ( recommendations ) ;
106+
107+ if ( button )
108+ button . disabled = false ;
109+ }
110+ } )
111+ . withFailureHandler (
112+ function ( errorMsg , button ) {
113+ if ( ! timeout && lastSearchedText == text ) {
114+ removeAjaxLoader ( ) ;
115+ showError ( errorMsg ) ;
116+
117+ if ( button )
118+ button . disabled = false ;
119+ }
120+ } )
121+ . withUserObject ( button )
122+ . fetchRecommendations ( [ text ] ) ;
123+ }
124+
125+ /**
126+ * Compares two 1-dimensional arrays by their content.
127+ *
128+ * @param a array 1
129+ * @param b array 2
130+ */
131+ function arraysEqual ( a , b ) {
132+ if ( a === b )
133+ return true ;
134+
135+ if ( a == null || b == null )
136+ return false ;
137+
138+ if ( a . length != b . length )
139+ return false ;
140+
141+ for ( var i = 0 ; i < a . length ; ++ i ) {
142+ if ( a [ i ] !== b [ i ] )
143+ return false ;
144+ }
145+
146+ return true ;
147+ }
148+
149+ /**
150+ * Inserts the result list
151+ *
152+ * @param recommendations The results
153+ */
154+ function showResultList ( recommendations ) {
155+ var container = $ ( "#eexcess-recommendations-list" ) ;
156+ var titleLength = 30 ;
157+ var descriptionLength = 80 ;
158+ // Parsing the JSON string
159+ var o = JSON . parse ( recommendations ) ;
160+ if ( o . totalResults > 0 ) {
161+ // iterate the results and append the list elements
162+ $ . each ( o . result , function ( ) {
163+ var title = this . title ;
164+ if ( this . title . length > titleLength ) {
165+ title = jQuery . trim ( title ) . substring ( 0 , titleLength ) . split ( " " ) . slice ( 0 , - 1 ) . join ( " " ) + "..." ;
166+ }
167+ var previewImage = "http://dummyimage.com/60x60/999/fff.png&text=+" ;
168+
169+ if ( this . previewImage ) {
170+ previewImage = this . previewImage ;
171+ }
172+
173+ var description = "No description available." ;
174+
175+ if ( this . description ) {
176+ description = this . description ;
177+ }
178+
179+ var titleDescription = description ;
180+ if ( description . length > descriptionLength ) {
181+ description = jQuery . trim ( description ) . substring ( 0 , descriptionLength ) . split ( " " ) . slice ( 0 , - 1 ) . join ( " " ) + "..." ;
182+ }
183+
184+ var template =
185+ '<li>' +
186+ '<a href="' + this . uri + '" target="_blank" class="inner">' +
187+ '<div class="li-img">' +
188+ '<img src="' + previewImage + '" alt="Image Alt Text" />' +
189+ '</div>' +
190+ '<div class="li-text">' +
191+ '<h4 class="li-head" title="' + this . title + '">' + title + '</h4>' +
192+ '<p class="li-provider">Provider: ' + this . facets . provider + '</p>' +
193+ '<p class="li-summary" title="' + titleDescription + '">' + description + '</p>' +
194+ '</div>' +
195+ '</a>' +
196+ '</li>' ;
197+ container . append ( template ) ;
198+ } )
199+ } else {
200+ showError ( "No results found" ) ;
201+ }
202+ }
203+
204+ /**
205+ * Inserts a div that contains an error message after a given element.
206+ *
207+ * @param msg The error message to display.
208+ * @param element The element after which to display the error.
209+ */
210+ function showError ( msg ) {
211+ removeError ( ) ;
212+ var div = $ ( '<div id="error" class="error">' + msg + '</div>' ) ;
213+ $ ( "#eexcess-recommendations-list" ) . after ( div ) ;
214+ }
215+
216+ /**
217+ * Removes previously added error messages.
218+ */
219+ function removeError ( ) {
220+ $ ( "#error" ) . remove ( ) ;
221+ }
222+
223+ /**
224+ * Removes the initially added info message.
225+ */
226+ function removeInfo ( ) {
227+ $ ( "#info" ) . remove ( ) ;
228+ }
229+
230+ /**
231+ * Inserts the ajax loader icon.
232+ */
233+ function showAjaxLoader ( ) {
234+ if ( $ ( "#ajax-loader-container" ) . length == 0 ) {
235+ var div = $ ( '<div id="ajax-loader-container"><img src="http://mics.fim.uni-passau.de/wp-content/uploads/2014/10/ajax-loader.gif" width="16px" height="16px" alt="ajax loader"/></div>' ) ;
236+ $ ( "#eexcess-recommendations-list" ) . after ( div ) ;
237+ }
238+ }
239+
240+ /**
241+ * Removes the ajax loader icon (spinner) from the DOM.
242+ */
243+ function removeAjaxLoader ( ) {
244+ $ ( '#ajax-loader-container' ) . remove ( ) ;
245+ }
246+ </ script >
0 commit comments