// -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*-
//
// Copyright (C) 2015  Daiki Ueno <dueno@src.gnome.org>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Params = imports.params;
const Pango = imports.gi.Pango;

var MenuPopover = new Lang.Class({
    Name: 'MenuPopover',
    Extends: Gtk.Popover,
    Template: 'resource:///org/gnome/Characters/menu.ui',
    InternalChildren: ['search-entry', 'font-listbox'],

    _createFontListRow: function(title, family) {
        let row = new Gtk.ListBoxRow({ visible: true });
        row.get_style_context().add_class('font');
        row._family = family;
        let label = new Gtk.Label({ label: title,
                                    visible: true,
                                    halign: Gtk.Align.START });
        label.get_style_context().add_class('font-label');
        row.add(label);
        return row;
    },

    _init: function(params) {
        params = Params.fill(params, {});
        this.parent(params);

        this._font_listbox.get_style_context().add_class('fonts');
        let row = this._createFontListRow(_("None"), 'None');
        this._font_listbox.add(row);

        let context = this.get_pango_context();
        let families = context.list_families();
        families = families.sort(function(a, b) {
            return a.get_name().localeCompare(b.get_name());
        });
        for (let index in families) {
            row = this._createFontListRow(families[index].get_name(),
                                          families[index].get_name());
            this._font_listbox.add(row);
        }

        this._keywords = [];
        this._search_entry.connect('search-changed',
                                   Lang.bind(this, this._handleSearchChanged));
        this._font_listbox.connect('row-activated',
                                   Lang.bind(this, this._handleRowActivated));
        this._font_listbox.set_filter_func(Lang.bind(this, this._filterFunc));
        this._font_listbox.set_header_func(Lang.bind(this, this._headerFunc));

        // This silents warning at Characters exit about this widget being
        // visible but not mapped.  Borrowed from Maps.
        this.connect('unmap', function(popover) {
            popover._font_listbox.unselect_all();
            popover.hide();
        });
    },

    _handleSearchChanged: function(entry) {
        let text = entry.get_text().replace(/^\s+|\s+$/g, '');
        let keywords = text == '' ? [] : text.split(/\s+/);
        this._keywords = keywords.map(String.toLowerCase);
        this._font_listbox.invalidate_filter();
        return true;
    },

    _handleRowActivated: function(listBox, row) {
        if (row != null) {
            let toplevel = this.get_toplevel();
            let action = toplevel.lookup_action('filter-font');
            action.activate(new GLib.Variant('s', row._family));
        }
    },

    _filterFunc: function(row) {
        if (this._keywords.length == 0)
            return true;
        if (row._family == 'None')
            return true;

        let nameWords = row._family.split(/\s+/).map(String.toLowerCase);
        return this._keywords.every(function(keyword, index, array) {
            return nameWords.some(function(nameWord, index, array) {
                return nameWord.indexOf(keyword) >= 0;
            });
        });
    },

    _headerFunc: function(row, before) {
        if (before && !row.get_header()) {
            let separator = new Gtk.Separator({
                orientation: Gtk.Orientation.HORIZONTAL
            });
            row.set_header (separator);
        }
    }
});

@@ -861,105 +861,35 @@
 nst 
-Gio = imports.gi.Gio;%0Aconst GLib = imports.gi.GLib;%0Aconst GObject = imports.gi.GObject;%0Aconst Gtk
+%7BGLib, GObject, Gtk, Pango%7D
  = i
@@ -901,13 +901,10 @@
 s.gi
-.Gtk
 ;
+%0A
 %0Acon
@@ -962,126 +962,50 @@
 ms;%0A
-const Pango = imports.gi.Pango;%0A%0Avar MenuPopover = new Lang.Class(%7B%0A    Name: 'MenuPopover',%0A    Extends: Gtk.Popover,
+%0Avar MenuPopover = GObject.registerClass(%7B
 %0A   
@@ -1115,16 +1115,58 @@
 tbox'%5D,%0A
+%7D, class MenuPopover extends Gtk.Popover %7B
 %0A    _cr
@@ -1180,26 +1180,16 @@
 tListRow
-: function
 (title, 
@@ -1198,34 +1198,36 @@
 mily) %7B%0A        
-le
+cons
 t row = new Gtk.
@@ -1607,25 +1607,24 @@
 n row;%0A    %7D
-,
 %0A%0A    _init:
@@ -1622,26 +1622,16 @@
    _init
-: function
 (params)
@@ -1687,18 +1687,18 @@
     
-this.paren
+super._ini
 t(pa
@@ -3042,33 +3042,32 @@
        %7D);%0A    %7D
-,
 %0A%0A    _handleSea
@@ -3076,26 +3076,16 @@
 hChanged
-: function
 (entry) 
@@ -3338,25 +3338,24 @@
  true;%0A    %7D
-,
 %0A%0A    _handl
@@ -3367,26 +3367,16 @@
 ctivated
-: function
 (listBox
@@ -3599,25 +3599,24 @@
      %7D%0A    %7D
-,
 %0A%0A    _filte
@@ -3616,34 +3616,24 @@
  _filterFunc
-: function
 (row) %7B%0A    
@@ -4055,17 +4055,16 @@
 );%0A    %7D
-,
 %0A%0A    _h
@@ -4076,18 +4076,8 @@
 Func
-: function
 (row

Use ES6 classes