[gnome-maps/wip/mlundblad/es6-modules] WIP: port to ES6 modules




commit 86b7ccf1e17e813f9b2a714a178e968bee6e65c2
Author: Marcus Lundblad <ml dfupdate se>
Date:   Tue May 3 00:02:54 2022 +0200

    WIP: port to ES6 modules

 src/application.js                      | 106 +++++++------
 src/boundingBox.js                      |   4 +-
 src/constants.js                        |   8 +-
 src/contactPlace.js                     |  15 +-
 src/contextMenu.js                      |  86 +++++-----
 src/favoritesPopover.js                 |  50 +++---
 src/geoclue.js                          |  53 ++++---
 src/geocode.js                          |  10 +-
 src/graphHopperGeocode.js               |  16 +-
 src/headerBar.js                        |  46 +++---
 src/http.js                             |   6 +-
 src/layersPopover.js                    |  82 +++++-----
 src/location.js                         |  15 +-
 src/main.js                             |  44 ++---
 src/mainWindow.js                       |  76 ++++-----
 src/mapView.js                          | 273 ++++++++++++++++----------------
 src/org.gnome.Maps.in                   |  14 +-
 src/org.gnome.Maps.src.gresource.xml.in |  11 ++
 src/osmAccountDialog.js                 |  42 ++---
 src/osmConnection.js                    |  84 +++++-----
 src/osmEdit.js                          |  18 +--
 src/osmEditDialog.js                    | 129 +++++++--------
 src/osmTypeListRow.js                   |  20 +--
 src/osmTypePopover.js                   |  38 ++---
 src/osmTypeSearchEntry.js               |  24 +--
 src/osmUtils.js                         |   4 +-
 src/overpass.js                         |  44 ++---
 src/photonGeocode.js                    |  16 +-
 src/photonParser.js                     |  12 +-
 src/place.js                            |  33 ++--
 src/placeFormatter.js                   |  14 +-
 src/placeListRow.js                     |  40 ++---
 src/placeStore.js                       |  65 ++++----
 src/route.js                            |  32 ++--
 src/routeQuery.js                       | 134 ++++++++--------
 src/searchPopover.js                    |  20 +--
 src/storedRoute.js                      | 111 ++++++-------
 src/transitOptions.js                   |  34 ++--
 src/zoomInDialog.js                     |  24 +--
 tests/boundingBoxTest.js                |  52 +++---
 tests/meson.build                       |  31 +++-
 tests/test.in                           |  16 +-
 42 files changed, 1034 insertions(+), 918 deletions(-)
---
diff --git a/src/application.js b/src/application.js
index 385061d5..2092f0d9 100644
--- a/src/application.js
+++ b/src/application.js
@@ -20,21 +20,21 @@
  *         Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Geocode = imports.gi.GeocodeGlib;
-const Gio = imports.gi.Gio;
-const Gtk = imports.gi.Gtk;
-const GtkClutter = imports.gi.GtkClutter;
-const Hdy = imports.gi.Handy;
-
-const ContactPlace = imports.contactPlace;
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Geocode from 'gi://GeocodeGlib';
+import Gio from 'gi://Gio';
+import Gtk from 'gi://Gtk';
+import GtkClutter from 'gi://GtkClutter';
+import Hdy from 'gi://Handy';
+
+import {ContactPlace} from './contactPlace.js';
 const Format = imports.format;
-const Geoclue = imports.geoclue;
-const GeocodeFactory = imports.geocode;
-const MainWindow = imports.mainWindow;
-const Maps = imports.gi.GnomeMaps;
-const OSMEdit = imports.osmEdit;
+import {Geoclue} from './geoclue.js';
+import * as GeocodeFactory from './geocode.js';
+import {MainWindow} from './mainWindow.js';
+import Maps from 'gi://GnomeMaps';
+import * as OSMEdit from './osmEdit.js';
 const OSMTypeSearchEntry = imports.osmTypeSearchEntry;
 const PlaceStore = imports.placeStore;
 const RoutingDelegator = imports.routingDelegator;
@@ -43,45 +43,31 @@ const Settings = imports.settings;
 const Utils = imports.utils;
 const URIS = imports.uris;
 
-// used globally
-var application = null;
-var settings = null;
-var placeStore = null;
-var routingDelegator = null;
-var geoclue = null;
-var contactStore = null;
-var osmEdit = null;
-var normalStartup = true;
-var routeQuery = null;
-
 const _ensuredTypes = [OSMTypeSearchEntry.OSMTypeSearchEntry];
 
-var Application = GObject.registerClass({
-    Properties: {
-        'selected-place': GObject.ParamSpec.object('selected-place',
-                                                   'Selected Place',
-                                                   'The selected place',
-                                                   GObject.ParamFlags.READABLE |
-                                                   GObject.ParamFlags.WRITABLE,
-                                                   Geocode.Place),
-        'adaptive-mode': GObject.ParamSpec.boolean('adaptive-mode',
-                                                   'Adaptive Move',
-                                                   'Whether the main window is in adaptive (narrow) mode',
-                                                   GObject.ParamFlags.READABLE |
-                                                   GObject.ParamFlags.WRITABLE),
-    },
-}, class Application extends Gtk.Application {
+export class Application extends Gtk.Application {
+
+    // used globally
+    static application = null;
+    static settings = null;
+    static placeStore = null;
+    static routingDelegator = null;
+    static geoclue = null;
+    static contactStore = null;
+    static osmEdit = null;
+    static normalStartup = true;
+    static routeQuery = null;
 
-    _init() {
+    constructor() {
         /* Translators: This is the program name. */
         GLib.set_application_name(_("Maps"));
 
         /* Needed to be able to use in UI files */
         _ensuredTypes.forEach((type) => GObject.type_ensure(type));
 
-        super._init({ application_id: pkg.name,
-                      flags: Gio.ApplicationFlags.HANDLES_OPEN |
-                             Gio.ApplicationFlags.HANDLES_COMMAND_LINE });
+        super({ application_id: pkg.name,
+                flags: Gio.ApplicationFlags.HANDLES_OPEN |
+                       Gio.ApplicationFlags.HANDLES_COMMAND_LINE });
 
         this.add_main_option('local',
                              0,
@@ -196,7 +182,7 @@ var Application = GObject.registerClass({
     }
 
     _initPlaceStore() {
-        placeStore = new PlaceStore.PlaceStore({
+        Application.placeStore = new PlaceStore({
             recentPlacesLimit: settings.get('recent-places-limit'),
             recentRoutesLimit: settings.get('recent-routes-limit')
         });
@@ -256,13 +242,13 @@ var Application = GObject.registerClass({
     }
 
     _initServices() {
-        settings         = Settings.getSettings('org.gnome.Maps');
-        routeQuery       = new RouteQuery.RouteQuery();
-        routingDelegator = new RoutingDelegator.RoutingDelegator({ query: routeQuery });
-        geoclue          = new Geoclue.Geoclue();
-        contactStore = new Maps.ContactStore();
+        Application.settings         = Settings.getSettings('org.gnome.Maps');
+        Application.routeQuery       = new RouteQuery();
+        Application.routingDelegator = new RoutingDelegator({ query: routeQuery });
+        Application.geoclue          = new Geoclue();
+        Application.contactStore = new GnomeMaps.ContactStore();
         contactStore.load();
-        osmEdit = new OSMEdit.OSMEdit();
+        Application.osmEdit = new OSMEdit();
     }
 
     _createWindow() {
@@ -443,4 +429,20 @@ var Application = GObject.registerClass({
     _onWindowDestroy(window) {
         this._mainWindow = null;
     }
-});
+}
+
+GObject.registerClass({
+    Properties: {
+        'selected-place': GObject.ParamSpec.object('selected-place',
+                                                   'Selected Place',
+                                                   'The selected place',
+                                                   GObject.ParamFlags.READABLE |
+                                                   GObject.ParamFlags.WRITABLE,
+                                                   Geocode.Place),
+        'adaptive-mode': GObject.ParamSpec.boolean('adaptive-mode',
+                                                   'Adaptive Move',
+                                                   'Whether the main window is in adaptive (narrow) mode',
+                                                   GObject.ParamFlags.READABLE |
+                                                   GObject.ParamFlags.WRITABLE),
+    }
+}, Application);
diff --git a/src/boundingBox.js b/src/boundingBox.js
index 0c06875e..396db2ca 100644
--- a/src/boundingBox.js
+++ b/src/boundingBox.js
@@ -19,9 +19,9 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Constants = imports.constants;
+import * as Constants from './constants.js';
 
-var BoundingBox = class {
+export class BoundingBox {
     constructor(params) {
         /* default to a bounding box the "opposite" of covering the whole
          * visible world, this way extending with a coordinate will ensure
diff --git a/src/constants.js b/src/constants.js
index a3419ec7..43a7635e 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -22,7 +22,7 @@
 /**
  * Constraints of visible location in the standard Mercaartor projection.
  */
-var MIN_LATITUDE = -85.0511287798;
-var MAX_LATITUDE = 85.0511287798;
-var MIN_LONGITUDE = -180;
-var MAX_LONGITUDE = 180;
+export var MIN_LATITUDE = -85.0511287798;
+export var MAX_LATITUDE = 85.0511287798;
+export var MIN_LONGITUDE = -180;
+export var MAX_LONGITUDE = 180;
diff --git a/src/contactPlace.js b/src/contactPlace.js
index 6c036c22..52f8870e 100644
--- a/src/contactPlace.js
+++ b/src/contactPlace.js
@@ -19,18 +19,17 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const GObject = imports.gi.GObject;
+import GObject from 'gi://GObject';
 
-const Place = imports.place;
+import {Place} from './place.js';
 
-var ContactPlace = GObject.registerClass(
-class ContactPlace extends Place.Place {
-    _init(params) {
+export class ContactPlace extends Place {
+    constructor(params) {
         this._contact = params.contact;
         delete params.contact;
 
         params.store = false;
-        super._init(params);
+        super(params);
     }
 
     get icon() {
@@ -42,4 +41,6 @@ class ContactPlace extends Place.Place {
                 this.osm_type,
                 this.osm_id].join('-');
     }
-});
+}
+
+GObject.registerClass(ContactPlace);
diff --git a/src/contextMenu.js b/src/contextMenu.js
index 6de6a8c8..4d9e4ee2 100644
--- a/src/contextMenu.js
+++ b/src/contextMenu.js
@@ -19,40 +19,32 @@
  * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const Gdk = imports.gi.Gdk;
-const Geocode = imports.gi.GeocodeGlib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Gdk from 'gi://Gdk';
+import GeocodeGlib from 'gi://GeocodeGlib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 const Mainloop = imports.mainloop;
 
-const Application = imports.application;
-const GeocodeFactory = imports.geocode;
-const Location = imports.location;
-const OSMAccountDialog = imports.osmAccountDialog;
-const OSMEdit = imports.osmEdit;
-const OSMEditDialog = imports.osmEditDialog;
-const Place = imports.place;
-const RouteQuery = imports.routeQuery;
-const Utils = imports.utils;
-const ZoomInDialog = imports.zoomInDialog;
-
-var ContextMenu = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/context-menu.ui',
-    InternalChildren: [ 'whatsHereItem',
-                        'geoURIItem',
-                        'addOSMLocationItem',
-                        'routeFromHereItem',
-                        'addIntermediateDestinationItem',
-                        'routeToHereItem' ],
-}, class ContextMenu extends Gtk.Menu {
-    _init(params) {
+import {Application} from './application.js';
+import * as GeocodeFactory from './geocode.js';
+import {Location} from './location.js';
+import {OSMAccountDialog} from './osmAccountDialog.js';
+import {OSMEdit} from './osmEdit.js';
+import {OSMEditDialog} from './osmEditDialog.js';
+import {Place} from './place.js';
+import {RouteQuery} from './routeQuery.js';
+import * as Utils from './utils.js';
+import {ZoomInDialog} from './zoomInDialog.js';
+
+export class ContextMenu extends Gtk.Menu {
+    constructor(params) {
         this._mapView = params.mapView;
         delete params.mapView;
 
         this._mainWindow = params.mainWindow;
         delete params.mainWindow;
 
-        super._init(params);
+        super(params);
 
         this._buttonGesture =
             new Gtk.GestureSingle({ widget: this._mapView,
@@ -98,19 +90,19 @@ var ContextMenu = GObject.registerClass({
 
     _onRouteFromHereActivated() {
         let query = Application.routeQuery;
-        let location = new Location.Location({ latitude: this._latitude,
-                                               longitude: this._longitude,
-                                               accuracy: 0 });
-        let place = new Place.Place({ location: location, store: false });
+        let location = new Location({ latitude: this._latitude,
+                                      longitude: this._longitude,
+                                      accuracy: 0 });
+        let place = new Place({ location: location, store: false });
 
         query.points[0].place = place;
     }
 
     _onRouteToHereActivated() {
         let query = Application.routeQuery;
-        let location = new Location.Location({ latitude: this._latitude,
-                                               longitude: this._longitude,
-                                               accuracy: 0 });
+        let location = new Location({ latitude: this._latitude,
+                                      longitude: this._longitude,
+                                      accuracy: 0 });
         let place = new Place.Place({ location: location, store: false });
 
         query.points.last().place = place;
@@ -118,10 +110,10 @@ var ContextMenu = GObject.registerClass({
 
     _onAddIntermediateDestinationActivated() {
         let query = Application.routeQuery;
-        let location = new Location.Location({ latitude: this._latitude,
-                                               longitude: this._longitude,
-                                               accuracy: 0 });
-        let place = new Place.Place({ location: location, store: false });
+        let location = new Location({ latitude: this._latitude,
+                                      longitude: this._longitude,
+                                      accuracy: 0 });
+        let place = new Place({ location: location, store: false });
 
         query.addPoint(-1).place = place;
     }
@@ -140,12 +132,12 @@ var ContextMenu = GObject.registerClass({
     }
 
     _onGeoURIActivated() {
-        let location = new Location.Location({ latitude: this._latitude,
-                                               longitude: this._longitude,
-                                               accuracy: 0 });
+        let location = new Location({ latitude: this._latitude,
+                                      longitude: this._longitude,
+                                      accuracy: 0 });
         let display = Gdk.Display.get_default();
         let clipboard = Gtk.Clipboard.get_default(display);
-        let uri = location.to_uri(Geocode.LocationURIScheme.GEO);
+        let uri = location.to_uri(GeocodeGlib.LocationURIScheme.GEO);
 
         clipboard.set_text(uri, uri.length);
     }
@@ -198,4 +190,14 @@ var ContextMenu = GObject.registerClass({
             }
         });
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/context-menu.ui',
+    InternalChildren: [ 'whatsHereItem',
+                        'geoURIItem',
+                        'addOSMLocationItem',
+                        'routeFromHereItem',
+                        'addIntermediateDestinationItem',
+                        'routeToHereItem' ],
+}, ContextMenu);
diff --git a/src/favoritesPopover.js b/src/favoritesPopover.js
index 097c1e58..6e7169a0 100644
--- a/src/favoritesPopover.js
+++ b/src/favoritesPopover.js
@@ -17,40 +17,26 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Application = imports.application;
-const PlaceListRow = imports.placeListRow;
-const PlaceStore = imports.placeStore;
+import {Application} from './application.js';
+import {PlaceListRow} from './placeListRow.js';
+import {PlaceStore} from './placeStore.js';
 
 const _N_VISIBLE = 6;
 
-var FavoritesPopover = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/favorites-popover.ui',
-    InternalChildren: [ 'mainGrid',
-                        'entry',
-                        'scrolledWindow',
-                        'list' ],
-    Properties: {
-        'rows': GObject.ParamSpec.int('rows',
-                                        '',
-                                        '',
-                                        GObject.ParamFlags.READABLE |
-                                        GObject.ParamFlags.WRITABLE,
-                                        0, GLib.MAXINT32, 0)
-    }
-}, class FavoritesPopover extends Gtk.Popover {
+export class FavoritesPopover extends Gtk.Popover {
 
-    _init(params) {
+    constructor(params) {
         params = params || { };
 
         this._mapView = params.mapView;
         delete params.mapView;
 
         params.transitions_enabled = false;
-        super._init(params);
+        super(params);
 
         this._rows = 0;
 
@@ -117,4 +103,20 @@ var FavoritesPopover = GObject.registerClass({
 
         this.rows = rows;
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/favorites-popover.ui',
+    InternalChildren: [ 'mainGrid',
+                        'entry',
+                        'scrolledWindow',
+                        'list' ],
+    Properties: {
+        'rows': GObject.ParamSpec.int('rows',
+                                        '',
+                                        '',
+                                        GObject.ParamFlags.READABLE |
+                                        GObject.ParamFlags.WRITABLE,
+                                        0, GLib.MAXINT32, 0)
+    }
+}, FavoritesPopover);
diff --git a/src/geoclue.js b/src/geoclue.js
index af127355..8a1497de 100644
--- a/src/geoclue.js
+++ b/src/geoclue.js
@@ -19,15 +19,14 @@
  * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const GObject = imports.gi.GObject;
-const GClue = imports.gi.Geoclue;
-const Gio = imports.gi.Gio;
+import GObject from 'gi://GObject';
+import GClue from 'gi://Geoclue';
+import Gio from 'gi://Gio';
 const Mainloop = imports.mainloop;
 
-const Place = imports.place;
-const Location = imports.location;
-const Settings = imports.settings;
-const Utils = imports.utils;
+import {Place} from './place.js';
+import {Location} from './location.js';
+import * as Utils from './utils.js';
 
 var State = {
     INITIAL: 0,
@@ -36,21 +35,7 @@ var State = {
     FAILED: 3
 };
 
-var Geoclue = GObject.registerClass({
-    Signals: {
-        'location-changed': { }
-    },
-    Properties: {
-        'state': GObject.ParamSpec.int('state',
-                                       '',
-                                       '',
-                                       GObject.ParamFlags.READABLE |
-                                       GObject.ParamFlags.WRITABLE,
-                                       State.INITIAL,
-                                       State.FAILED,
-                                       State.INITIAL)
-    },
-}, class Geoclue extends GObject.Object {
+export class Geoclue extends GObject.Object {
 
     set state(s) {
         this._state = s;
@@ -61,7 +46,7 @@ var Geoclue = GObject.registerClass({
         return this._state;
     }
 
-    _init() {
+    constructor() {
         super._init();
         this.place = null;
         this._state = State.INITIAL;
@@ -119,8 +104,8 @@ var Geoclue = GObject.registerClass({
 
     _updateLocation(location) {
         if (!this.place)
-            this.place = new Place.Place({ name: _("Current Location"),
-                                           isCurrentLocation: true });
+            this.place = new Place({ name: _("Current Location"),
+                                     isCurrentLocation: true });
 
         this.place.location = location;
         this.emit('location-changed');
@@ -128,4 +113,20 @@ var Geoclue = GObject.registerClass({
                     " (" + location.latitude + ", " + location.longitude +
                     ", accuracy = " + location.accuracy + " m)");
     }
-});
+}
+
+GObject.registerClass({
+    Signals: {
+        'location-changed': { }
+    },
+    Properties: {
+        'state': GObject.ParamSpec.int('state',
+                                       '',
+                                       '',
+                                       GObject.ParamFlags.READABLE |
+                                       GObject.ParamFlags.WRITABLE,
+                                       State.INITIAL,
+                                       State.FAILED,
+                                       State.INITIAL)
+    },
+}, Geoclue);
diff --git a/src/geocode.js b/src/geocode.js
index 7623684a..996cd91d 100644
--- a/src/geocode.js
+++ b/src/geocode.js
@@ -19,18 +19,18 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Service = imports.service;
-const GraphHopperGeocode = imports.graphHopperGeocode;
-const PhotonGeocode = imports.photonGeocode;
+import * as Service from './service.js';
+import {GraphHopperGeocode} from './graphHopperGeocode.js';
+import {PhotonGeocode} from './photonGeocode.js';
 
 var _geocoder = null;
 
 function getGeocoder() {
     if (!_geocoder) {
         if (Service.getService().photonGeocode)
-            _geocoder = new PhotonGeocode.PhotonGeocode();
+            _geocoder = new PhotonGeocode();
         else
-            _geocoder = new GraphHopperGeocode.GraphHopperGeocode();
+            _geocoder = new GraphHopperGeocode();
     }
 
     return _geocoder;
diff --git a/src/graphHopperGeocode.js b/src/graphHopperGeocode.js
index 975cde2e..b74142c3 100644
--- a/src/graphHopperGeocode.js
+++ b/src/graphHopperGeocode.js
@@ -21,19 +21,19 @@
 
 const Format = imports.format;
 
-const GLib = imports.gi.GLib;
-const Soup = imports.gi.Soup;
+import GLib from 'gi://GLib';
+import Soup from 'gi://Soup';
 
-const Application = imports.application;
-const HTTP = imports.http;
-const PhotonParser = imports.photonParser;
-const Service = imports.service;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import * as HTTP from './http.js';
+import * as PhotonParser from './photonParser.js';
+import * as Service from './service.js';
+import * as Utils from './utils.js';
 
 // HTTP session timeout (in seconds)
 const TIMEOUT = 5;
 
-var GraphHopperGeocode = class {
+export class GraphHopperGeocode {
     constructor() {
         this._session =
             new Soup.Session({ user_agent : 'gnome-maps/' + pkg.version,
diff --git a/src/headerBar.js b/src/headerBar.js
index cbd74274..d010893b 100644
--- a/src/headerBar.js
+++ b/src/headerBar.js
@@ -20,25 +20,22 @@
  *         Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const FavoritesPopover = imports.favoritesPopover;
-const LayersPopover = imports.layersPopover;
-const MapView = imports.mapView;
+import {FavoritesPopover} from './favoritesPopover.js';
+import {LayersPopover} from './layersPopover.js';
+import {MapView} from './mapView.js';
 
-var HeaderBarLeft = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/headerbar-left.ui',
-    InternalChildren: [ 'layersButton' ]
-}, class HeaderBarLeft extends Gtk.Box {
-    _init(params) {
+export class HeaderBarLeft extends Gtk.Box {
+    constructor(params) {
         this._application = params.application;
         delete params.application;
 
         this._mapView = params.mapView;
         delete params.mapView;
 
-        super._init(params);
+        super(params);
 
         this._layersPopover = new LayersPopover.LayersPopover({
             mapView: this._mapView
@@ -49,22 +46,22 @@ var HeaderBarLeft = GObject.registerClass({
     popdownLayersPopover() {
         this._layersPopover.popdown();
     }
-});
+}
 
-var HeaderBarRight = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/headerbar-right.ui',
-    InternalChildren: [ 'toggleSidebarButton',
-                        'favoritesButton',
-                        'printRouteButton' ]
-}, class HeaderBarRight extends Gtk.Box {
-    _init(params) {
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/headerbar-left.ui',
+    InternalChildren: [ 'layersButton' ]
+}, HeaderBarLeft);
+
+export class HeaderBarRight extends Gtk.Box {
+    constructor(params) {
         this._application = params.application;
         delete params.application;
 
         this._mapView = params.mapView;
         delete params.mapView;
 
-        super._init(params);
+        super(params);
 
         this._favoritesButton.popover = new FavoritesPopover.FavoritesPopover({
             mapView: this._mapView
@@ -78,4 +75,11 @@ var HeaderBarRight = GObject.registerClass({
         this._mapView.bind_property('routeShowing', this._printRouteButton,
                                     'visible', GObject.BindingFlags.DEFAULT);
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/headerbar-right.ui',
+    InternalChildren: [ 'toggleSidebarButton',
+                        'favoritesButton',
+                        'printRouteButton' ]
+}, HeaderBarRight);
diff --git a/src/http.js b/src/http.js
index 8d853fee..ee8e65dc 100644
--- a/src/http.js
+++ b/src/http.js
@@ -19,7 +19,7 @@
  * Author: Mattias Bengtsson <mattias jc bengtsson gmail com>
  */
 
-const Soup = imports.gi.Soup;
+import Soup from 'gi://Soup';
 
 function encode(data) {
     if(data === null)
@@ -28,7 +28,7 @@ function encode(data) {
     return Soup.URI.encode(data.toString(), '&');
 }
 
-var Query = class Query {
+export class Query {
 
     constructor(obj) {
         this._query = {};
@@ -73,4 +73,4 @@ var Query = class Query {
         }
         return vars.join('&');
     }
-};
+}
diff --git a/src/layersPopover.js b/src/layersPopover.js
index d421b71f..55059aa8 100644
--- a/src/layersPopover.js
+++ b/src/layersPopover.js
@@ -17,33 +17,29 @@
  * Author: Dario Di Nucci <linkin88mail gmail com>
  */
 
-const Champlain = imports.gi.Champlain;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-const Gdk = imports.gi.Gdk;
-const Hdy = imports.gi.Handy;
-
-const Application = imports.application;
-const MapSource = imports.mapSource;
-const MapView = imports.mapView;
-const Service = imports.service;
-const ShapeLayer = imports.shapeLayer;
-const Utils = imports.utils;
+import Champlain from 'gi://Champlain';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import Gdk from 'gi://Gdk';
+import Handy from 'gi://Handy';
+
+import {Application} from './application.js';
+import {MapSource} from './mapSource.js';
+import {MapView} from './mapView.js';
+import * as Service from './service.js';
+import {ShapeLayer} from './shapeLayer.js';
+import * as Utils from './utils.js';
 
 const PREVIEW_WIDTH = 230;
 const PREVIEW_HEIGHT = 80;
 
-var ShapeLayerRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/shape-layer-row.ui',
-    Children: ['closeButton'],
-    InternalChildren: ['layerLabel', 'visibleButton']
-}, class ShapeLayerRow extends Gtk.ListBoxRow {
+export class ShapeLayerRow extends Gtk.ListBoxRow {
 
-    _init(params) {
+    constructor(params) {
         this.shapeLayer = params.shapeLayer;
         delete params.shapeLayer;
 
-        super._init(params);
+        super(params);
 
         this._layerLabel.label = this.shapeLayer.getName();
         this._layerLabel.tooltip_text = this.shapeLayer.file.get_parse_name();
@@ -58,27 +54,24 @@ var ShapeLayerRow = GObject.registerClass({
                 image.icon_name = 'layer-not-visible-symbolic';
         });
     }
-});
+}
 
-var LayersPopover = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/layers-popover.ui',
-    InternalChildren: [ 'streetLayerButton',
-                        'aerialLayerButton',
-                        'streetLayerImage',
-                        'aerialLayerImage',
-                        'hybridAerialRevealer',
-                        'layersListBox',
-                        'loadLayerButton' ]
-}, class LayersPopover extends Gtk.Popover {
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/shape-layer-row.ui',
+    Children: ['closeButton'],
+    InternalChildren: ['layerLabel', 'visibleButton']
+}, ShapeLayerRow);
+
+export class LayersPopover extends Gtk.Popover {
 
-    _init(params) {
+    constructor(params) {
         this._mapView = params.mapView;
         delete params.mapView;
 
-        super._init({ width_request: 200,
-                      no_show_all: true,
-                      transitions_enabled: false,
-                      visible: false });
+        super({ width_request: 200,
+                no_show_all: true,
+                transitions_enabled: false,
+                visible: false });
 
         this._aerialLayerButton.join_group(this._streetLayerButton);
 
@@ -145,7 +138,7 @@ var LayersPopover = GObject.registerClass({
                                        this._setLayerPreviews.bind(this));
             this._mapView.view.connect("notify::longitude",
                                        this._setLayerPreviews.bind(this));
-            Hdy.StyleManager.get_default().connect("notify::dark",
+            Handy.StyleManager.get_default().connect("notify::dark",
                                                     this._onDarkChanged.bind(this));
             Application.settings.connect("changed::hybrid-aerial",
                                          this._onHybridAerialChanged.bind(this));
@@ -163,7 +156,7 @@ var LayersPopover = GObject.registerClass({
 
     _onDarkChanged() {
         if (Service.getService().tiles.streetDark &&
-            Hdy.StyleManager.get_default().dark) {
+            Handy.StyleManager.get_default().dark) {
             this._setLayerPreviewImage('streetDark', true);
         } else {
             this._setLayerPreviewImage('street', true);
@@ -181,7 +174,7 @@ var LayersPopover = GObject.registerClass({
 
     _setLayerPreviews() {
         if (Service.getService().tiles.streetDark &&
-            Hdy.StyleManager.get_default().dark) {
+            Handy.StyleManager.get_default().dark) {
             this._setLayerPreviewImage('streetDark');
         } else {
             this._setLayerPreviewImage('street');
@@ -264,4 +257,15 @@ var LayersPopover = GObject.registerClass({
         this._layersListBox.show();
         return row;
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/layers-popover.ui',
+    InternalChildren: [ 'streetLayerButton',
+                        'aerialLayerButton',
+                        'streetLayerImage',
+                        'aerialLayerImage',
+                        'hybridAerialRevealer',
+                        'layersListBox',
+                        'loadLayerButton' ]
+}, LayersPopover);
diff --git a/src/location.js b/src/location.js
index 88427abc..473fcbdc 100644
--- a/src/location.js
+++ b/src/location.js
@@ -21,18 +21,17 @@
  *          Jonas Danielsson <jonas threetimestwo org>
  */
 
-const Geocode = imports.gi.GeocodeGlib;
-const GObject = imports.gi.GObject;
+import Geocode from 'gi://GeocodeGlib';
+import GObject from 'gi://GObject';
 
 /* Adds heading to Geocode.Location */
-var Location = GObject.registerClass(
-class Location extends Geocode.Location {
+export class Location extends Geocode.Location {
 
-    _init(params) {
+    constructor(params) {
         this._heading = params.heading;
         delete params.heading;
 
-        super._init(params);
+        super(params);
     }
 
     get heading() {
@@ -42,4 +41,6 @@ class Location extends Geocode.Location {
     set heading(v) {
         this._heading = v;
     }
-});
+}
+
+GObject.registerClass(Location);
diff --git a/src/main.js b/src/main.js
index 6e4fa113..d46faa94 100644
--- a/src/main.js
+++ b/src/main.js
@@ -20,27 +20,29 @@
  *         Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
+import 'gi://Champlain?version=0.12';
+import 'gi://Clutter?version=1.0';
+import 'gi://Cogl?version=1.0';
+import 'gi://GeocodeGlib?version=1.0';
+import 'gi://Gdk?version=3.0';
+import 'gi://GdkPixbuf?version=2.0';
+import 'gi://Gio?version=2.0';
+import 'gi://GLib?version=2.0';
+import 'gi://GObject?version=2.0';
+import 'gi://Gtk?version=3.0';
+import 'gi://GtkChamplain?version=0.12';
+import 'gi://GtkClutter?version=1.0';
+import 'gi://GWeather?version=4.0';
+import 'gi://Handy?version=1';
+import 'gi://Rest?version=0.7';
+import 'gi://Soup?version=2.4';
+
+import * as system from 'system';
+
+import {Application} from './application.js';
+
 pkg.initGettext();
 pkg.initFormat();
-pkg.require({ 'cairo': '1.0',
-              'Champlain': '0.12',
-              'Clutter': '1.0',
-              'Cogl': '1.0',
-              'GeocodeGlib': '1.0',
-              'Gdk': '3.0',
-              'GdkPixbuf': '2.0',
-              'Gio': '2.0',
-              'GLib': '2.0',
-              'GObject': '2.0',
-              'Gtk': '3.0',
-              'GtkChamplain': '0.12',
-              'GtkClutter': '1.0',
-              'GWeather': '4.0',
-              'Handy': '1',
-              'Rest': '0.7',
-              'Soup': '2.4' });
-
-const Application = imports.application;
 
 function main(args) {
     /* Add prototype to get last element of an array.
@@ -53,6 +55,8 @@ function main(args) {
         }
     }
 
-    let application = new Application.Application();
+    let application = new Application();
     return application.run(args);
 }
+
+main([system.programInvocationName, ...system.programArgs]);
diff --git a/src/mainWindow.js b/src/mainWindow.js
index bb4fc69e..f565dbd8 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -20,23 +20,23 @@
  *         Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const _ = imports.gettext.gettext;
-
-const Champlain = imports.gi.Champlain;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gdk = imports.gi.Gdk;
-const Gio = imports.gi.Gio;
-const Gtk = imports.gi.Gtk;
+//const _ = imports.gettext.gettext;
+
+import Champlain from 'gi://Champlain';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gdk from 'gi://Gdk';
+import Gio from 'gi://Gio';
+import Gtk from 'gi://Gtk';
 const Mainloop = imports.mainloop;
 
-const Application = imports.application;
-const ContextMenu = imports.contextMenu;
-const ExportViewDialog = imports.exportViewDialog;
-const FavoritesPopover = imports.favoritesPopover;
-const Geoclue = imports.geoclue;
-const GeocodeFactory = imports.geocode;
-const HeaderBar = imports.headerBar;
+import {Application} from './application.js';
+import {ContextMenu} from './contextMenu.js';
+import {ExportViewDialog} from './exportViewDialog.js';
+import {FavoritesPopover} from './favoritesPopover.js';
+import {Geoclue} from './geoclue.js';
+import * as GeocodeFactory from './geocode.js';
+import {HeaderBarLeft, HeaderBarRight} from './headerBar.js';
 const LocationServiceDialog = imports.locationServiceDialog;
 const MapView = imports.mapView;
 const PlaceBar = imports.placeBar;
@@ -52,12 +52,10 @@ const _CONFIGURE_ID_TIMEOUT = 100; // msecs
 const _ADAPTIVE_VIEW_WIDTH = 700;
 const _PLACE_ENTRY_MARGIN = 35;
 
-var ShapeLayerFileChooser = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/shape-layer-file-chooser.ui'
-}, class ShapeLayerFileChooser extends Gtk.FileChooserNative {
+export class ShapeLayerFileChooser extends Gtk.FileChooserNative {
 
-    _init(params) {
-        super._init(params);
+    constructor(params) {
+        super(params);
         let allFilter = new Gtk.FileFilter();
         allFilter.set_name(_("All Layer Files"));
         this.add_filter(allFilter);
@@ -75,16 +73,13 @@ var ShapeLayerFileChooser = GObject.registerClass({
             this.add_filter(filter);
         });
     }
-});
+}
 
-var MainWindow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/main-window.ui',
-    InternalChildren: [ 'headerBar',
-                        'grid',
-                        'actionBar',
-                        'actionBarRevealer',
-                        'placeBarContainer']
-}, class MainWindow extends Gtk.ApplicationWindow {
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/shape-layer-file-chooser.ui'
+}, ShapeLayerFileChooser);
+
+export class MainWindow extends Gtk.ApplicationWindow {
 
     get mapView() {
         return this._mapView;
@@ -94,8 +89,8 @@ var MainWindow = GObject.registerClass({
         return this._placeEntry;
     }
 
-    _init(params) {
-        super._init(params);
+    constructor(params) {
+        super(params);
 
         this._configureId = 0;
 
@@ -348,13 +343,13 @@ var MainWindow = GObject.registerClass({
     }
 
     _initHeaderbar() {
-        this._headerBarLeft = new HeaderBar.HeaderBarLeft({
+        this._headerBarLeft = new HeaderBarLeft({
             mapView: this._mapView,
             application: this.application
         });
         this._headerBar.pack_start(this._headerBarLeft);
 
-        this._headerBarRight = new HeaderBar.HeaderBarRight({
+        this._headerBarRight = new HeaderBarRight({
             mapView: this._mapView,
             application: this.application
         });
@@ -367,13 +362,13 @@ var MainWindow = GObject.registerClass({
                                     this._updateLocationSensitivity.bind(this));
 
         // action bar, for when the window is too narrow for the full headerbar
-        this._actionBarLeft =  new HeaderBar.HeaderBarLeft({
+        this._actionBarLeft =  new HeaderBarLeft({
             mapView: this._mapView,
             application: this.application
         })
         this._actionBar.pack_start(this._actionBarLeft);
 
-        this._actionBarRight = new HeaderBar.HeaderBarRight({
+        this._actionBarRight = new HeaderBarRight({
             mapView: this._mapView,
             application: this.application
         })
@@ -675,4 +670,13 @@ var MainWindow = GObject.registerClass({
         });
         this._fileChooser.show();
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/main-window.ui',
+    InternalChildren: [ 'headerBar',
+                        'grid',
+                        'actionBar',
+                        'actionBarRevealer',
+                        'placeBarContainer']
+}, MainWindow);
diff --git a/src/mapView.js b/src/mapView.js
index 103a40d3..1e30104c 100644
--- a/src/mapView.js
+++ b/src/mapView.js
@@ -19,58 +19,44 @@
  * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
-const Champlain = imports.gi.Champlain;
-const Clutter = imports.gi.Clutter;
-const GObject = imports.gi.GObject;
-const Geocode = imports.gi.GeocodeGlib;
-const Gio = imports.gi.Gio;
-const Gtk = imports.gi.Gtk;
-const GtkChamplain = imports.gi.GtkChamplain;
-const Hdy = imports.gi.Handy;
+import Champlain from 'gi://Champlain';
+import Clutter from 'gi://Clutter';
+import GObject from 'gi://GObject';
+import GeocodeGlib from 'gi://GeocodeGlib';
+import Gio from 'gi://Gio';
+import Gtk from 'gi://Gtk';
+import GtkChamplain from 'gi://GtkChamplain';
+import Handy from 'gi://Handy';
 const Mainloop = imports.mainloop;
 
-const Application = imports.application;
-const BoundingBox = imports.boundingBox;
-const ContactPlace = imports.contactPlace;
-const Color = imports.color;
-const Geoclue = imports.geoclue;
-const GeoJSONShapeLayer = imports.geoJSONShapeLayer;
-const KmlShapeLayer = imports.kmlShapeLayer;
-const GpxShapeLayer = imports.gpxShapeLayer;
-const Location = imports.location;
-const Maps = imports.gi.GnomeMaps;
-const MapSource = imports.mapSource;
-const MapWalker = imports.mapWalker;
-const Place = imports.place;
-const PlaceMarker = imports.placeMarker;
-const RouteQuery = imports.routeQuery;
-const Service = imports.service;
-const ShapeLayer = imports.shapeLayer;
-const StoredRoute = imports.storedRoute;
-const TransitArrivalMarker = imports.transitArrivalMarker;
-const TransitBoardMarker = imports.transitBoardMarker;
-const TransitWalkMarker = imports.transitWalkMarker;
-const TurnPointMarker = imports.turnPointMarker;
-const UserLocationMarker = imports.userLocationMarker;
-const Utils = imports.utils;
-
-var MapType = {
-    LOCAL: 'MapsLocalSource',
-    STREET: 'MapsStreetSource',
-    AERIAL: 'MapsAerialSource'
-};
+import GnomeMaps from 'gi://GnomeMaps';
+
+import {Application} from './application.js';
+import {BoundingBox} from './boundingBox.js';
+import {ContactPlace} from './contactPlace.js';
+import * as Color from './color.js';
+import * as Geoclue from './geoclue.js';
+import {GeoJSONShapeLayer} from './geoJSONShapeLayer.js';
+import {KmlShapeLayer} from './kmlShapeLayer.js';
+import {GpxShapeLayer} from './gpxShapeLayer.js';
+import {Location} from './location.js';
+import {MapSource} from './mapSource.js';
+import {MapWalker} from './mapWalker.js';
+import {Place} from './place.js';
+import {PlaceMarker} from './placeMarker.js';
+import * as Service from './service.js';
+import {ShapeLayer} from './shapeLayer.js';
+import {StoredRoute} from './storedRoute.js';
+import {TransitArrivalMarker} from './transitArrivalMarker.js';
+import {TransitBoardMarker} from './transitBoardMarker.js';
+import {TransitWalkMarker} from './transitWalkMarker.js';
+import {TurnPointMarker} from './turnPointMarker.js';
+import {UserLocationMarker} from './userLocationMarker.js';
+import * as Utils from './utils.js';
+
 const _LOCATION_STORE_TIMEOUT = 500;
 const MapMinZoom = 2;
 
-/*
- * Due to the mathematics of spherical mericator projection,
- * the map must be truncated at a latitude less than 90 degrees.
- */
-var MAX_LATITUDE = 85.05112;
-var MIN_LATITUDE = -85.05112;
-var MAX_LONGITUDE = 180;
-var MIN_LONGITUDE = -180;
-
 /* threashhold for route color luminance when we consider it more or less
  * as white, and draw an outline on the path */
 const OUTLINE_LUMINANCE_THREASHHOLD = 0.9;
@@ -92,33 +78,22 @@ const DASHED_ROUTE_LINE_GAP_LENGTH = 5;
 // Maximum limit of file size (20 MB) that can be loaded without user confirmation
 const FILE_SIZE_LIMIT_MB = 20;
 
-var MapView = GObject.registerClass({
-    Properties: {
-        // this property is true when the routing sidebar is active
-        'routingOpen': GObject.ParamSpec.boolean('routingOpen',
-                                                  'Routing open',
-                                                  'Routing sidebar open',
-                                                  GObject.ParamFlags.READABLE |
-                                                  GObject.ParamFlags.WRITABLE,
-                                                  false),
-        /* this property is true when a route is being shown on the map */
-        'routeShowing': GObject.ParamSpec.boolean('routeShowing',
-                                                 'Route showing',
-                                                 'Showing a route on the map',
-                                                 GObject.ParamFlags.READABLE |
-                                                 GObject.ParamFlags.WRITABLE,
-                                                 false)
-    },
-    Signals: {
-        'user-location-changed': {},
-        'going-to': {},
-        'going-to-user-location': {},
-        'gone-to-user-location': {},
-        'view-moved': {},
-        'marker-selected': { param_types: [Champlain.Marker] },
-        'map-type-changed': { param_types: [GObject.TYPE_STRING] }
-    },
-}, class MapView extends GtkChamplain.Embed {
+export class MapView extends GtkChamplain.Embed {
+
+    static MapType = {
+        LOCAL: 'MapsLocalSource',
+        STREET: 'MapsStreetSource',
+        AERIAL: 'MapsAerialSource'
+    }
+
+    /*
+     * Due to the mathematics of spherical mericator projection,
+     * the map must be truncated at a latitude less than 90 degrees.
+     */
+    static MAX_LATITUDE = 85.05112;
+    static MIN_LATITUDE = -85.05112;
+    static MAX_LONGITUDE = 180;
+    static MIN_LONGITUDE = -180;
 
     get routingOpen() {
         return this._routingOpen || this._instructionMarkerLayer.visible;
@@ -144,8 +119,8 @@ var MapView = GObject.registerClass({
         this.notify('routeShowing');
     }
 
-    _init(params) {
-        super._init();
+    constructor(params) {
+        super();
 
         let mapType = params.mapType || this._getStoredMapType();
         delete params.mapType;
@@ -208,7 +183,7 @@ var MapView = GObject.registerClass({
 
         // if dark tiles is available, setup handler to switch style
         if (Service.getService().tiles.streetDark) {
-            Hdy.StyleManager.get_default().connect('notify::dark',
+            Handy.StyleManager.get_default().connect('notify::dark',
                                                     this._onDarkChanged.bind(this));
         }
 
@@ -229,7 +204,7 @@ var MapView = GObject.registerClass({
         if (this._mapType === MapType.STREET) {
             let overlay_sources = this.view.get_overlay_sources();
 
-            if (Hdy.StyleManager.get_default().dark)
+            if (Handy.StyleManager.get_default().dark)
                 this.view.map_source = MapSource.createStreetDarkSource();
             else
                 this.view.map_source = MapSource.createStreetSource();
@@ -369,10 +344,10 @@ var MapView = GObject.registerClass({
 
         this._mapType = mapType;
 
-        if (mapType !== MapType.LOCAL) {
+        if (mapType !== MapView.MapType.LOCAL) {
             let tiles = Service.getService().tiles;
 
-            if (mapType === MapType.AERIAL && tiles.aerial) {
+            if (mapType === MapView.MapType.AERIAL && tiles.aerial) {
                 if (tiles.hybridAerial &&
                     Application.settings.get('hybrid-aerial')) {
                     this.view.map_source = MapSource.createHybridAerialSource();
@@ -381,7 +356,7 @@ var MapView = GObject.registerClass({
                 }
             } else {
                 if (tiles.streetDark &&
-                    Hdy.StyleManager.get_default().dark) {
+                    Handy.StyleManager.get_default().dark) {
                     this.view.map_source = MapSource.createStreetDarkSource();
                 } else {
                     this.view.map_source = MapSource.createStreetSource();
@@ -391,7 +366,7 @@ var MapView = GObject.registerClass({
             Application.settings.set('map-type', mapType);
         } else {
             let renderer = new Champlain.ImageRenderer();
-            let source = new Maps.FileTileSource({
+            let source = new GnomeMaps.FileTileSource({
                 path: Utils.getBufferText(Application.application.local_tile_path),
                 renderer: renderer,
                 tile_size: Application.application.local_tile_size || 512
@@ -404,7 +379,7 @@ var MapView = GObject.registerClass({
                 let [lat, lon] = this.view.world.get_center();
                 this.view.center_on(lat, lon);
             } catch(e) {
-                this.setMapType(MapType.STREET);
+                this.setMapType(MapView.MapType.STREET);
                 Application.application.local_tile_path = false;
                 Utils.showDialog(e.message, Gtk.MessageType.ERROR, this._mainWindow);
             }
@@ -478,7 +453,7 @@ var MapView = GObject.registerClass({
     }
 
     _loadShapeLayers(files) {
-        let bbox = new BoundingBox.BoundingBox();
+        let bbox = new BoundingBox();
         this._remainingFilesToLoad = files.length;
 
         files.forEach((file) => {
@@ -515,14 +490,14 @@ var MapView = GObject.registerClass({
 
     goToGeoURI(uri) {
         try {
-            let location = new Location.Location({ heading: -1 });
+            let location = new Location({ heading: -1 });
             location.set_from_uri(uri);
 
-            let place = new Place.Place({ location: location,
-                                          name: location.description,
-                                          store: false });
-            let marker = new PlaceMarker.PlaceMarker({ place: place,
-                                                       mapView: this });
+            let place = new Place({ location: location,
+                                    name: location.description,
+                                    store: false });
+            let marker = new PlaceMarker({ place: place,
+                                           mapView: this });
             this._placeLayer.add_marker(marker);
             marker.goToAndSelect(true);
         } catch(e) {
@@ -535,8 +510,8 @@ var MapView = GObject.registerClass({
     goToHttpURL(url) {
         Place.parseHttpURL(url, (place, error) => {
             if (place) {
-                let marker = new PlaceMarker.PlaceMarker({ place: place,
-                                                           mapView: this });
+                let marker = new PlaceMarker({ place: place,
+                                               mapView: this });
 
                 this._placeLayer.add_marker(marker);
                 marker.goToAndSelect(true);
@@ -561,11 +536,11 @@ var MapView = GObject.registerClass({
         let lon = this.view.longitude > 0 ?
                   this.view.longitude - 180 : this.view.longitude + 180;
         let place =
-            new Place.Place({ location: new Location.Location({ latitude: lat,
-                                                                longitude: lon }),
-                              initialZoom: this.view.zoom_level });
+            new Place({ location: new Location({ latitude: lat,
+                                                 longitude: lon }),
+                        initialZoom: this.view.zoom_level });
 
-        new MapWalker.MapWalker(place, this).goTo(true);
+        new MapWalker(place, this).goTo(true);
     }
 
     userLocationVisible() {
@@ -586,8 +561,8 @@ var MapView = GObject.registerClass({
 
         if (!this._userLocation) {
             let place = Application.geoclue.place;
-            this._userLocation = new UserLocationMarker.UserLocationMarker({ place: place,
-                                                                             mapView: this });
+            this._userLocation = new UserLocationMarker({ place: place,
+                                                          mapView: this });
             this._userLocationLayer.remove_all();
             this._userLocation.addToLayer(this._userLocationLayer);
         }
@@ -626,17 +601,17 @@ var MapView = GObject.registerClass({
             else
                 Utils.debug('Invalid initial zoom level: ' + zoom);
 
-            if (lat >= MIN_LATITUDE && lat <= MAX_LATITUDE &&
-                lon >= MIN_LONGITUDE && lon <= MAX_LONGITUDE)
+            if (lat >= MapView.MIN_LATITUDE && lat <= MapView.MAX_LATITUDE &&
+                lon >= MapView.MIN_LONGITUDE && lon <= MapView.MAX_LONGITUDE)
                 this.view.center_on(location[0], location[1]);
             else
                 Utils.debug('Invalid initial coordinates: ' + lat + ', ' + lon);
         } else {
             /* bounding box. for backwards compatibility, not used anymore */
-            let bbox = new BoundingBox.BoundingBox({ top: location[0],
-                                                     bottom: location[1],
-                                                     left: location[2],
-                                                     right: location[3] });
+            let bbox = new BoundingBox({ top: location[0],
+                                         bottom: location[1],
+                                         left: location[2],
+                                         right: location[3] });
             this.view.connect("notify::realized", () => {
                 if (this.view.realized)
                     this.gotoBBox(bbox, true);
@@ -651,15 +626,15 @@ var MapView = GObject.registerClass({
         }
 
         let [lon, lat] = bbox.getCenter();
-        let place = new Place.Place({
-            location: new Location.Location({ latitude  : lat,
+        let place = new Place({
+            location: new Location({ latitude  : lat,
                                               longitude : lon }),
-            bounding_box: new Geocode.BoundingBox({ top    : bbox.top,
-                                                    bottom : bbox.bottom,
-                                                    left   : bbox.left,
-                                                    right  : bbox.right })
+            bounding_box: new GeocodeGlib.BoundingBox({ top    : bbox.top,
+                                                        bottom : bbox.bottom,
+                                                        left   : bbox.left,
+                                                        right  : bbox.right })
         });
-        new MapWalker.MapWalker(place, this).goTo(true, linear);
+        new MapWalker(place, this).goTo(true, linear);
     }
 
     getZoomLevelFittingBBox(bbox) {
@@ -697,8 +672,8 @@ var MapView = GObject.registerClass({
         if (turnPoint.isStop())
             return;
 
-        this._turnPointMarker = new TurnPointMarker.TurnPointMarker({ turnPoint: turnPoint,
-                                                                      mapView: this });
+        this._turnPointMarker = new TurnPointMarker({ turnPoint: turnPoint,
+                                                      mapView: this });
         this._instructionMarkerLayer.add_marker(this._turnPointMarker);
         this._turnPointMarker.goTo();
     }
@@ -707,9 +682,9 @@ var MapView = GObject.registerClass({
         if (this._turnPointMarker)
             this._turnPointMarker.destroy();
 
-        this._turnPointMarker = new TurnPointMarker.TurnPointMarker({ transitStop: transitStop,
-                                                                      transitLeg: transitLeg,
-                                                                      mapView: this });
+        this._turnPointMarker = new TurnPointMarker({ transitStop: transitStop,
+                                                      transitLeg: transitLeg,
+                                                      mapView: this });
         this._instructionMarkerLayer.add_marker(this._turnPointMarker);
         this._turnPointMarker.goTo();
     }
@@ -721,14 +696,14 @@ var MapView = GObject.registerClass({
 
         this._placeLayer.remove_all();
         places.forEach((p) => {
-            let place = new ContactPlace.ContactPlace({ place: p,
-                                                        contact: contact });
-            let marker = new PlaceMarker.PlaceMarker({ place: place,
-                                                       mapView: this });
+            let place = new ContactPlace({ place: p,
+                                           contact: contact });
+            let marker = new PlaceMarker({ place: place,
+                                           mapView: this });
             this._placeLayer.add_marker(marker);
         });
 
-        new MapWalker.MapWalker(places[0], this).goTo(true);
+        new MapWalker(places[0], this).goTo(true);
     }
 
     _showStoredRoute(stored) {
@@ -759,14 +734,14 @@ var MapView = GObject.registerClass({
     showPlace(place, animation) {
         this._placeLayer.remove_all();
 
-        if (place instanceof StoredRoute.StoredRoute) {
+        if (place instanceof StoredRoute) {
             this._showStoredRoute(place);
             return;
         }
 
         this.routingOpen = false;
-        let placeMarker = new PlaceMarker.PlaceMarker({ place: place,
-                                                        mapView: this });
+        let placeMarker = new PlaceMarker({ place: place,
+                                            mapView: this });
 
         this._placeLayer.add_marker(placeMarker);
         placeMarker.goToAndSelect(animation);
@@ -799,9 +774,9 @@ var MapView = GObject.registerClass({
         route.turnPoints.forEach((turnPoint) => {
             if (turnPoint.isStop()) {
                 let queryPoint = query.filledPoints[pointIndex];
-                let destinationMarker = new TurnPointMarker.TurnPointMarker({ turnPoint: turnPoint,
-                                                                              queryPoint: queryPoint,
-                                                                              mapView: this });
+                let destinationMarker = new TurnPointMarker({ turnPoint: turnPoint,
+                                                              queryPoint: queryPoint,
+                                                              mapView: this });
                 this._instructionMarkerLayer.add_marker(destinationMarker);
                 pointIndex++;
             }
@@ -869,12 +844,12 @@ var MapView = GObject.registerClass({
             /* add start marker */
             let start;
             if (!leg.transit) {
-                start = new TransitWalkMarker.TransitWalkMarker({ leg: leg,
-                                                                  previousLeg: previousLeg,
-                                                                  mapView: this });
+                start = new TransitWalkMarker({ leg: leg,
+                                                previousLeg: previousLeg,
+                                                mapView: this });
             } else {
-                start = new TransitBoardMarker.TransitBoardMarker({ leg: leg,
-                                                                    mapView: this });
+                start = new TransitBoardMarker({ leg: leg,
+                                                 mapView: this });
             }
 
             this._instructionMarkerLayer.add_marker(start);
@@ -882,8 +857,8 @@ var MapView = GObject.registerClass({
 
         /* add arrival marker */
         let lastLeg = itinerary.legs.last();
-        let arrival = new TransitArrivalMarker.TransitArrivalMarker({ leg: lastLeg,
-                                                                      mapView: this });
+        let arrival = new TransitArrivalMarker({ leg: lastLeg,
+                                                 mapView: this });
         this._instructionMarkerLayer.add_marker(arrival);
 
         this.routingOpen = true;
@@ -907,4 +882,32 @@ var MapView = GObject.registerClass({
     onSetMarkerSelected(selectedMarker) {
         this.emit('marker-selected', selectedMarker);
     }
-});
+}
+
+GObject.registerClass({
+    Properties: {
+        // this property is true when the routing sidebar is active
+        'routingOpen': GObject.ParamSpec.boolean('routingOpen',
+                                                  'Routing open',
+                                                  'Routing sidebar open',
+                                                  GObject.ParamFlags.READABLE |
+                                                  GObject.ParamFlags.WRITABLE,
+                                                  false),
+        /* this property is true when a route is being shown on the map */
+        'routeShowing': GObject.ParamSpec.boolean('routeShowing',
+                                                 'Route showing',
+                                                 'Showing a route on the map',
+                                                 GObject.ParamFlags.READABLE |
+                                                 GObject.ParamFlags.WRITABLE,
+                                                 false)
+    },
+    Signals: {
+        'user-location-changed': {},
+        'going-to': {},
+        'going-to-user-location': {},
+        'gone-to-user-location': {},
+        'view-moved': {},
+        'marker-selected': { param_types: [Champlain.Marker] },
+        'map-type-changed': { param_types: [GObject.TYPE_STRING] }
+    },
+}, MapView);
diff --git a/src/org.gnome.Maps.in b/src/org.gnome.Maps.in
index 1cd74738..133656e8 100755
--- a/src/org.gnome.Maps.in
+++ b/src/org.gnome.Maps.in
@@ -1,5 +1,11 @@
 #!@GJS@
-imports.package.start({ name: "gnome-maps",
-                        version: "@PACKAGE_VERSION@",
-                        prefix: "@prefix@",
-                        libdir: "@libdir@" });
+imports.package.init({ name: "gnome-maps",
+                       version: "@PACKAGE_VERSION@",
+                       prefix: "@prefix@",
+                       libdir: "@libdir@" });
+
+import(`resource:///org/gnome/Maps@suffix@/js/main.js`).catch(error => {
+    console.error(error);
+    imports.system.exit(1);
+});
+
diff --git a/src/org.gnome.Maps.src.gresource.xml.in b/src/org.gnome.Maps.src.gresource.xml.in
index 1f3b93d7..0d03fadd 100644
--- a/src/org.gnome.Maps.src.gresource.xml.in
+++ b/src/org.gnome.Maps.src.gresource.xml.in
@@ -116,5 +116,16 @@
     <file>transitplugins/opendataCH.js</file>
     <file>transitplugins/openTripPlanner.js</file>
     <file>transitplugins/resrobot.js</file>
+
+    <file alias="addressTest.js">../tests/addressTest.js</file>
+    <file alias="boundingBoxTest.js">../tests/boundingBoxTest.js</file>
+    <file alias="colorTest.js">../tests/colorTest.js</file>
+    <file alias="osmNamesTest.js">../tests/osmNamesTest.js</file>
+    <file alias="placeIconsTest.js">../tests/placeIconsTest.js</file>
+    <file alias="placeZoomTest.js">../tests/placeZoomTest.js</file>
+    <file alias="timeTest.js">../tests/timeTest.js</file>
+    <file alias="translationsTest.js">../tests/translationsTest.js</file>
+    <file alias="urisTest.js">../tests/urisTest.js</file>
+    <file alias="wikipediaTest.js">../tests/wikipediaTest.js</file>
   </gresource>
 </gresources>
diff --git a/src/osmAccountDialog.js b/src/osmAccountDialog.js
index 21c63fe3..ff31a2a3 100644
--- a/src/osmAccountDialog.js
+++ b/src/osmAccountDialog.js
@@ -20,36 +20,24 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Application = imports.application;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import * as Utils from './utils.js';
 
-var Response = {
-    SIGNED_IN: 0
-};
+export class OSMAccountDialog extends Gtk.Dialog {
 
-var OSMAccountDialog = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/osm-account-dialog.ui',
-    InternalChildren: ['stack',
-                       'signInButton',
-                       'signInSpinner',
-                       'verificationEntry',
-                       'verifyButton',
-                       'errorLabel',
-                       'signedInUserLabel',
-                       'signOutButton'],
-}, class OSMAccountDialog extends Gtk.Dialog {
+    static Response = { SIGNED_IN: 0 };
 
-    _init(params) {
+    constructor(params) {
         /* This is a construct-only property and cannot be set by GtkBuilder */
         params.use_header_bar = true;
 
         this._closeOnSignIn = params.closeOnSignIn;
         delete params.closeOnSignIn;
 
-        super._init(params);
+        super(params);
 
         this._signInButton.connect('clicked',
                                    this._onSignInButtonClicked.bind(this));
@@ -174,4 +162,16 @@ var OSMAccountDialog = GObject.registerClass({
         this._signInButton.sensitive= true;
         this._stack.visible_child_name = 'sign-in';
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/osm-account-dialog.ui',
+    InternalChildren: ['stack',
+                       'signInButton',
+                       'signInSpinner',
+                       'verificationEntry',
+                       'verifyButton',
+                       'errorLabel',
+                       'signedInUserLabel',
+                       'signOutButton'],
+}, OSMAccountDialog);
diff --git a/src/osmConnection.js b/src/osmConnection.js
index f20e8600..09768927 100644
--- a/src/osmConnection.js
+++ b/src/osmConnection.js
@@ -20,16 +20,16 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
+//const _ = imports.gettext.gettext;
 
-const Maps = imports.gi.GnomeMaps;
+import GnomeMaps from 'gi://GnomeMaps';
 
-const Gio = imports.gi.Gio;
-const Rest = imports.gi.Rest;
-const Secret = imports.gi.Secret;
-const Soup = imports.gi.Soup;
+import Gio from 'gi://Gio';
+import Rest from 'gi://Rest';
+import Secret from 'gi://Secret';
+import Soup from 'gi://Soup';
 
-const Utils = imports.utils;
+import * as Utils from './utils.js';
 
 const BASE_URL = 'https://api.openstreetmap.org/api';
 const API_VERSION = '0.6';
@@ -46,7 +46,7 @@ const SECRET_SCHEMA = new Secret.Schema("org.gnome.Maps",
     }
 );
 
-var OSMConnection = class OSMConnection {
+export class OSMConnection {
 
     constructor() {
         this._session = new Soup.Session({ user_agent : 'gnome-maps/' + pkg.version });
@@ -55,7 +55,7 @@ var OSMConnection = class OSMConnection {
         this._callProxy = Rest.OAuthProxy.new(CONSUMER_KEY, CONSUMER_SECRET,
                                               BASE_URL + '/' + API_VERSION,
                                               false);
-        Maps.osm_init();
+        GnomeMaps.osm_init();
     }
 
     getOSMObject(type, id, callback, cancellable) {
@@ -74,8 +74,8 @@ var OSMConnection = class OSMConnection {
             }
 
             try {
-                let object = Maps.osm_parse (message.response_body.data,
-                                             message.response_body.length);
+                let object = GnomeMaps.osm_parse (message.response_body.data,
+                                                  message.response_body.length);
                 callback(true, message.status_code, object, type, null);
             } catch (e) {
                 Utils.debug(e);
@@ -121,10 +121,10 @@ var OSMConnection = class OSMConnection {
 
     _doOpenChangeset(comment, callback) {
         let changeset =
-            Maps.OSMChangeset.new(comment, 'gnome-maps ' + pkg.version);
+            GnomeMaps.OSMChangeset.new(comment, 'gnome-maps ' + pkg.version);
         let xml = changeset.serialize();
 
-        let call = Maps.OSMOAuthProxyCall.new(this._callProxy, xml);
+        let call = GnomeMaps.OSMOAuthProxyCall.new(this._callProxy, xml);
         call.set_method('PUT');
         call.set_function('/changeset/create');
 
@@ -146,7 +146,7 @@ var OSMConnection = class OSMConnection {
         object.changeset = changeset;
 
         let xml = object.serialize();
-        let call = Maps.OSMOAuthProxyCall.new(this._callProxy, xml);
+        let call = GnomeMaps.OSMOAuthProxyCall.new(this._callProxy, xml);
 
         call.set_method('PUT');
         call.set_function(this._getCreateOrUpdateFunction(object, type));
@@ -168,7 +168,7 @@ var OSMConnection = class OSMConnection {
         object.changeset = changeset;
 
         let xml = object.serialize();
-        let call = Maps.OSMOAuthProxyCall.new(this._callProxy, xml);
+        let call = GnomeMaps.OSMOAuthProxyCall.new(this._callProxy, xml);
 
         call.set_method('DELETE');
         call.set_function(this._getDeleteFunction(object, type));
@@ -274,7 +274,7 @@ var OSMConnection = class OSMConnection {
         switch (call.get_status_code()) {
             case Soup.Status.OK:
                 try {
-                    callback(Maps.osm_parse_user_details(call.get_payload()));
+                    callback(GnomeMaps.osm_parse_user_details(call.get_payload()));
                 } catch (e) {
                     Utils.debug('Error parsing user details: ' + e.message);
                     callback(null);
@@ -339,32 +339,32 @@ var OSMConnection = class OSMConnection {
     _onPasswordCleared(source, result) {
         Secret.password_clear_finish(result);
     }
-};
 
-/*
- * Gets a status message (usually for an error case)
- * to show for a given OSM server response.
- */
-function getStatusMessage(statusCode) {
-    switch (statusCode) {
-    case Soup.Status.IO_ERROR:
-    case Soup.Status.UNAUTHORIZED:
-        /* setting the status in session.cancel_message still seems
-           to always give status IO_ERROR */
-        return _("Incorrect user name or password");
-    case Soup.Status.OK:
-        return _("Success");
-    case Soup.Status.BAD_REQUEST:
-        return _("Bad request");
-    case Soup.Status.NOT_FOUND:
-        return _("Object not found");
-    case Soup.Status.CONFLICT:
-        return _("Conflict, someone else has just modified the object");
-    case Soup.Status.GONE:
-        return _("Object has been deleted");
-    case Soup.Status.PRECONDITION_FAILED:
-        return _("Way or relation refers to non-existing children");
-    default:
-        return null;
+    /*
+     * Gets a status message (usually for an error case)
+     * to show for a given OSM server response.
+     */
+    static getStatusMessage(statusCode) {
+        switch (statusCode) {
+        case Soup.Status.IO_ERROR:
+        case Soup.Status.UNAUTHORIZED:
+            /* setting the status in session.cancel_message still seems
+               to always give status IO_ERROR */
+            return _("Incorrect user name or password");
+        case Soup.Status.OK:
+            return _("Success");
+        case Soup.Status.BAD_REQUEST:
+            return _("Bad request");
+        case Soup.Status.NOT_FOUND:
+            return _("Object not found");
+        case Soup.Status.CONFLICT:
+            return _("Conflict, someone else has just modified the object");
+        case Soup.Status.GONE:
+            return _("Object has been deleted");
+        case Soup.Status.PRECONDITION_FAILED:
+            return _("Way or relation refers to non-existing children");
+        default:
+            return null;
+        }
     }
 }
diff --git a/src/osmEdit.js b/src/osmEdit.js
index bd3d6256..32ff2e81 100644
--- a/src/osmEdit.js
+++ b/src/osmEdit.js
@@ -20,16 +20,16 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Application = imports.application;
-const OSMAccountDialog = imports.osmAccountDialog;
-const OSMEditDialog = imports.osmEditDialog;
-const OSMConnection = imports.osmConnection;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import {OSMAccountDialog} from './osmAccountDialog.js';
+import {OSMEditDialog} from './osmEditDialog.js';
+import {OSMConnection} from './osmConnection.js';
+import * as Utils from './utils.js';
 
-/* minimum zoom level at which to offer adding a location */
-var MIN_ADD_LOCATION_ZOOM_LEVEL = 16;
+export class OSMEdit {
 
-var OSMEdit = class OSMEdit {
+    // minimum zoom level at which to offer adding a location
+    static get MIN_ADD_LOCATION_ZOOM_LEVEL() { return 16};
 
     constructor() {
         this._osmConnection = new OSMConnection.OSMConnection();
@@ -191,4 +191,4 @@ var OSMEdit = class OSMEdit {
     get username() {
         return this._username;
     }
-};
+}
diff --git a/src/osmEditDialog.js b/src/osmEditDialog.js
index 7b28d051..2ee25481 100644
--- a/src/osmEditDialog.js
+++ b/src/osmEditDialog.js
@@ -20,30 +20,25 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
-
-const Geocode = imports.gi.GeocodeGlib;
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-const Soup = imports.gi.Soup;
-
-const Application = imports.application;
-const Maps = imports.gi.GnomeMaps;
-const OSMConnection = imports.osmConnection;
-const OSMTypes = imports.osmTypes;
-const OSMTypeSearchEntry = imports.osmTypeSearchEntry;
-const OSMUtils = imports.osmUtils;
-const Utils = imports.utils;
-const Wikipedia = imports.wikipedia;
-
-var Response = {
-    UPLOADED: 0,
-    DELETED: 1,
-    CANCELLED: 2,
-    ERROR: 3
-};
+import gettext from 'gettext';
+
+const _ = gettext.gettext;
+
+import GeocodeGlib from 'gi://GeocodeGlib';
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import Soup from 'gi://Soup';
+
+import {Application} from './application.js';
+import GnomeMaps from 'gi://GnomeMaps';
+import {OSMConnection} from './osmConnection.js';
+import * as OSMTypes from './osmTypes.js';
+import {OSMTypeSearchEntry} from './osmTypeSearchEntry.js';
+import * as OSMUtils from './osmUtils.js';
+import * as Utils from './utils.js';
+import * as Wikipedia from './wikipedia.js';
 
 /*
  * enumeration representing
@@ -146,7 +141,7 @@ const OSM_FIELDS = [
         name: _("Phone"),
         tag: 'phone',
         type: EditFieldType.TEXT,
-        rewriteFunc: this._osmPhoneRewriteFunc,
+        rewriteFunc: _osmPhoneRewriteFunc,
         hint: _("Phone number. Use the international format, " +
                 "starting with a + sign. Beware of local privacy " +
                 "laws, especially for private phone numbers.")
@@ -156,7 +151,7 @@ const OSM_FIELDS = [
         tag: 'email',
         type: EditFieldType.TEXT,
         validate: Utils.isValidEmail,
-        rewriteFunc: this._osmEmailRewriteFunc,
+        rewriteFunc: _osmEmailRewriteFunc,
         validateError: _("This is not a valid e-mail address. Make sure to not include the mailto: protocol 
prefix."),
         hint: _("Contact e-mail address for inquiries. " +
                 "Add only email addresses that are intended to be publicly used.")
@@ -166,7 +161,7 @@ const OSM_FIELDS = [
         tag: 'wikipedia',
         type: EditFieldType.TEXT,
         validate: Wikipedia.isValidWikipedia,
-        rewriteFunc: this._osmWikipediaRewriteFunc,
+        rewriteFunc: _osmWikipediaRewriteFunc,
         hint: _("The format used should include the language code " +
                 "and the article title like “en:Article title”.")
     },
@@ -258,15 +253,9 @@ const OSM_FIELDS = [
         hint: _("Information used to inform other mappers about non-obvious information about an element, 
the author’s intent when creating it, or hints for further improvement.")
     }];
 
-const OSMEditAddress = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/osm-edit-address.ui',
-    Children: [ 'street',
-                'number',
-                'post',
-                'city' ],
-}, class OSMEditAddress extends Gtk.Grid {
+export class OSMEditAddress extends Gtk.Grid {
 
-    _init(params) {
+    constructor(params) {
         let street = params.street;
         delete params.street;
 
@@ -279,7 +268,7 @@ const OSMEditAddress = GObject.registerClass({
         let city = params.city;
         delete params.city;
 
-        super._init(params);
+        super(params);
 
         if (street)
             this.street.text = street;
@@ -293,31 +282,26 @@ const OSMEditAddress = GObject.registerClass({
         if (city)
             this.city.text = city;
     }
-});
+}
 
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/osm-edit-address.ui',
+    Children: [ 'street',
+                'number',
+                'post',
+                'city' ],
+}, OSMEditAddress);
 
-var OSMEditDialog = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/osm-edit-dialog.ui',
-    InternalChildren: [ 'cancelButton',
-                        'backButton',
-                        'nextButton',
-                        'stack',
-                        'editorGrid',
-                        'commentTextView',
-                        'addFieldPopoverGrid',
-                        'addFieldButton',
-                        'typeSearchGrid',
-                        'typeLabel',
-                        'typeButton',
-                        'typeValueLabel',
-                        'recentTypesLabel',
-                        'recentTypesListBox',
-                        'hintPopover',
-                        'hintLabel',
-                        'headerBar'],
-}, class OSMEditDialog extends Gtk.Dialog {
+export class OSMEditDialog extends Gtk.Dialog {
 
-    _init(params) {
+    static Response = {
+        UPLOADED: 0,
+        DELETED: 1,
+        CANCELLED: 2,
+        ERROR: 3
+    };
+
+    constructor(params) {
         this._place = params.place;
         delete params.place;
 
@@ -333,7 +317,7 @@ var OSMEditDialog = GObject.registerClass({
         /* This is a construct-only property and cannot be set by GtkBuilder */
         params.use_header_bar = true;
 
-        super._init(params);
+        super(params);
 
         /* I could not get this widget working from within the widget template
          * this results in a segfault. The widget definition is left in-place,
@@ -366,13 +350,13 @@ var OSMEditDialog = GObject.registerClass({
 
             /* the OSMObject ID, version, and changeset ID is unknown for now */
             let newNode =
-                Maps.OSMNode.new(0, 0, 0, this._longitude, this._latitude);
+                GnomeMaps.OSMNode.new(0, 0, 0, this._longitude, this._latitude);
             /* set a placeholder name tag to always get a name entry for new
              * locations */
             newNode.set_tag('name', '');
             this._loadOSMData(newNode);
             this._isEditing = true;
-            this._osmType = Geocode.PlaceOsmType.NODE;
+            this._osmType = GeocodeGlib.PlaceOsmType.NODE;
         } else {
             this._osmType = this._place.osmType;
             Application.osmEdit.fetchObject(this._place,
@@ -904,4 +888,25 @@ var OSMEditDialog = GObject.registerClass({
         this._updateTypeButton();
         this._stack.visible_child_name = 'editor';
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/osm-edit-dialog.ui',
+    InternalChildren: [ 'cancelButton',
+                        'backButton',
+                        'nextButton',
+                        'stack',
+                        'editorGrid',
+                        'commentTextView',
+                        'addFieldPopoverGrid',
+                        'addFieldButton',
+                        'typeSearchGrid',
+                        'typeLabel',
+                        'typeButton',
+                        'typeValueLabel',
+                        'recentTypesLabel',
+                        'recentTypesListBox',
+                        'hintPopover',
+                        'hintLabel',
+                        'headerBar'],
+}, OSMEditDialog);
diff --git a/src/osmTypeListRow.js b/src/osmTypeListRow.js
index 795d203c..84bb0c48 100644
--- a/src/osmTypeListRow.js
+++ b/src/osmTypeListRow.js
@@ -19,19 +19,16 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-var OSMTypeListRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/osm-type-list-row.ui',
-    InternalChildren: [ 'name' ]
-}, class OSMTypeListRow extends Gtk.ListBoxRow {
+export class OSMTypeListRow extends Gtk.ListBoxRow {
 
-    _init(props) {
+    constructor(props) {
         this._type = props.type;
         delete props.type;
 
-        super._init(props);
+        super(props);
 
         this._name.label = this._type.title;
     }
@@ -47,4 +44,9 @@ var OSMTypeListRow = GObject.registerClass({
     get title() {
         return this._type.title;
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/osm-type-list-row.ui',
+    InternalChildren: [ 'name' ]
+}, OSMTypeListRow);
diff --git a/src/osmTypePopover.js b/src/osmTypePopover.js
index 664ae721..8d1ce588 100644
--- a/src/osmTypePopover.js
+++ b/src/osmTypePopover.js
@@ -19,26 +19,16 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const OSMTypeListRow = imports.osmTypeListRow;
-const SearchPopover = imports.searchPopover;
+import {OSMTypeListRow} from './osmTypeListRow.js';
+import {SearchPopover} from './searchPopover.js';
 
-var OSMTypePopover = GObject.registerClass({
-    InternalChildren: ['list'],
-    Template: 'resource:///org/gnome/Maps/ui/osm-type-popover.ui',
-    Signals : {
-        /* signal emitted when selecting a type, indicates OSM key and value
-         * and display title */
-        'selected' : { param_types: [ GObject.TYPE_STRING,
-                                      GObject.TYPE_STRING,
-                                      GObject.TYPE_STRING ] }
-    }
-}, class OSMTypePopover extends SearchPopover.SearchPopover {
+export class OSMTypePopover extends SearchPopover {
 
-    _init(props) {
-        super._init(props);
+    constructor(props) {
+        super(props);
 
         this._list.connect('row-activated', (list, row) => {
             if (row)
@@ -58,4 +48,16 @@ var OSMTypePopover = GObject.registerClass({
                                                       can_focus: true });
         this._list.insert(row, -1);
     }
-});
+}
+
+GObject.registerClass({
+    InternalChildren: ['list'],
+    Template: 'resource:///org/gnome/Maps/ui/osm-type-popover.ui',
+    Signals : {
+        /* signal emitted when selecting a type, indicates OSM key and value
+         * and display title */
+        'selected' : { param_types: [ GObject.TYPE_STRING,
+                                      GObject.TYPE_STRING,
+                                      GObject.TYPE_STRING ] }
+    }
+}, OSMTypePopover);
diff --git a/src/osmTypeSearchEntry.js b/src/osmTypeSearchEntry.js
index eae92355..e48e954d 100644
--- a/src/osmTypeSearchEntry.js
+++ b/src/osmTypeSearchEntry.js
@@ -19,21 +19,19 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const OSMTypePopover = imports.osmTypePopover;
-const OSMTypes = imports.osmTypes;
-const Utils = imports.utils;
+import {OSMTypePopover} from './osmTypePopover.js';
+import * as OSMTypes from './osmTypes.js';
+import * as Utils from './utils.js';
 
 const MAX_MATCHES = 10;
 
-var OSMTypeSearchEntry = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/osm-type-search-entry.ui'
-}, class OSMTypeSearchEntry extends Gtk.SearchEntry {
+export class OSMTypeSearchEntry extends Gtk.SearchEntry {
 
-    _init(props) {
-        super._init(props);
+    constructor(props) {
+        super(props);
 
         this._popover =
             new OSMTypePopover.OSMTypePopover({relative_to: this});
@@ -72,4 +70,8 @@ var OSMTypeSearchEntry = GObject.registerClass({
             }
         }
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/osm-type-search-entry.ui'
+}, OSMTypeSearchEntry);
diff --git a/src/osmUtils.js b/src/osmUtils.js
index 866d063f..66ea6184 100644
--- a/src/osmUtils.js
+++ b/src/osmUtils.js
@@ -20,9 +20,9 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const Soup = imports.gi.Soup;
+import Soup from 'gi://Soup';
 
-const Application = imports.application;
+import {Application} from './application.js';
 
 /*
  * Gets a Wikipedia article in OSM tag format (i.e. lang:Article title)
diff --git a/src/overpass.js b/src/overpass.js
index 2265f24c..eb561c1f 100644
--- a/src/overpass.js
+++ b/src/overpass.js
@@ -18,14 +18,15 @@
  */
 
 const Format = imports.format;
-const Geocode = imports.gi.GeocodeGlib;
-const GObject = imports.gi.GObject;
-const Soup = imports.gi.Soup;
 
-const OSMNames = imports.osmNames;
-const PhotonParser = imports.photonParser;
-const Place = imports.place;
-const Utils = imports.utils;
+import Geocode from 'gi://GeocodeGlib';
+import GObject from 'gi://GObject';
+import Soup from 'gi://Soup';
+
+import * as OSMNames from './osmNames.js';
+import * as PhotonParser from './photonParser.js';
+import {Place} from './place.js';
+import * as Utils from './utils.js';
 
 const _DEFAULT_TIMEOUT = 180;
 const _DEFAULT_MAXSIZE = 536870912;
@@ -36,21 +37,12 @@ const _DEFAULT_OUTPUT_SORT_ORDER = 'qt';
 
 const BASE_URL = 'https://overpass-api.de/api/interpreter';
 
-var Overpass = GObject.registerClass({
-    Properties: {
-        'place': GObject.ParamSpec.object('place',
-                                          'Place',
-                                          'Place with added information',
-                                          GObject.ParamFlags.READABLE |
-                                          GObject.ParamFlags.WRITABLE,
-                                          Geocode.Place)
-    }
-}, class Overpass extends GObject.Object {
+export class Overpass extends GObject.Object {
 
-    _init(params) {
+    constructor(params) {
         params = params || { };
 
-        super._init();
+        super();
 
         // maximum allowed runtime for the query in seconds
         this.timeout = params.timeout || _DEFAULT_TIMEOUT;
@@ -249,4 +241,16 @@ var Overpass = GObject.registerClass({
                                                        this.outputSortOrder,
                                                        this.outputCount ]);
     }
-});
+}
+
+GObject.registerClass({
+    Properties: {
+        'place': GObject.ParamSpec.object('place',
+                                          'Place',
+                                          'Place with added information',
+                                          GObject.ParamFlags.READABLE |
+                                          GObject.ParamFlags.WRITABLE,
+                                          Geocode.Place)
+    }},
+    Overpass
+);
diff --git a/src/photonGeocode.js b/src/photonGeocode.js
index 38d88ca2..159db1f1 100644
--- a/src/photonGeocode.js
+++ b/src/photonGeocode.js
@@ -21,19 +21,19 @@
 
 const Format = imports.format;
 
-const GLib = imports.gi.GLib;
-const Soup = imports.gi.Soup;
+import GLib from 'gi://GLib';
+import Soup from 'gi://Soup';
 
-const Application = imports.application;
-const HTTP = imports.http;
-const PhotonParser = imports.photonParser;
-const Service = imports.service;
-const Utils = imports.utils;
+import {Application} from './application.js';
+import * as HTTP from './http.js';
+import * as PhotonParser from './photonParser.js';
+import * as Service from './service.js';
+import * as Utils from './utils.js';
 
 // HTTP session timeout (in seconds)
 const TIMEOUT = 5;
 
-var PhotonGeocode = class {
+export class PhotonGeocode {
     constructor() {
         this._session =
             new Soup.Session({ user_agent : 'gnome-maps/' + pkg.version,
diff --git a/src/photonParser.js b/src/photonParser.js
index 041b7734..f5c3634e 100644
--- a/src/photonParser.js
+++ b/src/photonParser.js
@@ -19,14 +19,14 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const _ = imports.gettext.gettext;
+//const _ = imports.gettext.gettext;
 
-const Geocode = imports.gi.GeocodeGlib;
+import Geocode from 'gi://GeocodeGlib';
 
-const Address = imports.address;
-const OSMTypes = imports.osmTypes;
-const Place = imports.place;
-const Utils = imports.utils;
+import * as Address from './address.js';
+import * as OSMTypes from './osmTypes.js';
+import {Place} from './place.js';
+import * as Utils from './utils.js';
 
 function parsePlace(latitude, longitude, properties) {
     let location = new Geocode.Location({ latitude:  latitude,
diff --git a/src/place.js b/src/place.js
index b772a46c..62f8050c 100644
--- a/src/place.js
+++ b/src/place.js
@@ -19,18 +19,18 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const _ = imports.gettext.gettext;
+//const _ = imports.gettext.gettext;
 
-const Geocode = imports.gi.GeocodeGlib;
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
+import Geocode from 'gi://GeocodeGlib';
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
 
-const Location = imports.location;
-const Overpass = imports.overpass;
-const PlaceIcons = imports.placeIcons;
-const URIS = imports.uris;
-const Utils = imports.utils;
+import {Location} from './location.js';
+import {Overpass} from './overpass.js';
+import * as PlaceIcons from './placeIcons.js';
+import * as URIS from './uris.js';
+import * as Utils from './utils.js';
 
 // Matches coordinates string in 'Decimal Degrees' format
 const DECIMAL_COORDINATES_REGEX = (
@@ -44,10 +44,9 @@ const DMS_COORDINATES_REGEX = new RegExp(
     "i"
 );
 
-var Place = GObject.registerClass(
-class Place extends Geocode.Place {
+export class Place extends Geocode.Place {
 
-    _init(params) {
+    constructor(params) {
         this.updateFromTags(params);
 
         delete params.population;
@@ -117,7 +116,7 @@ class Place extends Geocode.Place {
             if (!params[prop])
                 delete params[prop];
 
-        super._init(params);
+        super(params);
     }
 
     /**
@@ -409,7 +408,9 @@ class Place extends Geocode.Place {
             return false;
         }
     }
-});
+}
+
+GObject.registerClass(Place);
 
 Place.fromJSON = function(obj) {
     let props = { };
@@ -500,7 +501,7 @@ let overpass = null;
 /* we can't import Application before the Place class has been defined
  * since it's used via PlaceStore
  */
-const Application = imports.application;
+import {Application} from './application.js';
 
 function parseHttpURL(text, callback) {
     let [type, id] = URIS.parseAsObjectURL(text);
diff --git a/src/placeFormatter.js b/src/placeFormatter.js
index 58dff6d1..8100772f 100644
--- a/src/placeFormatter.js
+++ b/src/placeFormatter.js
@@ -19,11 +19,11 @@
  * Author: Damián Nohales <damiannohales gmail com>
  */
 
-const Geocode = imports.gi.GeocodeGlib;
+import GeocodeGlib from 'gi://GeocodeGlib';
 
-const StoredRoute = imports.storedRoute;
+import {StoredRoute} from './storedRoute.js';
 
-var PlaceFormatter = class PlaceFormatter {
+export class PlaceFormatter {
 
     constructor(place) {
         this._place = place;
@@ -67,24 +67,24 @@ var PlaceFormatter = class PlaceFormatter {
 
     _update() {
         switch (this._place.place_type) {
-        case Geocode.PlaceType.COUNTRY:
+        case GeocodeGlib.PlaceType.COUNTRY:
             if (this._place.country)
                 this._titleProperty = 'country';
 
             this._addRow(['country_code']);
             break;
 
-        case Geocode.PlaceType.STATE:
+        case GeocodeGlib.PlaceType.STATE:
             if (this._place.state)
                 this._titleProperty = 'state';
             break;
 
-        case Geocode.PlaceType.COUNTY:
+        case GeocodeGlib.PlaceType.COUNTY:
             if (this._place.county)
                 this._titleProperty = 'county';
             break;
 
-        case Geocode.PlaceType.TOWN:
+        case GeocodeGlib.PlaceType.TOWN:
             if (this._place.county)
                 this._addRow(['county']);
             else if (this._place.state)
diff --git a/src/placeListRow.js b/src/placeListRow.js
index abb40b7d..e7260e12 100644
--- a/src/placeListRow.js
+++ b/src/placeListRow.js
@@ -17,28 +17,20 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const ContactPlace = imports.contactPlace;
-const PlaceFormatter = imports.placeFormatter;
-const PlaceStore = imports.placeStore;
-const Utils = imports.utils;
+import {ContactPlace} from './contactPlace.js';
+import {PlaceFormatter} from './placeFormatter.js';
+import {PlaceStore} from './placeStore.js';
+import * as Utils from './utils.js';
 
 var ROW_HEIGHT = 55;
 
-var PlaceListRow = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/place-list-row.ui',
-    InternalChildren: [ 'icon',
-                        'iconStack',
-                        'contactAvatar',
-                        'name',
-                        'details',
-                        'typeIcon' ],
-}, class PlaceListRow extends Gtk.ListBoxRow {
+export class PlaceListRow extends Gtk.ListBoxRow {
 
-    _init(params) {
+    constructor(params) {
         let place = params.place;
         delete params.place;
 
@@ -49,7 +41,7 @@ var PlaceListRow = GObject.registerClass({
         delete params.type;
 
         params.height_request = ROW_HEIGHT;
-        super._init(params);
+        super(params);
         this.update(place, type, searchString);
     }
 
@@ -102,4 +94,14 @@ var PlaceListRow = GObject.registerClass({
         }
         return title;
     }
-});
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/place-list-row.ui',
+    InternalChildren: [ 'icon',
+                        'iconStack',
+                        'contactAvatar',
+                        'name',
+                        'details',
+                        'typeIcon' ],
+}, PlaceListRow);
diff --git a/src/placeStore.js b/src/placeStore.js
index 8dd8ed4a..f7589e31 100644
--- a/src/placeStore.js
+++ b/src/placeStore.js
@@ -17,43 +17,42 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const GdkPixbuf = imports.gi.GdkPixbuf;
-const Geocode = imports.gi.GeocodeGlib;
-const Gtk = imports.gi.Gtk;
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import GdkPixbuf from 'gi://GdkPixbuf';
+import GeocodeGlib from 'gi://GeocodeGlib';
+import Gtk from 'gi://Gtk';
 
-const ContactPlace = imports.contactPlace;
-const Place = imports.place;
-const StoredRoute = imports.storedRoute;
-const Utils = imports.utils;
+import {ContactPlace} from './contactPlace.js';
+import {Place} from './place.js';
+import {StoredRoute} from './storedRoute.js';
+import * as Utils from './utils.js';
 
 const _PLACES_STORE_FILE = 'maps-places.json';
 const _ICON_SIZE = 20;
 const _ONE_DAY = 1000 * 60 * 60 * 24; // one day in ms
 const _STALE_THRESHOLD = 7; // mark the osm information as stale after a week
 
-var PlaceType = {
-    ANY: -1,
-    RECENT: 0,
-    FAVORITE: 1,
-    CONTACT: 2,
-    RECENT_ROUTE: 3
-};
-
-var Columns = {
-    PLACE_ICON: 0,
-    PLACE: 1,
-    NAME: 2,
-    TYPE: 3,
-    ADDED: 4,
-    LANGUAGE: 5
-};
-
-var PlaceStore = GObject.registerClass(
-class PlaceStore extends Gtk.ListStore {
-
-    _init(params) {
+export class PlaceStore extends Gtk.ListStore {
+
+    static PlaceType = {
+        ANY: -1,
+        RECENT: 0,
+        FAVORITE: 1,
+        CONTACT: 2,
+        RECENT_ROUTE: 3
+    }
+
+    static Columns = {
+        PLACE_ICON: 0,
+        PLACE: 1,
+        NAME: 2,
+        TYPE: 3,
+        ADDED: 4,
+        LANGUAGE: 5
+    }
+
+    constructor(params) {
         this._recentPlacesLimit = params.recentPlacesLimit;
         delete params.recentPlacesLimit;
 
@@ -67,7 +66,7 @@ class PlaceStore extends Gtk.ListStore {
         this._typeTable = {};
         this._language = Utils.getLanguage();
 
-        super._init(params);
+        super(params);
         this.set_column_types([GdkPixbuf.Pixbuf,
                                GObject.TYPE_OBJECT,
                                GObject.TYPE_STRING,
@@ -356,4 +355,6 @@ class PlaceStore extends Gtk.ListStore {
             }
         });
     }
-});
+}
+
+GObject.registerClass(PlaceStore);
diff --git a/src/route.js b/src/route.js
index 0ef127fc..a1e37a8d 100644
--- a/src/route.js
+++ b/src/route.js
@@ -19,10 +19,10 @@
  * Author: Mattias Bengtsson <mattias jc bengtsson gmail com>
  */
 
-const GObject = imports.gi.GObject;
+import GObject from 'gi://GObject';
 
-const BoundingBox = imports.boundingBox;
-const Utils = imports.utils;
+import {BoundingBox} from './boundingBox.js';
+import * as Utils from './utils.js';
 
 var TurnPointType = {
     START:            0,
@@ -58,16 +58,10 @@ const LHT_COUNTRIES = new Set(['AG', 'AI', 'AU', 'BB', 'BD', 'BM', 'BN', 'BS',
                                'TO', 'TT', 'TV', 'TZ', 'UG', 'VC', 'VG', 'VI',
                                'WS', 'ZA', 'ZM', 'ZW']);
 
-var Route = GObject.registerClass({
-    Signals: {
-        'update': {},
-        'reset': {},
-        'error': { param_types: [GObject.TYPE_STRING] }
-    }
-}, class Route extends GObject.Object {
+export class Route extends GObject.Object {
 
-    _init() {
-        super._init();
+    constructor() {
+        super();
         this.reset();
     }
 
@@ -101,9 +95,17 @@ var Route = GObject.registerClass({
         }, this);
         return bbox;
     }
-});
+}
+
+GObject.registerClass({
+    Signals: {
+        'update': {},
+        'reset': {},
+        'error': { param_types: [GObject.TYPE_STRING] }
+    }
+}, Route);
 
-var TurnPoint = class TurnPoint {
+export class TurnPoint {
 
     constructor({ coordinate, type, distance, instruction, turnAngle }) {
         this.coordinate = coordinate;
@@ -181,4 +183,4 @@ var TurnPoint = class TurnPoint {
 
         return LHT_COUNTRIES.has(country);
     }
-};
+}
diff --git a/src/routeQuery.js b/src/routeQuery.js
index 3b424ec3..57ed0fbc 100644
--- a/src/routeQuery.js
+++ b/src/routeQuery.js
@@ -19,46 +19,18 @@
  * Author: Mattias Bengtsson <mattias jc bengtsson gmail com>
  */
 
-const GObject = imports.gi.GObject;
-const Geocode = imports.gi.GeocodeGlib;
-
-const Application = imports.application;
-const PlaceStore = imports.placeStore;
-const TransitOptions = imports.transitOptions;
-
-var MAX_QUERY_POINTS = 10;
-
-var Transportation = {
-    CAR:        0,
-    BIKE:       1,
-    PEDESTRIAN: 2,
-    TRANSIT:    3,
-
-    toString: function (transportation) {
-        switch(transportation) {
-        case Transportation.CAR:        return 'car';
-        case Transportation.BIKE:       return 'bike';
-        case Transportation.PEDESTRIAN: return 'foot';
-        case Transportation.TRANSIT:    return 'transit';
-        default:                        return null;
-        }
-    }
-};
+import GObject from 'gi://GObject';
+import GeocodeGlib from 'gi://GeocodeGlib';
 
-var QueryPoint = GObject.registerClass({
-    Properties: {
-        'place': GObject.ParamSpec.object('place',
-                                          '',
-                                          '',
-                                          GObject.ParamFlags.READABLE |
-                                          GObject.ParamFlags.WRITABLE,
-                                          Geocode.Place)
-    }
-}, class QueryPoint extends GObject.Object {
+import {Application} from './application.js';
+import {PlaceStore} from './placeStore.js';
+import {TransitOptions} from './transitOptions.js';
+
+export class QueryPoint extends GObject.Object {
 
-    _init() {
+    constructor() {
         this._place = null;
-        super._init();
+        super();
     }
 
     set place(p) {
@@ -69,33 +41,39 @@ var QueryPoint = GObject.registerClass({
     get place() {
         return this._place;
     }
-});
+}
 
-var RouteQuery = GObject.registerClass({
-    Signals: {
-        'reset': { },
-        'point-added': { param_types: [GObject.TYPE_OBJECT, GObject.TYPE_INT] },
-        'point-removed': { param_types: [GObject.TYPE_OBJECT, GObject.TYPE_INT] },
-        'run': { }
-    },
+GObject.registerClass({
     Properties: {
-        'points': GObject.ParamSpec.object('points',
-                                           '',
-                                           '',
-                                           GObject.ParamFlags.READABLE |
-                                           GObject.ParamFlags.WRITABLE,
-                                           GObject.Object),
-        'transportation': GObject.ParamSpec.int('transportation',
-                                                '',
-                                                '',
-                                                GObject.ParamFlags.READABLE |
-                                                GObject.ParamFlags.WRITABLE,
-                                                Transportation.CAR,
-                                                Transportation.PEDESTRIAN,
-                                                Transportation.CAR,
-                                                Transportation.TRANSIT)
+        'place': GObject.ParamSpec.object('place',
+                                          '',
+                                          '',
+                                          GObject.ParamFlags.READABLE |
+                                          GObject.ParamFlags.WRITABLE,
+                                          GeocodeGlib.Place)
+    }
+}, QueryPoint);
+
+export class RouteQuery extends GObject.Object {
+
+    static MAX_QUERY_POINTS = 10;
+
+    static Transportation = {
+        CAR:        0,
+        BIKE:       1,
+        PEDESTRIAN: 2,
+        TRANSIT:    3,
+
+        toString: function (transportation) {
+            switch(transportation) {
+            case Transportation.CAR:        return 'car';
+            case Transportation.BIKE:       return 'bike';
+            case Transportation.PEDESTRIAN: return 'foot';
+            case Transportation.TRANSIT:    return 'transit';
+            default:                        return null;
+            }
+        }
     }
-}, class RouteQuery extends GObject.Object {
 
     get points() {
         return this._points;
@@ -163,13 +141,13 @@ var RouteQuery = GObject.registerClass({
         this.notify('points');
     }
 
-    _init(args) {
-        super._init(args);
+    constructor(args) {
+        super(args);
         this._points = [];
         this._time = null;
         this._date = null;
         this._arriveBy = false;
-        this._transitOptions = new TransitOptions.TransitOptions();
+        this._transitOptions = new TransitOptions();
         this._initTransportation();
         this.reset();
     }
@@ -251,4 +229,30 @@ var RouteQuery = GObject.registerClass({
         return "\nPoints: " + this.points +
                "\nTransportation: " + this.transportation;
     }
-});
+}
+
+GObject.registerClass({
+    Signals: {
+        'reset': { },
+        'point-added': { param_types: [GObject.TYPE_OBJECT, GObject.TYPE_INT] },
+        'point-removed': { param_types: [GObject.TYPE_OBJECT, GObject.TYPE_INT] },
+        'run': { }
+    },
+    Properties: {
+        'points': GObject.ParamSpec.object('points',
+                                           '',
+                                           '',
+                                           GObject.ParamFlags.READABLE |
+                                           GObject.ParamFlags.WRITABLE,
+                                           GObject.Object),
+        'transportation': GObject.ParamSpec.int('transportation',
+                                                '',
+                                                '',
+                                                GObject.ParamFlags.READABLE |
+                                                GObject.ParamFlags.WRITABLE,
+                                                RouteQuery.Transportation.CAR,
+                                                RouteQuery.Transportation.PEDESTRIAN,
+                                                RouteQuery.Transportation.CAR,
+                                                RouteQuery.Transportation.TRANSIT)
+    }
+}, RouteQuery);
diff --git a/src/searchPopover.js b/src/searchPopover.js
index 64c9f229..cb184b21 100644
--- a/src/searchPopover.js
+++ b/src/searchPopover.js
@@ -20,18 +20,16 @@
  *         Jonas Danielsson <jonas threetimestwo org>
  */
 
-const Gdk = imports.gi.Gdk;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Gdk from 'gi://Gdk';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
 /* Abstract search result popover that progagates keypress events from a
    focus-taking internal widget to the spawning search entry widget */
-var SearchPopover = GObject.registerClass({
-    Abstract: true
-}, class SearchPopover extends Gtk.Popover {
+export class SearchPopover extends Gtk.Popover {
 
-    _init(props) {
-        super._init(props);
+    constructor(props) {
+        super(props);
 
         this._entry = this.relative_to;
 
@@ -110,5 +108,9 @@ var SearchPopover = GObject.registerClass({
             adjustment.clamp_page(allocation.y, allocation.y + allocation.height);
         }
     }
-});
+}
+
+GObject.registerClass({
+    Abstract: true
+}, SearchPopover);
 
diff --git a/src/storedRoute.js b/src/storedRoute.js
index 04763097..ea96f17f 100644
--- a/src/storedRoute.js
+++ b/src/storedRoute.js
@@ -20,20 +20,19 @@
  * Author: Jonas Danielsson <jonas threetimestwo org>
  */
 
-const Champlain = imports.gi.Champlain;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import Champlain from 'gi://Champlain';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const Place = imports.place;
-const Route = imports.route;
-const RouteQuery = imports.routeQuery;
+import {Place} from './place.js';
+import {Route, TurnPoint} from './route.js';
+import {RouteQuery} from './routeQuery.js';
 
 // directional override markers
 const _RLM = '\u200F';
 const _LRM = '\u200E';
 
-var StoredRoute = GObject.registerClass(
-class StoredRoute extends Place.Place {
+export class StoredRoute extends Place {
 
     _init(params) {
         let route = params.route;
@@ -42,7 +41,7 @@ class StoredRoute extends Place.Place {
         this._transportation = params.transportation;
         delete params.transportation;
 
-        this.route = new Route.Route();
+        this.route = new Route();
         this.route.update({ path: route.path,
                             turnPoints: route.turnPoints,
                             distance: route.distance,
@@ -154,53 +153,55 @@ class StoredRoute extends Place.Place {
                  route: route,
                  places: places };
     }
-});
-
-StoredRoute.fromJSON = function(obj) {
-    let props;
-    let places = [];
-    let route;
-    let transportation = null;
-
-    for (let key in obj) {
-        let prop = obj[key];
-
-        switch(key) {
-        case 'transportation':
-            transportation = prop;
-            break;
-
-        case 'route':
-            route = new Route.Route();
-            prop.path = prop.path.map((coordinate) => {
-                let lat = coordinate.latitude;
-                let lon = coordinate.longitude;
-                return new Champlain.Coordinate({ latitude: lat,
-                                                  longitude: lon });
-            });
-            prop.turnPoints = prop.turnPoints.map((turnPoint) => {
-                let lat = turnPoint.coordinate.latitude;
-                let lon = turnPoint.coordinate.longitude;
-
-                let coordinate = new Champlain.Coordinate({ latitude: lat,
-                                                            longitude: lon });
-
-                return new Route.TurnPoint({
-                    coordinate: coordinate,
-                    type: turnPoint.type,
-                    distance: turnPoint.distance,
-                    instruction: turnPoint.instruction
+
+    static fromJSON(obj) {
+        let props;
+        let places = [];
+        let route;
+        let transportation = null;
+
+        for (let key in obj) {
+            let prop = obj[key];
+
+            switch(key) {
+            case 'transportation':
+                transportation = prop;
+                break;
+
+            case 'route':
+                route = new Route();
+                prop.path = prop.path.map((coordinate) => {
+                    let lat = coordinate.latitude;
+                    let lon = coordinate.longitude;
+                    return new Champlain.Coordinate({ latitude: lat,
+                                                      longitude: lon });
                 });
-            });
-            route.update(prop);
-            break;
+                prop.turnPoints = prop.turnPoints.map((turnPoint) => {
+                    let lat = turnPoint.coordinate.latitude;
+                    let lon = turnPoint.coordinate.longitude;
+
+                    let coordinate = new Champlain.Coordinate({ latitude: lat,
+                                                                longitude: lon });
+
+                    return new TurnPoint({
+                        coordinate: coordinate,
+                        type: turnPoint.type,
+                        distance: turnPoint.distance,
+                        instruction: turnPoint.instruction
+                    });
+                });
+                route.update(prop);
+                break;
 
-        case 'places':
-            prop.forEach((p) => places.push(Place.Place.fromJSON(p)));
-            break;
+            case 'places':
+                prop.forEach((p) => places.push(Place.fromJSON(p)));
+                break;
+            }
         }
+        return new StoredRoute({ transportation: transportation,
+                                 route: route,
+                                 places: places });
     }
-    return new StoredRoute({ transportation: transportation,
-                             route: route,
-                             places: places });
-};
+}
+
+GObject.registerClass(StoredRoute);
diff --git a/src/transitOptions.js b/src/transitOptions.js
index 0a964eef..12e6067c 100644
--- a/src/transitOptions.js
+++ b/src/transitOptions.js
@@ -19,7 +19,7 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-var TransitOptions = class TransitOptions {
+export class TransitOptions {
 
     constructor() {
         this._showAllTransitTypes = true;
@@ -48,23 +48,23 @@ var TransitOptions = class TransitOptions {
     get transitTypes() {
         return this._transitTypes;
     }
-};
 
-/* return true if the passed in options objects are equal, either both
- * accept any transit type, or both contains the same set of types, otherwise
- * return false
- */
-function equals(first, second) {
-    if (first.showAllTransitTypes && second.showAllTransitTypes) {
-        return true;
-    } else if (first.transitTypes.length !== second.transitTypes.length) {
-        return false;
-    } else {
-        for (let type of first.transitTypes) {
-            if (second.transitTypes.indexOf(type) === -1)
-                return false;
-        }
+    /* return true if the passed in options objects are equal, either both
+     * accept any transit type, or both contains the same set of types, otherwise
+     * return false
+     */
+    static equals(first, second) {
+        if (first.showAllTransitTypes && second.showAllTransitTypes) {
+            return true;
+        } else if (first.transitTypes.length !== second.transitTypes.length) {
+            return false;
+        } else {
+            for (let type of first.transitTypes) {
+                if (second.transitTypes.indexOf(type) === -1)
+                    return false;
+            }
 
-        return true;
+            return true;
+        }
     }
 }
diff --git a/src/zoomInDialog.js b/src/zoomInDialog.js
index 16bb9c99..a5559742 100644
--- a/src/zoomInDialog.js
+++ b/src/zoomInDialog.js
@@ -20,18 +20,14 @@
  * Author: Marcus Lundblad <ml update uu se>
  */
 
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const OSMEdit = imports.osmEdit;
+import {OSMEdit} from './osmEdit.js';
 
-var ZoomInDialog = GObject.registerClass({
-    Template: 'resource:///org/gnome/Maps/ui/zoom-in-dialog.ui',
-    InternalChildren: [ 'cancelButton',
-                        'zoomInButton'],
-}, class ZoomInDialog extends Gtk.Dialog {
+export class ZoomInDialog extends Gtk.Dialog {
 
-    _init(params) {
+    constructor(params) {
         this._latitude = params.latitude;
         delete params.latitude;
         this._longitude = params.longitude;
@@ -42,7 +38,7 @@ var ZoomInDialog = GObject.registerClass({
         /* This is a construct-only property and cannot be set by GtkBuilder */
         params.use_header_bar = true;
 
-        super._init(params);
+        super(params);
 
         this._zoomInButton.connect('clicked', () => this._onZoomIn());
         this._cancelButton.connect('clicked', () => this._onCancel());
@@ -59,4 +55,10 @@ var ZoomInDialog = GObject.registerClass({
     _onCancel() {
         this.response(Gtk.ResponseType.CANCEL);
     }
-});
\ No newline at end of file
+}
+
+GObject.registerClass({
+    Template: 'resource:///org/gnome/Maps/ui/zoom-in-dialog.ui',
+    InternalChildren: [ 'cancelButton',
+                        'zoomInButton'],
+}, ZoomInDialog);
diff --git a/tests/boundingBoxTest.js b/tests/boundingBoxTest.js
index d8a605e1..707059be 100644
--- a/tests/boundingBoxTest.js
+++ b/tests/boundingBoxTest.js
@@ -21,8 +21,8 @@
 
 const JsUnit = imports.jsUnit;
 
-const BoundingBox = imports.boundingBox;
-const Constants = imports.constants;
+import {BoundingBox} from './boundingBox.js';
+import * as Constants from './constants.js';
 
 function main() {
     constructTest();
@@ -36,8 +36,8 @@ function main() {
 }
 
 function constructTest() {
-    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                             bottom: 59.0, right: 16.0 });
+    let bbox = new BoundingBox({ top: 60.0, left: 15.0,
+                                 bottom: 59.0, right: 16.0 });
 
     JsUnit.assertEquals(60.0, bbox.top);
     JsUnit.assertEquals(15.0, bbox.left);
@@ -45,7 +45,7 @@ function constructTest() {
     JsUnit.assertEquals(16.0, bbox.right);
 
     // test default values
-    bbox = new BoundingBox.BoundingBox();
+    bbox = new BoundingBox();
 
     JsUnit.assertEquals(Constants.MIN_LATITUDE, bbox.top);
     JsUnit.assertEquals(Constants.MAX_LONGITUDE, bbox.left);
@@ -54,8 +54,8 @@ function constructTest() {
 }
 
 function copyTest() {
-    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                             bottom: 59.0, right: 16.0 });
+    let bbox = new BoundingBox({ top: 60.0, left: 15.0,
+                                 bottom: 59.0, right: 16.0 });
     let copy = bbox.copy();
 
     // update original box
@@ -72,7 +72,7 @@ function copyTest() {
 }
 
 function setTest() {
-    let bbox = new BoundingBox.BoundingBox();
+    let bbox = new BoundingBox();
 
     bbox.top = 0;
     bbox.left = 0;
@@ -86,8 +86,8 @@ function setTest() {
 }
 
 function getCenterTest() {
-    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                             bottom: 59.0, right: 16.0 });
+    let bbox = new BoundingBox({ top: 60.0, left: 15.0,
+                                 bottom: 59.0, right: 16.0 });
     let center = bbox.getCenter();
 
     JsUnit.assertTrue(center instanceof Array);
@@ -97,10 +97,10 @@ function getCenterTest() {
 }
 
 function composeTest() {
-    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                             bottom: 59.0, right: 16.0 });
-    let other = new BoundingBox.BoundingBox({ top: 60.0, left: 14.0,
-                                              bottom: 59.0, right: 15.0 });
+    let bbox = new BoundingBox({ top: 60.0, left: 15.0,
+                                 bottom: 59.0, right: 16.0 });
+    let other = new BoundingBox({ top: 60.0, left: 14.0,
+                                  bottom: 59.0, right: 15.0 });
 
     bbox.compose(other);
 
@@ -111,8 +111,8 @@ function composeTest() {
 }
 
 function extendTest() {
-    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                             bottom: 59.0, right: 16.0 });
+    let bbox = new BoundingBox({ top: 60.0, left: 15.0,
+                                 bottom: 59.0, right: 16.0 });
 
     bbox.extend(58.0, 14.0);
 
@@ -123,31 +123,33 @@ function extendTest() {
 }
 
 function isValidTest() {
-    let valid = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                              bottom: 59.0, right: 16.0 });
+    let valid = new BoundingBox({ top: 60.0, left: 15.0,
+                                  bottom: 59.0, right: 16.0 });
 
     JsUnit.assertTrue(valid.isValid());
 
-    let unset = new BoundingBox.BoundingBox();
+    let unset = new BoundingBox();
 
     JsUnit.assertFalse(unset.isValid());
 
-    let overflowNorth = new BoundingBox.BoundingBox({ top: 100.0, left: 15.0,
-                                                      bottom: 0.0, right: 16.0 });
+    let overflowNorth = new BoundingBox({ top: 100.0, left: 15.0,
+                                          bottom: 0.0, right: 16.0 });
 
     JsUnit.assertFalse(overflowNorth.isValid());
 
-    let flipped = new BoundingBox.BoundingBox({ top: 59.0, left: 16.0,
-                                                bottom: 60.0, right: 15.0 });
+    let flipped = new BoundingBox({ top: 59.0, left: 16.0,
+                                    bottom: 60.0, right: 15.0 });
 
     JsUnit.assertFalse(flipped.isValid());
 }
 
 function coversTest() {
-    let bbox = new BoundingBox.BoundingBox({ top: 60.0, left: 15.0,
-                                             bottom: 59.0, right: 16.0 });
+    let bbox = new BoundingBox({ top: 60.0, left: 15.0,
+                                 bottom: 59.0, right: 16.0 });
 
     JsUnit.assertTrue(bbox.covers(59.5, 15.5));
     JsUnit.assertFalse(bbox.covers(0.0, 0.0));
     JsUnit.assertFalse(bbox.covers(59.0, -180.0));
 }
+
+main();
diff --git a/tests/meson.build b/tests/meson.build
index 51a600f0..8c2fbd1a 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -2,6 +2,14 @@ tests = ['addressTest', 'boundingBoxTest', 'colorTest', 'osmNamesTest',
          'placeIconsTest', 'placeZoomTest', 'timeTest', 'translationsTest',
          'utilsTest', 'urisTest', 'wikipediaTest']
 
+# suffix for source resources (so we get /org/gnome/Maps or
+# /org/gnome/Maps/Devel, depending on the profile)
+if (get_option('profile') == 'development')
+       suffix = '/Devel'
+else
+       suffix = ''
+endif
+
 foreach test : tests
   script_conf = configuration_data()
   script_conf.set('GJS', gjs.path())
@@ -9,6 +17,7 @@ foreach test : tests
   script_conf.set('libdir', libdir)
   script_conf.set('prefix', prefix)
   script_conf.set('name', test)
+  script_conf.set('suffix', suffix)
   configure_file(
     input: 'test.in',
     output: test,
@@ -18,11 +27,27 @@ foreach test : tests
   )
 endforeach
 
+sources_conf = configuration_data()
+sources_conf.set('suffix', suffix)
+
+# generate combined GResource with source files and tests to use ES modules
+gnome.compile_resources(
+  'test.src',
+  configure_file(
+       input: '../src/org.gnome.Maps.src.gresource.xml.in',
+       output: 'test.src.gresource.xml',
+       configuration: sources_conf
+  ),
+  gresource_bundle: true,
+  install: true,
+  install_dir: meson.build_root(),
+  source_dir: ['../src', '../src/geojson-vt']
+)
+
 foreach test : tests
   test(test, gjs,
-       args: ['-I', meson.source_root() + '/src/', '-I',
-              meson.source_root() + '/tests/',
-              'tests/@0@'.format(test)],
+       args: ['tests/@0@'.format(test),
+              join_paths(meson.build_root(), 'tests', 'test.src.gresource')],
        env:  ['LANG=en_US.utf8', 'LC_ALL=en_US.utf8']
   )
 endforeach
diff --git a/tests/test.in b/tests/test.in
index 1f3aeabe..a2ef7bc0 100644
--- a/tests/test.in
+++ b/tests/test.in
@@ -1,6 +1,20 @@
 #!@GJS@
+const Gio = imports.gi.Gio;
+
 imports.package.init({ name: "@name@",
                        version: "@PACKAGE_VERSION@",
                        prefix: "@prefix@",
                        libdir: "@libdir@" });
-imports.package.run(imports.@name@);
+
+log('program name: ' + imports.system.programInvocationName);
+log('ARG: ' + imports.system.programArgs);
+
+// manually load GResource from build tree for the generated test scripts
+let resource = Gio.Resource.load(imports.system.programArgs[0]);
+
+resource._register();
+
+import(`resource:///org/gnome/Maps@suffix@/js/@name@.js`).catch(error => {
+    console.error(error);
+    imports.system.exit(1);
+});


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]