/gnome-extensions/extensions/web_search_dialog@awamper.gmail.com/helper.js
JavaScript | 250 lines | 205 code | 44 blank | 1 comment | 17 complexity | ece138d78bb4a46622d946d0a789603a MD5 | raw file
Possible License(s): GPL-2.0
1const St = imports.gi.St; 2const Lang = imports.lang; 3const PopupMenu = imports.ui.popupMenu; 4const Animation = imports.ui.animation; 5const Params = imports.misc.params; 6const Tweener = imports.ui.tweener; 7const Soup = imports.gi.Soup; 8 9const Me = imports.misc.extensionUtils.getCurrentExtension(); 10const Utils = Me.imports.utils; 11 12const _httpSession = Utils._httpSession; 13 14const DUCKDUCKGO_API_URL = 15 "https://api.duckduckgo.com/?format=json&no_redirect=1"+ 16 "&skip_disambig=1&q="; 17 18const HelperSpinnerMenuItem = Lang.Class({ 19 Name: 'HelperSpinnerMenuItem', 20 Extends: PopupMenu.PopupBaseMenuItem, 21 22 _init: function(text) { 23 this.parent({ 24 reactive: false, 25 activate: false, 26 hover: false, 27 can_focus: false 28 }); 29 this._type = 'HELPER'; 30 31 let spinner = new Animation.AnimatedIcon( 32 global.datadir + '/theme/process-working.svg', 33 24 34 ); 35 spinner.actor.show(); 36 spinner.play(); 37 38 let label = new St.Label({ 39 text: Utils.is_blank(text) ? 'Checking helper...' : text 40 }); 41 42 let box = new St.BoxLayout({ 43 style_class: 'helper-title' 44 }); 45 box.add(spinner.actor); 46 box.add(label); 47 48 this.actor.add_child(box); 49 } 50}); 51 52const DuckDuckGoHelperMenuItem = new Lang.Class({ 53 Name: 'DuckDuckGoHelperMenuItem', 54 Extends: PopupMenu.PopupBaseMenuItem, 55 56 _init: function(data) { 57 this.parent({ 58 reactive: false, 59 activate: false, 60 hover: false, 61 can_focus: false 62 }); 63 this._type = 'HELPER'; 64 65 data = Params.parse(data, { 66 heading: '', 67 definition: '', 68 abstract: '', 69 icon: '' 70 }); 71 72 if(Utils.is_blank(data.abstract) && Utils.is_blank(data.definition)) { 73 return false; 74 } 75 76 let icon = this._get_icon(data.icon); 77 let table = new St.Table({ 78 name: 'helper_table', 79 style_class: 'helper-box' 80 }); 81 let max_length = 80; 82 83 if(icon) { 84 table.add(icon, { 85 row: 0, 86 col: 1, 87 x_fill: false, 88 y_fill: false 89 }); 90 } 91 else { 92 max_length = 110; 93 } 94 95 let text = ''; 96 if(data.definition) {text += '<i>'+data.definition.trim()+'</i>\n';} 97 if(data.abstract) {text += data.abstract.trim();} 98 let label = this._get_label(text, 'helper-abstract', max_length); 99 table.add(label, { 100 row: 0, 101 col: 0 102 }); 103 104 this.actor.add_child(table); 105 106 return true; 107 }, 108 109 _get_icon: function(icon_info) { 110 let info = Params.parse(icon_info, { 111 url: false, 112 width: 120, 113 height: 100 114 }); 115 116 if(!info.url) { 117 return false; 118 } 119 120 let scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor; 121 let textureCache = St.TextureCache.get_default(); 122 let icon = textureCache.load_uri_async( 123 info.url, 124 info.width, 125 info.height, 126 scale_factor 127 ); 128 129 this.icon_box = new St.BoxLayout({ 130 style_class: 'helper-icon-box', 131 opacity: 0 132 }); 133 134 this.icon_box.add(icon); 135 this.icon_box.connect('notify::allocation', Lang.bind(this, function() { 136 let natural_width = this.icon_box.get_preferred_width(-1)[1]; 137 138 if(natural_width > 10) { 139 Tweener.addTween(this.icon_box, { 140 transition: 'easeOutQuad', 141 time: 1, 142 opacity: 255 143 }); 144 } 145 })); 146 147 return this.icon_box; 148 }, 149 150 _get_label: function(text, class_name, max_length) { 151 if(Utils.is_blank(text)) { 152 return false; 153 } 154 155 text = Utils.wordwrap(text.trim(), max_length); 156 157 let label = new St.Label({ 158 text: text, 159 style_class: class_name 160 }); 161 label.clutter_text.use_markup = true; 162 label.clutter_text.line_wrap = true; 163 164 return label; 165 } 166}); 167 168const DuckDuckGoHelper = new Lang.Class({ 169 Name: 'DuckDuckGoHelper', 170 171 _init: function() { 172 // nothing 173 }, 174 175 _get_data_async: function(url, callback) { 176 let request = Soup.Message.new('GET', url); 177 178 _httpSession.queue_message(request, 179 Lang.bind(this, function(_httpSession, message) { 180 if(message.status_code === 200) { 181 callback.call(this, request.response_body.data); 182 } 183 else { 184 callback.call(this, false); 185 } 186 }) 187 ); 188 }, 189 190 _parse_response: function(response) { 191 response = JSON.parse(response); 192 193 let result = { 194 heading: Utils.is_blank(response.Heading) 195 ? false 196 : response.Heading.trim().replace(/<[^>]+>/g, ""), 197 abstract: Utils.is_blank(response.Abstract) 198 ? false 199 : response.AbstractText.trim().replace(/<[^>]+>/g, ""), 200 definition: 201 Utils.is_blank(response.Definition) || 202 response.Definition == response.Abstract 203 ? false 204 : response.Definition.trim().replace(/<[^>]+>/g, ""), 205 image: Utils.is_blank(response.Image) 206 ? false 207 : response.Image.trim() 208 }; 209 210 return result; 211 }, 212 213 get_info: function(query, callback) { 214 query = query.trim(); 215 216 if(Utils.is_blank(query)) { 217 return false; 218 } 219 220 let url = DUCKDUCKGO_API_URL+encodeURIComponent(query); 221 this._get_data_async(url, Lang.bind(this, function(result) { 222 if(!result) { 223 callback.call(this, false); 224 } 225 226 let info = this._parse_response(result); 227 callback.call(this, info); 228 })); 229 230 return true; 231 }, 232 233 get_menu_item: function(data) { 234 data = Params.parse(data, { 235 heading: '', 236 definition: '', 237 abstract: '', 238 icon: false 239 }); 240 241 if(Utils.is_blank(data.abstract) && Utils.is_blank(data.definition)) { 242 return false; 243 } 244 else { 245 let menu_item = new DuckDuckGoHelperMenuItem(data); 246 247 return menu_item; 248 } 249 } 250});