PageRenderTime 29ms CodeModel.GetById 2ms app.highlight 21ms RepoModel.GetById 2ms app.codeStats 0ms

/gnome-extensions/extensions/web_search_dialog@awamper.gmail.com/helper.js

https://gitlab.com/jhta/.myconfig
JavaScript | 250 lines | 205 code | 44 blank | 1 comment | 17 complexity | ece138d78bb4a46622d946d0a789603a MD5 | raw file
  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});