Sumit has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/265547

Change subject: MobileFrontend Remove deprecated Class.extend
......................................................................

MobileFrontend Remove deprecated Class.extend

Remove all instances of Class.extend and introduces OO.mfExtend for extending
modules.

Bug: T123077
Change-Id: I641f9f4145b0e96b33beefcef35bc2cfa243696d
---
M resources/mobile.abusefilter/AbuseFilterOverlay.js
M resources/mobile.abusefilter/AbuseFilterPanel.js
M resources/mobile.backtotop/BackToTopOverlay.js
M resources/mobile.betaoptin/BetaOptinPanel.js
M resources/mobile.categories.overlays/CategoryAddOverlay.js
M resources/mobile.categories.overlays/CategoryOverlay.js
M resources/mobile.commonsCategory/CommonsCategoryOverlay.js
M resources/mobile.contentOverlays/PointerOverlay.js
M resources/mobile.drawers/CtaDrawer.js
M resources/mobile.drawers/Drawer.js
M resources/mobile.editor.common/EditorOverlayBase.js
M resources/mobile.editor.overlay.withtoolbar/AddReferenceOverlay.js
M resources/mobile.editor.overlay.withtoolbar/EditorOverlayWithToolbar.js
M resources/mobile.editor.overlay/EditorOverlay.js
M resources/mobile.editor.ve/VisualEditorOverlay.js
M resources/mobile.fontchanger/FontChanger.js
M resources/mobile.gallery/PhotoItem.js
M resources/mobile.gallery/PhotoList.js
M resources/mobile.issues/CleanupOverlay.js
M resources/mobile.languages/LanguageOverlay.js
M resources/mobile.loggingSchemas/SchemaEdit.js
M resources/mobile.loggingSchemas/SchemaMobileWebSectionUsage.js
M resources/mobile.mainMenu/MainMenu.js
M resources/mobile.mediaViewer.beta/ImageOverlayBeta.js
M resources/mobile.mediaViewer/ImageOverlay.js
M resources/mobile.messageBox/MessageBox.js
M resources/mobile.nearby/Nearby.js
M resources/mobile.notifications.overlay/NotificationsOverlay.js
M resources/mobile.overlays/ContentOverlay.js
M resources/mobile.overlays/LoadingOverlay.js
M resources/mobile.overlays/Overlay.js
M resources/mobile.pagelist.scripts/WatchstarPageList.js
M resources/mobile.pagelist/PageList.js
M resources/mobile.references/ReferencesDrawer.js
M resources/mobile.search/SearchOverlay.js
M resources/mobile.special.mobileoptions.scripts/mobileoptions.js
M resources/mobile.startup/Anchor.js
M resources/mobile.startup/Button.js
M resources/mobile.startup/Icon.js
M resources/mobile.startup/Page.js
M resources/mobile.startup/Panel.js
M resources/mobile.startup/Schema.js
M resources/mobile.startup/Section.js
M resources/mobile.startup/Skin.js
M resources/mobile.startup/Thumbnail.js
M resources/mobile.talk.overlays/TalkOverlay.js
M resources/mobile.talk.overlays/TalkOverlayBase.js
M resources/mobile.talk.overlays/TalkSectionAddOverlay.js
M resources/mobile.talk.overlays/TalkSectionOverlay.js
M resources/mobile.toc/TableOfContents.js
M resources/mobile.view/View.js
M resources/mobile.watchlist/WatchList.js
M resources/mobile.watchstar/Watchstar.js
M tests/qunit/mobile.overlays/test_Overlay.js
M tests/qunit/mobile.view/test_View.js
55 files changed, 884 insertions(+), 798 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MobileFrontend 
refs/changes/47/265547/1

diff --git a/resources/mobile.abusefilter/AbuseFilterOverlay.js 
b/resources/mobile.abusefilter/AbuseFilterOverlay.js
index 5bfd2cc..f649dd6 100644
--- a/resources/mobile.abusefilter/AbuseFilterOverlay.js
+++ b/resources/mobile.abusefilter/AbuseFilterOverlay.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var AbuseFilterOverlay,
-               Button = M.require( 'mobile.startup/Button' ),
+       var Button = M.require( 'mobile.startup/Button' ),
                Overlay = M.require( 'mobile.overlays/Overlay' );
 
        /**
@@ -9,7 +8,11 @@
         * @class AbuseFilterOverlay
         * @extends Overlay
         */
-       AbuseFilterOverlay = Overlay.extend( {
+       function AbuseFilterOverlay() {
+               Overlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( AbuseFilterOverlay, Overlay, {
                /**
                 * @inheritdoc
                 * @cfg {Object} defaults Default options hash.
diff --git a/resources/mobile.abusefilter/AbuseFilterPanel.js 
b/resources/mobile.abusefilter/AbuseFilterPanel.js
index 9fbf3b7..f66f761 100644
--- a/resources/mobile.abusefilter/AbuseFilterPanel.js
+++ b/resources/mobile.abusefilter/AbuseFilterPanel.js
@@ -2,8 +2,7 @@
        var
                View = M.require( 'mobile.view/View' ),
                AbuseFilterOverlay = M.require( 
'mobile.abusefilter/AbuseFilterOverlay' ),
-               overlayManager = M.require( 'mobile.startup/overlayManager' ),
-               AbuseFilterPanel;
+               overlayManager = M.require( 'mobile.startup/overlayManager' );
 
        /**
         * Panel that shows an error message related to the abusefilter 
extension.
@@ -12,7 +11,12 @@
         * @uses AbuseFilterOverlay
         * FIXME: should extend Panel not View. Or the name should be changed 
to something meaningful.
         */
-       AbuseFilterPanel = View.extend( {
+       function AbuseFilterPanel() {
+               this.isDisallowed = false;
+               View.apply( this, arguments );
+       }
+
+       OO.mfExtend( AbuseFilterPanel, View, {
                /**
                 * @cfg {Object} defaults Default options hash.
                 * @cfg {String} defaults.readMoreMsg A caption for the button 
allowing the user to read
@@ -23,12 +27,6 @@
                },
                template: mw.template.get( 'mobile.abusefilter', 'Panel.hogan' 
),
                className: 'panel hidden',
-
-               /** @inheritdoc */
-               initialize: function () {
-                       View.prototype.initialize.apply( this, arguments );
-                       this.isDisallowed = false;
-               },
 
                /**
                 * Show the panel. Create a route to show AbuseFilterOverlay 
with message.
diff --git a/resources/mobile.backtotop/BackToTopOverlay.js 
b/resources/mobile.backtotop/BackToTopOverlay.js
index c39e320..40dad69 100644
--- a/resources/mobile.backtotop/BackToTopOverlay.js
+++ b/resources/mobile.backtotop/BackToTopOverlay.js
@@ -1,14 +1,17 @@
 ( function ( M, $ ) {
 
-       var BackToTopOverlay,
-               View = M.require( 'mobile.view/View' );
+       var View = M.require( 'mobile.view/View' );
 
        /**
         * Displays a little arrow at the bottom right of the viewport.
         * @class BackToTopOverlay
         * @extends View
         */
-       BackToTopOverlay = View.extend( {
+       function BackToTopOverlay() {
+               View.apply( this, arguments );
+       }
+
+       OO.mfExtend( BackToTopOverlay, View, {
                /**
                 * @inheritdoc
                 */
diff --git a/resources/mobile.betaoptin/BetaOptinPanel.js 
b/resources/mobile.betaoptin/BetaOptinPanel.js
index bfafe64..2529b6f 100644
--- a/resources/mobile.betaoptin/BetaOptinPanel.js
+++ b/resources/mobile.betaoptin/BetaOptinPanel.js
@@ -1,14 +1,17 @@
 ( function ( M, $ ) {
 
-       var BetaOptinPanel,
-               Button = M.require( 'mobile.startup/Button' ),
+       var Button = M.require( 'mobile.startup/Button' ),
                Panel = M.require( 'mobile.startup/Panel' );
 
        /**
         * @class BetaOptinPanel
         * @extends Panel
         */
-       BetaOptinPanel = Panel.extend( {
+       function BetaOptinPanel() {
+               Panel.apply( this, arguments );
+       }
+
+       OO.mfExtend( BetaOptinPanel, Panel, {
                className: 'panel panel-inline visible',
                templatePartials: $.extend( {}, 
Panel.prototype.templatePartials, {
                        button: Button.prototype.template
diff --git a/resources/mobile.categories.overlays/CategoryAddOverlay.js 
b/resources/mobile.categories.overlays/CategoryAddOverlay.js
index 4b71541..316d54b 100644
--- a/resources/mobile.categories.overlays/CategoryAddOverlay.js
+++ b/resources/mobile.categories.overlays/CategoryAddOverlay.js
@@ -1,7 +1,6 @@
 ( function ( M, $ ) {
 
-       var CategoryAddOverlay,
-               Overlay = M.require( 'mobile.overlays/Overlay' ),
+       var Overlay = M.require( 'mobile.overlays/Overlay' ),
                CategoryGateway = M.require( 
'mobile.categories.overlays/CategoryGateway' ),
                CategoryLookupInputWidget = M.require( 
'mobile.categories.overlays/CategoryLookupInputWidget' ),
                icons = M.require( 'mobile.startup/icons' ),
@@ -13,7 +12,12 @@
         * @extends Overlay
         * @uses CategoryGateway
         */
-       CategoryAddOverlay = Overlay.extend( {
+       function CategoryAddOverlay( options ) {
+               options.heading = mw.msg( 
'mobile-frontend-categories-add-heading', options.title );
+               Overlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( CategoryAddOverlay, Overlay, {
                /**
                 * @inheritdoc
                 * @cfg {Object} defaults Default options hash.
@@ -49,14 +53,6 @@
                        header: mw.template.get( 'mobile.categories.overlays', 
'CategoryAddOverlayHeader.hogan' ),
                        saveHeader: mw.template.get( 'mobile.editor.common', 
'saveHeader.hogan' )
                } ),
-
-               /**
-                * @inheritdoc
-                */
-               initialize: function ( options ) {
-                       options.heading = mw.msg( 
'mobile-frontend-categories-add-heading', options.title );
-                       Overlay.prototype.initialize.apply( this, arguments );
-               },
 
                /**
                 * @inheritdoc
diff --git a/resources/mobile.categories.overlays/CategoryOverlay.js 
b/resources/mobile.categories.overlays/CategoryOverlay.js
index 297b3c3..7a9667a 100644
--- a/resources/mobile.categories.overlays/CategoryOverlay.js
+++ b/resources/mobile.categories.overlays/CategoryOverlay.js
@@ -1,7 +1,6 @@
 ( function ( M, $ ) {
 
-       var CategoryOverlay,
-               Overlay = M.require( 'mobile.overlays/Overlay' ),
+       var Overlay = M.require( 'mobile.overlays/Overlay' ),
                CategoryGateway = M.require( 
'mobile.categories.overlays/CategoryGateway' );
 
        /**
@@ -10,7 +9,11 @@
         * @extends Overlay
         * @uses CategoryGateway
         */
-       CategoryOverlay = Overlay.extend( {
+       function CategoryOverlay() {
+               Overlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( CategoryOverlay, Overlay, {
                /**
                 * @inheritdoc
                 * @cfg {Object} defaults Default options hash.
diff --git a/resources/mobile.commonsCategory/CommonsCategoryOverlay.js 
b/resources/mobile.commonsCategory/CommonsCategoryOverlay.js
index 051682d..85e9b6e 100644
--- a/resources/mobile.commonsCategory/CommonsCategoryOverlay.js
+++ b/resources/mobile.commonsCategory/CommonsCategoryOverlay.js
@@ -1,14 +1,17 @@
 ( function ( M ) {
        var Overlay = M.require( 'mobile.overlays/Overlay' ),
-               PhotoList = M.require( 'mobile.gallery/PhotoList' ),
-               CommonsCategoryOverlay;
+               PhotoList = M.require( 'mobile.gallery/PhotoList' );
 
        /**
         * Overlay for displaying page issues
         * @class CommonsCategoryOverlay
         * @extends Overlay
         */
-       CommonsCategoryOverlay = Overlay.extend( {
+       function CommonsCategoryOverlay() {
+               Overlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( CommonsCategoryOverlay, Overlay, {
                /** @inheritdoc */
                postRender: function () {
                        Overlay.prototype.postRender.apply( this );
diff --git a/resources/mobile.contentOverlays/PointerOverlay.js 
b/resources/mobile.contentOverlays/PointerOverlay.js
index 0c7c8f9..a00af7f 100644
--- a/resources/mobile.contentOverlays/PointerOverlay.js
+++ b/resources/mobile.contentOverlays/PointerOverlay.js
@@ -1,13 +1,19 @@
 ( function ( M, $ ) {
-       var PointerOverlay,
-               Overlay = M.require( 'mobile.overlays/Overlay' );
+       var Overlay = M.require( 'mobile.overlays/Overlay' );
 
        /**
         * Page overlay prompting a user for given action
         * @class PointerOverlay
         * @extends Overlay
         */
-       PointerOverlay = Overlay.extend( {
+       function PointerOverlay( options ) {
+               // FIXME: This should not have a default fallback. This is a 
non-optional parameter.
+               // Remove when all existing uses in Gather have been updated.
+               this.appendToElement = options.appendToElement || 
'#mw-mf-page-center';
+               Overlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( PointerOverlay, Overlay, {
                className: 'overlay pointer-overlay tutorial-overlay',
                /**
                 * @inheritdoc
@@ -42,15 +48,6 @@
                        alignment: 'center',
                        confirmMsg: undefined
                } ),
-               /**
-                * @inheritdoc
-                */
-               initialize: function ( options ) {
-                       // FIXME: This should not have a default fallback. This 
is a non-optional parameter.
-                       // Remove when all existing uses in Gather have been 
updated.
-                       this.appendToElement = options.appendToElement || 
'#mw-mf-page-center';
-                       Overlay.prototype.initialize.apply( this, arguments );
-               },
                /**
                 * @inheritdoc
                 */
diff --git a/resources/mobile.drawers/CtaDrawer.js 
b/resources/mobile.drawers/CtaDrawer.js
index 76447e3..b57f80c 100644
--- a/resources/mobile.drawers/CtaDrawer.js
+++ b/resources/mobile.drawers/CtaDrawer.js
@@ -2,8 +2,7 @@
        var Drawer = M.require( 'mobile.drawers/Drawer' ),
                Icon = M.require( 'mobile.startup/Icon' ),
                Button = M.require( 'mobile.startup/Button' ),
-               Anchor = M.require( 'mobile.startup/Anchor' ),
-               CtaDrawer;
+               Anchor = M.require( 'mobile.startup/Anchor' );
 
        /**
         * This creates the drawer at the bottom of the screen that appears 
when an anonymous
@@ -15,7 +14,11 @@
         * @uses Icon
         * @uses Anchor
         */
-       CtaDrawer = Drawer.extend( {
+       function CtaDrawer() {
+               Drawer.apply( this, arguments );
+       }
+
+       OO.mfExtend( CtaDrawer, Drawer, {
                /**
                 * @cfg {Object} defaults Default options hash.
                 * @cfg {Object} defaults.collapseIcon options for Icon for 
collapsing the drawer
diff --git a/resources/mobile.drawers/Drawer.js 
b/resources/mobile.drawers/Drawer.js
index 09c1790..f6eab4e 100644
--- a/resources/mobile.drawers/Drawer.js
+++ b/resources/mobile.drawers/Drawer.js
@@ -1,15 +1,18 @@
 ( function ( M, $ ) {
 
        var Panel = M.require( 'mobile.startup/Panel' ),
-               Icon = M.require( 'mobile.startup/Icon' ),
-               Drawer;
+               Icon = M.require( 'mobile.startup/Icon' );
 
        /**
         * A {@link View} that pops up from the bottom of the screen.
         * @class Drawer
         * @extends Panel
         */
-       Drawer = Panel.extend( {
+       function Drawer() {
+               Panel.apply( this, arguments );
+       }
+
+       OO.mfExtend( Drawer, Panel, {
                /**
                 * @inheritdoc
                 * @cfg {Object} defaults Default options hash.
diff --git a/resources/mobile.editor.common/EditorOverlayBase.js 
b/resources/mobile.editor.common/EditorOverlayBase.js
index a71f02b..4ed104d 100644
--- a/resources/mobile.editor.common/EditorOverlayBase.js
+++ b/resources/mobile.editor.common/EditorOverlayBase.js
@@ -4,8 +4,7 @@
                browser = M.require( 'mobile.browser/browser' ),
                Icon = M.require( 'mobile.startup/Icon' ),
                toast = M.require( 'mobile.toast/toast' ),
-               user = M.require( 'mobile.user/user' ),
-               EditorOverlayBase;
+               user = M.require( 'mobile.user/user' );
 
        /**
         * 'Edit' button
@@ -44,7 +43,41 @@
         * @uses Icon
         * @uses user
         */
-       EditorOverlayBase = Overlay.extend( {
+       function EditorOverlayBase( options ) {
+               var self = this;
+
+               if ( options.isNewPage ) {
+                       options.placeholder = mw.msg( 
'mobile-frontend-editor-placeholder-new-page', mw.user );
+               }
+               // change the message to request a summary when not in article 
namespace
+               if ( mw.config.get( 'wgNamespaceNumber' ) !== 0 ) {
+                       options.summaryRequestMsg = mw.msg( 
'mobile-frontend-editor-summary' );
+               }
+               this.pageGateway = new PageGateway( options.api );
+               this.editCount = user.getEditCount();
+               this.isNewPage = options.isNewPage;
+               this.isNewEditor = options.isNewEditor;
+               this.sectionId = options.sectionId;
+               this.schema = options.editSchema;
+               this.config = mw.config.get( 'wgMFEditorOptions' );
+               this.sessionId = options.sessionId;
+               this.allowCloseWindow = mw.confirmCloseWindow( {
+                       /** Returns true, if content has changed, otherwise 
false */
+                       test: function () {
+                               // Check if content has changed
+                               return self.hasChanged();
+                       },
+
+                       /** Message to show the user, if content has changed */
+                       message: mw.msg( 
'mobile-frontend-editor-cancel-confirm' ),
+                       /** Event namespace */
+                       namespace: 'editwarning'
+               } );
+
+               Overlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( EditorOverlayBase, Overlay, {
                /**
                 * @inheritdoc
                 * @cfg {Object} defaults Default options hash.
@@ -173,40 +206,6 @@
                        $.cookie( 'mobileEditor', 'true', {
                                expires: 30
                        } );
-               },
-               /** @inheritdoc **/
-               initialize: function ( options ) {
-                       var self = this;
-
-                       if ( options.isNewPage ) {
-                               options.placeholder = mw.msg( 
'mobile-frontend-editor-placeholder-new-page', mw.user );
-                       }
-                       // change the message to request a summary when not in 
article namespace
-                       if ( mw.config.get( 'wgNamespaceNumber' ) !== 0 ) {
-                               options.summaryRequestMsg = mw.msg( 
'mobile-frontend-editor-summary' );
-                       }
-                       this.pageGateway = new PageGateway( options.api );
-                       this.editCount = user.getEditCount();
-                       this.isNewPage = options.isNewPage;
-                       this.isNewEditor = options.isNewEditor;
-                       this.sectionId = options.sectionId;
-                       this.schema = options.editSchema;
-                       this.config = mw.config.get( 'wgMFEditorOptions' );
-                       this.sessionId = options.sessionId;
-                       this.allowCloseWindow = mw.confirmCloseWindow( {
-                               /** Returns true, if content has changed, 
otherwise false */
-                               test: function () {
-                                       // Check if content has changed
-                                       return self.hasChanged();
-                               },
-
-                               /** Message to show the user, if content has 
changed */
-                               message: mw.msg( 
'mobile-frontend-editor-cancel-confirm' ),
-                               /** Event namespace */
-                               namespace: 'editwarning'
-                       } );
-
-                       Overlay.prototype.initialize.apply( this, arguments );
                },
                /**
                 * Report load errors back to the user. Silently record the 
error using EventLogging.
diff --git a/resources/mobile.editor.overlay.withtoolbar/AddReferenceOverlay.js 
b/resources/mobile.editor.overlay.withtoolbar/AddReferenceOverlay.js
index 030a955..dd1a41b 100644
--- a/resources/mobile.editor.overlay.withtoolbar/AddReferenceOverlay.js
+++ b/resources/mobile.editor.overlay.withtoolbar/AddReferenceOverlay.js
@@ -1,13 +1,16 @@
 ( function ( M, $ ) {
-       var     AddReferenceOverlay,
-               Overlay = M.require( 'mobile.overlays/Overlay' );
+       var Overlay = M.require( 'mobile.overlays/Overlay' );
 
        /**
         * Overlay that shows an editor
         * @class AddReferenceOverlay
         * @extends Overlay
         */
-       AddReferenceOverlay = Overlay.extend( {
+       function AddReferenceOverlay() {
+               Overlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( AddReferenceOverlay, Overlay, {
                /**
                 * @inheritdoc
                 * @cfg {Object} defaults Default options hash.
diff --git 
a/resources/mobile.editor.overlay.withtoolbar/EditorOverlayWithToolbar.js 
b/resources/mobile.editor.overlay.withtoolbar/EditorOverlayWithToolbar.js
index 612bfce..6cfc547 100644
--- a/resources/mobile.editor.overlay.withtoolbar/EditorOverlayWithToolbar.js
+++ b/resources/mobile.editor.overlay.withtoolbar/EditorOverlayWithToolbar.js
@@ -1,14 +1,17 @@
 ( function ( M, $ ) {
        var EditorOverlay = M.require( 'mobile.editor.overlay/EditorOverlay' ),
-               AddReferenceOverlay = M.require( 
'mobile.editor.overlay.withtoolbar/AddReferenceOverlay' ),
-               EditorOverlayWithToolbar;
+               AddReferenceOverlay = M.require( 
'mobile.editor.overlay.withtoolbar/AddReferenceOverlay' );
 
        /**
         * Overlay that shows an editor
         * @class EditorOverlayWithToolbar
         * @extends EditorOverlay
         */
-       EditorOverlayWithToolbar = EditorOverlay.extend( {
+       function EditorOverlayWithToolbar() {
+               EditorOverlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( EditorOverlayWithToolbar, EditorOverlay, {
                templatePartials: $.extend( {}, 
EditorOverlay.prototype.templatePartials, {
                        footer: mw.template.get( 
'mobile.editor.overlay.withtoolbar', 'editorFooter.hogan' )
                } ),
diff --git a/resources/mobile.editor.overlay/EditorOverlay.js 
b/resources/mobile.editor.overlay/EditorOverlay.js
index 7be9a82..7e200d7 100644
--- a/resources/mobile.editor.overlay/EditorOverlay.js
+++ b/resources/mobile.editor.overlay/EditorOverlay.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var EditorOverlay,
-               EditorOverlayBase = M.require( 
'mobile.editor.common/EditorOverlayBase' ),
+       var EditorOverlayBase = M.require( 
'mobile.editor.common/EditorOverlayBase' ),
                Section = M.require( 'mobile.startup/Section' ),
                EditorGateway = M.require( 'mobile.editor.api/EditorGateway' ),
                AbuseFilterPanel = M.require( 
'mobile.abusefilter/AbuseFilterPanel' ),
@@ -19,7 +18,35 @@
         * @uses VisualEditorOverlay
         * @extends EditorOverlayBase
         */
-       EditorOverlay = EditorOverlayBase.extend( {
+       function EditorOverlay( options ) {
+               this.gateway = new EditorGateway( {
+                       api: options.api,
+                       title: options.title,
+                       sectionId: options.sectionId,
+                       oldId: options.oldId,
+                       isNewPage: options.isNewPage
+               } );
+               this.readOnly = options.oldId ? true : false; // If old 
revision, readOnly mode
+               if ( this.isVisualEditorEnabled() ) {
+                       options.editSwitcher = true;
+               }
+               if ( this.readOnly ) {
+                       options.readOnly = true;
+                       options.editingMsg = mw.msg( 
'mobile-frontend-editor-viewing-source-page', options.title );
+               } else {
+                       options.editingMsg = mw.msg( 
'mobile-frontend-editor-editing-page', options.title );
+               }
+               if ( options.isAnon ) {
+                       // add required data for anonymous editing warning
+                       options = this._prepareAnonWarning( options );
+               }
+               // be explicit here. This may have been initialized from VE.
+               options.isVisualEditor = false;
+               options.previewingMsg = mw.msg( 
'mobile-frontend-editor-previewing-page', options.title );
+               EditorOverlayBase.call( this, options );
+       }
+
+       OO.mfExtend( EditorOverlay, EditorOverlayBase, {
                /** @inheritdoc **/
                isBorderBox: false,
                /** @inheritdoc **/
@@ -70,35 +97,6 @@
                                $.inArray( mw.config.get( 'wgNamespaceNumber' 
), mw.config.get( 'wgVisualEditorConfig' ).namespaces ) > -1 &&
                                mw.config.get( 'wgTranslatePageTranslation' ) 
!== 'translation' &&
                                mw.config.get( 'wgPageContentModel' ) === 
'wikitext';
-               },
-
-               /** @inheritdoc **/
-               initialize: function ( options ) {
-                       this.gateway = new EditorGateway( {
-                               api: options.api,
-                               title: options.title,
-                               sectionId: options.sectionId,
-                               oldId: options.oldId,
-                               isNewPage: options.isNewPage
-                       } );
-                       this.readOnly = options.oldId ? true : false; // If old 
revision, readOnly mode
-                       if ( this.isVisualEditorEnabled() ) {
-                               options.editSwitcher = true;
-                       }
-                       if ( this.readOnly ) {
-                               options.readOnly = true;
-                               options.editingMsg = mw.msg( 
'mobile-frontend-editor-viewing-source-page', options.title );
-                       } else {
-                               options.editingMsg = mw.msg( 
'mobile-frontend-editor-editing-page', options.title );
-                       }
-                       if ( options.isAnon ) {
-                               // add required data for anonymous editing 
warning
-                               options = this._prepareAnonWarning( options );
-                       }
-                       // be explicit here. This may have been initialized 
from VE.
-                       options.isVisualEditor = false;
-                       options.previewingMsg = mw.msg( 
'mobile-frontend-editor-previewing-page', options.title );
-                       EditorOverlayBase.prototype.initialize.call( this, 
options );
                },
                events: $.extend( {}, EditorOverlayBase.prototype.events, {
                        'input .wikitext-editor': 'onInputWikitextEditor'
diff --git a/resources/mobile.editor.ve/VisualEditorOverlay.js 
b/resources/mobile.editor.ve/VisualEditorOverlay.js
index df072ce..e8a80ea 100644
--- a/resources/mobile.editor.ve/VisualEditorOverlay.js
+++ b/resources/mobile.editor.ve/VisualEditorOverlay.js
@@ -1,15 +1,20 @@
 ( function ( M, $, ve ) {
        var EditorOverlayBase = M.require( 
'mobile.editor.common/EditorOverlayBase' ),
                settings = M.require( 'mobile.settings/settings' ),
-               overlayManager = M.require( 'mobile.startup/overlayManager' ),
-               VisualEditorOverlay;
+               overlayManager = M.require( 'mobile.startup/overlayManager' );
 
        /**
         * Overlay for VisualEditor view
         * @class VisualEditorOverlay
         * @extends EditorOverlayBase
         */
-       VisualEditorOverlay = EditorOverlayBase.extend( {
+       function VisualEditorOverlay( options ) {
+               this.applyHeaderOptions( options, true );
+               EditorOverlayBase.apply( this, arguments );
+               this.isNewPage = options.isNewPage;
+       }
+
+       OO.mfExtend( VisualEditorOverlay, EditorOverlayBase, {
                /** @inheritdoc **/
                isBorderBox: false,
                /** @inheritdoc **/
@@ -33,12 +38,6 @@
                        // Set things that are known to be true.
                        options.hasToolbar = isVE;
                        options.isVisualEditor = isVE;
-               },
-               /** @inheritdoc **/
-               initialize: function ( options ) {
-                       this.applyHeaderOptions( options, true );
-                       EditorOverlayBase.prototype.initialize.apply( this, 
arguments );
-                       this.isNewPage = options.isNewPage;
                },
                /**
                 * Destroy the existing VisualEditor target.
diff --git a/resources/mobile.fontchanger/FontChanger.js 
b/resources/mobile.fontchanger/FontChanger.js
index dff22d2..4226df4 100644
--- a/resources/mobile.fontchanger/FontChanger.js
+++ b/resources/mobile.fontchanger/FontChanger.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var FontChanger,
-               View = M.require( 'mobile.view/View' ),
+       var View = M.require( 'mobile.view/View' ),
                Button = M.require( 'mobile.startup/Button' ),
                settings = M.require( 'mobile.settings/settings' );
 
@@ -9,7 +8,11 @@
         * @class FontChanger
         * @extends View
         */
-       FontChanger = View.extend( {
+       function FontChanger() {
+               View.apply( this, arguments );
+       }
+
+       OO.mfExtend( FontChanger, View, {
                /**
                 * @cfg {Object} defaults Default options hash.
                 * @cfg {Object} defaults.viewLink Anchor options for a link to 
wikidata page.
diff --git a/resources/mobile.gallery/PhotoItem.js 
b/resources/mobile.gallery/PhotoItem.js
index 0cae5ef..abd84b5 100644
--- a/resources/mobile.gallery/PhotoItem.js
+++ b/resources/mobile.gallery/PhotoItem.js
@@ -1,13 +1,16 @@
 ( function ( M ) {
-       var PhotoItem,
-               View = M.require( 'mobile.view/View' );
+       var View = M.require( 'mobile.view/View' );
 
        /**
         * Single photo item in gallery
         * @class PhotoItem
         * @extends View
         */
-       PhotoItem = View.extend( {
+       function PhotoItem() {
+               View.apply( this, arguments );
+       }
+
+       OO.mfExtend( PhotoItem, View, {
                template: mw.template.get( 'mobile.gallery', 'PhotoItem.hogan' 
),
                tagName: 'li'
        } );
diff --git a/resources/mobile.gallery/PhotoList.js 
b/resources/mobile.gallery/PhotoList.js
index ddaa692..6bae624 100644
--- a/resources/mobile.gallery/PhotoList.js
+++ b/resources/mobile.gallery/PhotoList.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var PhotoList,
-               icons = M.require( 'mobile.startup/icons' ),
+       var icons = M.require( 'mobile.startup/icons' ),
                PhotoListGateway = M.require( 'mobile.gallery/PhotoListGateway' 
),
                PhotoItem = M.require( 'mobile.gallery/PhotoItem' ),
                InfiniteScroll = M.require( 
'mobile.infiniteScroll/InfiniteScroll' ),
@@ -14,7 +13,24 @@
         * @uses InfiniteScroll
         * @extends View
         */
-       PhotoList = View.extend( {
+       function PhotoList( options ) {
+               var gatewayOptions = {
+                       api: options.api
+               };
+
+               if ( options.username ) {
+                       gatewayOptions.username = options.username;
+               } else if ( options.category ) {
+                       gatewayOptions.category = options.category;
+               }
+               this.gateway = new PhotoListGateway( gatewayOptions );
+               // Set up infinite scroll
+               this.infiniteScroll = new InfiniteScroll( 1000 );
+               this.infiniteScroll.on( 'load', $.proxy( this, '_loadPhotos' ) 
);
+               View.call( this, options );
+       }
+
+       OO.mfExtend( PhotoList, View, {
                template: mw.template.get( 'mobile.gallery', 'PhotoList.hogan' 
),
                /**
                 * @cfg {Object} defaults Default options hash.
@@ -23,23 +39,6 @@
                 */
                defaults: {
                        spinner: icons.spinner().toHtmlString()
-               },
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       var gatewayOptions = {
-                               api: options.api
-                       };
-
-                       if ( options.username ) {
-                               gatewayOptions.username = options.username;
-                       } else if ( options.category ) {
-                               gatewayOptions.category = options.category;
-                       }
-                       this.gateway = new PhotoListGateway( gatewayOptions );
-                       // Set up infinite scroll
-                       this.infiniteScroll = new InfiniteScroll( 1000 );
-                       this.infiniteScroll.on( 'load', $.proxy( this, 
'_loadPhotos' ) );
-                       View.prototype.initialize.apply( this, arguments );
                },
                /** @inheritdoc */
                preRender: function () {
diff --git a/resources/mobile.issues/CleanupOverlay.js 
b/resources/mobile.issues/CleanupOverlay.js
index 798d40e..dbc6d82 100644
--- a/resources/mobile.issues/CleanupOverlay.js
+++ b/resources/mobile.issues/CleanupOverlay.js
@@ -5,15 +5,19 @@
                        name: 'cleanup-gray',
                        additionalClassNames: 'issue-notice',
                        hasText: true
-               } ),
-               CleanupOverlay;
+               } );
 
        /**
         * Overlay for displaying page issues
         * @class CleanupOverlay
         * @extends Overlay
         */
-       CleanupOverlay = Overlay.extend( {
+       function CleanupOverlay( options ) {
+               options.heading = '<strong>' + options.headingText + 
'</strong>';
+               Overlay.call( this, options );
+       }
+
+       OO.mfExtend( CleanupOverlay, Overlay, {
                templatePartials: $.extend( {}, 
Overlay.prototype.templatePartials, {
                        content: mw.template.get( 'mobile.issues', 
'OverlayContent.hogan' )
                } ),
@@ -24,12 +28,7 @@
                 */
                defaults: $.extend( {}, Overlay.prototype.defaults, {
                        className: icon.getClassName()
-               } ),
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       options.heading = '<strong>' + options.headingText + 
'</strong>';
-                       Overlay.prototype.initialize.call( this, options );
-               }
+               } )
        } );
        M.define( 'mobile.issues/CleanupOverlay', CleanupOverlay );
 }( mw.mobileFrontend, jQuery ) );
diff --git a/resources/mobile.languages/LanguageOverlay.js 
b/resources/mobile.languages/LanguageOverlay.js
index 588a7ab..a929b3d 100644
--- a/resources/mobile.languages/LanguageOverlay.js
+++ b/resources/mobile.languages/LanguageOverlay.js
@@ -1,15 +1,32 @@
 ( function ( M, $ ) {
 
        var Overlay = M.require( 'mobile.overlays/Overlay' ),
-               settings = M.require( 'mobile.settings/settings' ),
-               LanguageOverlay;
+               settings = M.require( 'mobile.settings/settings' );
 
        /**
         * Overlay displaying list of languages for a page
         * @class LanguageOverlay
         * @extends Overlay
         */
-       LanguageOverlay = Overlay.extend( {
+       function LanguageOverlay( options ) {
+               var langMap;
+
+               if ( options.languages && options.languages.length ) {
+                       options.header = mw.msg( 
'mobile-frontend-language-header', options.languages.length );
+               }
+               if ( options.variants && options.variants.length ) {
+                       options.variantHeader = mw.msg( 
'mobile-frontend-language-variant-header' );
+               }
+               langMap = settings.get( 'langMap' );
+               this.languageMap = langMap ? $.parseJSON( langMap ) : {};
+               if ( options.currentLanguage ) {
+                       this.trackLanguage( options.currentLanguage );
+               }
+               options = this._sortLanguages( options );
+               Overlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( LanguageOverlay, Overlay, {
                /**
                 * @inheritdoc
                 * @cfg {Object} defaults Default options hash.
@@ -38,25 +55,6 @@
                        'click ul a': 'onLinkClick',
                        'input .search': 'onSearchInput'
                } ),
-
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       var langMap;
-
-                       if ( options.languages && options.languages.length ) {
-                               options.header = mw.msg( 
'mobile-frontend-language-header', options.languages.length );
-                       }
-                       if ( options.variants && options.variants.length ) {
-                               options.variantHeader = mw.msg( 
'mobile-frontend-language-variant-header' );
-                       }
-                       langMap = settings.get( 'langMap' );
-                       this.languageMap = langMap ? $.parseJSON( langMap ) : 
{};
-                       if ( options.currentLanguage ) {
-                               this.trackLanguage( options.currentLanguage );
-                       }
-                       options = this._sortLanguages( options );
-                       Overlay.prototype.initialize.apply( this, arguments );
-               },
                /**
                 * Sorts the provided languages based on previous usage and 
tags them
                 * with a property preferred for template usage
diff --git a/resources/mobile.loggingSchemas/SchemaEdit.js 
b/resources/mobile.loggingSchemas/SchemaEdit.js
index 9f79b6b..e632e40 100644
--- a/resources/mobile.loggingSchemas/SchemaEdit.js
+++ b/resources/mobile.loggingSchemas/SchemaEdit.js
@@ -1,13 +1,16 @@
 ( function ( M, $ ) {
-       var SchemaEdit,
-               Schema = M.require( 'mobile.startup/Schema' ),
+       var Schema = M.require( 'mobile.startup/Schema' ),
                user = M.require( 'mobile.user/user' );
 
        /**
         * @class SchemaEdit
         * @extends Schema
         */
-       SchemaEdit = Schema.extend( {
+       function SchemaEdit() {
+               Schema.apply( this, arguments );
+       }
+
+       OO.mfExtend( SchemaEdit, Schema, {
                /** @inheritdoc **/
                name: 'Edit',
                /**
diff --git a/resources/mobile.loggingSchemas/SchemaMobileWebSectionUsage.js 
b/resources/mobile.loggingSchemas/SchemaMobileWebSectionUsage.js
index 14235da..b934d2a 100644
--- a/resources/mobile.loggingSchemas/SchemaMobileWebSectionUsage.js
+++ b/resources/mobile.loggingSchemas/SchemaMobileWebSectionUsage.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var SchemaMobileWebSectionUsage,
-               Schema = M.require( 'mobile.startup/Schema' ),
+       var Schema = M.require( 'mobile.startup/Schema' ),
                user = M.require( 'mobile.user/user' ),
                browser = M.require( 'mobile.browser/browser' ),
                experiments = mw.config.get( 'wgMFExperiments' );
@@ -9,7 +8,11 @@
         * @class SchemaMobileWebSectionUsage
         * @extends Schema
         */
-       SchemaMobileWebSectionUsage = Schema.extend( {
+       function SchemaMobileWebSectionUsage() {
+               Schema.apply( this, arguments );
+       }
+
+       OO.mfExtend( SchemaMobileWebSectionUsage, Schema, {
                /**
                 * @inheritdoc
                 */
diff --git a/resources/mobile.mainMenu/MainMenu.js 
b/resources/mobile.mainMenu/MainMenu.js
index c31a2f9..15d6de4 100644
--- a/resources/mobile.mainMenu/MainMenu.js
+++ b/resources/mobile.mainMenu/MainMenu.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var MainMenu,
-               browser = M.require( 'mobile.browser/browser' ),
+       var browser = M.require( 'mobile.browser/browser' ),
                View = M.require( 'mobile.view/View' );
 
        /**
@@ -9,7 +8,12 @@
         * @class MainMenu
         * @extends View
         */
-       MainMenu = View.extend( {
+       function MainMenu( options ) {
+               this.activator = options.activator;
+               View.call( this, options );
+       }
+
+       OO.mfExtend( MainMenu, View, {
                /** @inheritdoc */
                isTemplateMode: true,
                /** @inheritdoc */
@@ -61,13 +65,6 @@
                                } );
                        } );
                        return d;
-               },
-
-               /** @inheritdoc **/
-               initialize: function ( options ) {
-
-                       this.activator = options.activator;
-                       View.prototype.initialize.call( this, options );
                },
 
                /**
diff --git a/resources/mobile.mediaViewer.beta/ImageOverlayBeta.js 
b/resources/mobile.mediaViewer.beta/ImageOverlayBeta.js
index 4992d84..b1ba8b6 100644
--- a/resources/mobile.mediaViewer.beta/ImageOverlayBeta.js
+++ b/resources/mobile.mediaViewer.beta/ImageOverlayBeta.js
@@ -1,14 +1,17 @@
 ( function ( M, $ ) {
        var ImageOverlay = M.require( 'mobile.mediaViewer/ImageOverlay' ),
-               Swipe = M.require( 'mobile.swipe/Swipe' ),
-               ImageOverlayBeta;
+               Swipe = M.require( 'mobile.swipe/Swipe' );
 
        /**
         * Extends ImageOverlay to add a swipe functionality
         * @class ImageOverlayBeta
         * @extends ImageOverlay
         */
-       ImageOverlayBeta = ImageOverlay.extend( {
+       function ImageOverlayBeta() {
+               ImageOverlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( ImageOverlayBeta, ImageOverlay, {
                /** @inheritdoc */
                _enableArrowImages: function ( thumbs ) {
                        var self = this;
diff --git a/resources/mobile.mediaViewer/ImageOverlay.js 
b/resources/mobile.mediaViewer/ImageOverlay.js
index 70caa30..70f7a01 100644
--- a/resources/mobile.mediaViewer/ImageOverlay.js
+++ b/resources/mobile.mediaViewer/ImageOverlay.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var ImageOverlay,
-               Overlay = M.require( 'mobile.overlays/Overlay' ),
+       var Overlay = M.require( 'mobile.overlays/Overlay' ),
                Icon = M.require( 'mobile.startup/Icon' ),
                Button = M.require( 'mobile.startup/Button' ),
                ImageGateway = M.require( 'mobile.mediaViewer/ImageGateway' );
@@ -12,7 +11,14 @@
         * @uses Icon
         * @uses ImageGateway
         */
-       ImageOverlay = Overlay.extend( {
+       function ImageOverlay( options ) {
+               this.gateway = new ImageGateway( {
+                       api: options.api
+               } );
+               Overlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( ImageOverlay, Overlay, {
                // allow pinch zooming
                hasFixedHeader: false,
                className: 'overlay media-viewer',
@@ -56,14 +62,6 @@
                        // Click tracking for table of contents so we can see 
if people interact with it
                        'click .slider-button': 'onSlide'
                } ),
-
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       this.gateway = new ImageGateway( {
-                               api: options.api
-                       } );
-                       Overlay.prototype.initialize.apply( this, arguments );
-               },
                /**
                 * Event handler for slide event
                 * @param {jQuery.Event} ev
diff --git a/resources/mobile.messageBox/MessageBox.js 
b/resources/mobile.messageBox/MessageBox.js
index 0864a3f..2ed00e0 100644
--- a/resources/mobile.messageBox/MessageBox.js
+++ b/resources/mobile.messageBox/MessageBox.js
@@ -1,12 +1,15 @@
 ( function ( M ) {
-       var MessageBox,
-               View = M.require( 'mobile.view/View' );
+       var View = M.require( 'mobile.view/View' );
 
        /**
         * @class MessageBox
         * @extends View
         */
-       MessageBox = View.extend( {
+       function MessageBox() {
+               View.apply( this, arguments );
+       }
+
+       OO.mfExtend( MessageBox, View, {
                /** @inheritdoc */
                isTemplateMode: true,
                /**
diff --git a/resources/mobile.nearby/Nearby.js 
b/resources/mobile.nearby/Nearby.js
index 76b2dac..e420251 100644
--- a/resources/mobile.nearby/Nearby.js
+++ b/resources/mobile.nearby/Nearby.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var Nearby,
-               MessageBox = M.require( 'mobile.messageBox/MessageBox' ),
+       var MessageBox = M.require( 'mobile.messageBox/MessageBox' ),
                NearbyGateway = M.require( 'mobile.nearby/NearbyGateway' ),
                WatchstarPageList = M.require( 
'mobile.pagelist.scripts/WatchstarPageList' ),
                browser = M.require( 'mobile.browser/browser' ),
@@ -8,12 +7,58 @@
 
        /**
         * List of nearby pages
-
         * @class Nearby
         * @uses NearbyGateway
         * @extends WatchstarPageList
         */
-       Nearby = WatchstarPageList.extend( {
+       function Nearby( options ) {
+               var self = this,
+                       _super = WatchstarPageList;
+
+               this.range = options.range || mw.config.get( 'wgMFNearbyRange' 
) || 1000;
+               this.source = options.source || 'nearby';
+               this.nearbyApi = new NearbyGateway( {
+                       api: options.api
+               } );
+
+               if ( options.errorType ) {
+                       options.errorOptions = self._errorOptions( 
options.errorType );
+               }
+
+               // Re-run after api/geolocation request
+               if ( options.useCurrentLocation ) {
+                       // Flush any existing list of pages
+                       options.pages = [];
+
+                       // Get some new pages
+                       this.getCurrentPosition().done( function ( coordOptions 
) {
+                               $.extend( options, coordOptions );
+                               self._find( options ).done( function ( options 
) {
+                                       _super.call( self, options );
+                               } );
+                       } ).fail( function ( errorType ) {
+                               options.errorType = errorType;
+                               _super.call( self, options );
+                       } );
+               } else if ( ( options.latitude && options.longitude ) || 
options.pageTitle ) {
+                       // Flush any existing list of pages
+                       options.pages = [];
+
+                       // Get some new pages
+                       this._find( options ).done( function ( options ) {
+                               _super.call( self, options );
+                       } ).fail( function ( errorType ) {
+                               options.errorType = errorType;
+                               _super.call( self, options );
+                       } );
+               }
+
+               // Run it once for loader etc
+               this._isLoading = true;
+               _super.apply( this, arguments );
+       }
+
+       OO.mfExtend( Nearby, WatchstarPageList, {
                errorMessages: {
                        empty: {
                                heading: mw.msg( 
'mobile-frontend-nearby-noresults' ),
@@ -89,56 +134,6 @@
                                result.reject( 'incompatible' );
                        }
                        return result;
-               },
-               /**
-                * Get pages within a nearby range of current location
-                * @inheritdoc
-                */
-               initialize: function ( options ) {
-                       var self = this,
-                               _super = WatchstarPageList.prototype.initialize;
-
-                       this.range = options.range || mw.config.get( 
'wgMFNearbyRange' ) || 1000;
-                       this.source = options.source || 'nearby';
-                       this.nearbyApi = new NearbyGateway( {
-                               api: options.api
-                       } );
-
-                       if ( options.errorType ) {
-                               options.errorOptions = self._errorOptions( 
options.errorType );
-                       }
-
-                       // Re-run after api/geolocation request
-                       if ( options.useCurrentLocation ) {
-                               // Flush any existing list of pages
-                               options.pages = [];
-
-                               // Get some new pages
-                               this.getCurrentPosition().done( function ( 
coordOptions ) {
-                                       $.extend( options, coordOptions );
-                                       self._find( options ).done( function ( 
options ) {
-                                               _super.call( self, options );
-                                       } );
-                               } ).fail( function ( errorType ) {
-                                       options.errorType = errorType;
-                                       _super.call( self, options );
-                               } );
-                       } else if ( ( options.latitude && options.longitude ) 
|| options.pageTitle ) {
-                               // Flush any existing list of pages
-                               options.pages = [];
-
-                               // Get some new pages
-                               this._find( options ).done( function ( options 
) {
-                                       _super.call( self, options );
-                               } ).fail( function ( errorType ) {
-                                       options.errorType = errorType;
-                                       _super.call( self, options );
-                               } );
-                       }
-
-                       // Run it once for loader etc
-                       this._isLoading = true;
-                       _super.apply( this, arguments );
                },
                /**
                 * Request pages from api based on provided options.
diff --git a/resources/mobile.notifications.overlay/NotificationsOverlay.js 
b/resources/mobile.notifications.overlay/NotificationsOverlay.js
index e03187b..7078083 100644
--- a/resources/mobile.notifications.overlay/NotificationsOverlay.js
+++ b/resources/mobile.notifications.overlay/NotificationsOverlay.js
@@ -1,8 +1,7 @@
 ( function ( M, $ ) {
        var Overlay = M.require( 'mobile.overlays/Overlay' ),
                api = new mw.Api(),
-               Anchor = M.require( 'mobile.startup/Anchor' ),
-               NotificationsOverlay;
+               Anchor = M.require( 'mobile.startup/Anchor' );
 
        /**
         * Overlay for notifications
@@ -10,7 +9,87 @@
         * @extend Overlay
         * @uses mw.Api
         */
-       NotificationsOverlay = Overlay.extend( {
+       function NotificationsOverlay( options ) {
+               var self = this;
+               Overlay.apply( this, options );
+               // Anchor tag that corresponds to a notifications badge
+               this.$badge = options.$badge;
+               // On error use the url as a fallback
+               if ( options.error ) {
+                       this.onError();
+               } else {
+                       // FIXME: Move to NotificationApi class
+                       api.get( {
+                               action: 'query',
+                               meta: 'notifications',
+                               notformat: 'flyout',
+                               notprop: 'index|list|count',
+                               uselang: 'user'
+                       } ).done( function ( result ) {
+                               var notifications;
+                               if ( result.query && result.query.notifications 
) {
+                                       notifications = $.map( 
result.query.notifications.list, function ( a ) {
+                                               return {
+                                                       message: a['*'],
+                                                       timestamp: 
a.timestamp.mw,
+                                                       unread: ( 
a.hasOwnProperty( 'read' ) ? 'mw-echo-notification-read' : 
'mw-echo-notification-unread' )
+                                               };
+                                       } ).sort( function ( a, b ) {
+                                               return a.timestamp < 
b.timestamp ? 1 : -1;
+                                       } );
+                                       if ( notifications.length ) {
+                                               options.notifications = 
notifications;
+                                       } else {
+                                               options.errorMessage = mw.msg( 
'echo-none' );
+                                       }
+
+                                       self.render( options );
+                                       self.$( '.mw-echo-notification' ).each( 
function () {
+                                               var $notification = $( this ),
+                                                       $primaryLink = 
$notification.find( '.mw-echo-notification-primary-link' ),
+                                                       eventId = 
$notification.attr( 'data-notification-event' ),
+                                                       eventType = 
$notification.attr( 'data-notification-type' );
+
+                                               // If there is a primary link, 
make the entire notification clickable.
+                                               if ( $primaryLink.length ) {
+                                                       $notification.addClass( 
'mw-echo-linked-notification' );
+                                                       $notification.on( 
'click', function () {
+                                                               
mw.echo.logger.logInteraction(
+                                                                       
mw.echo.Logger.static.actions.notificationClick,
+                                                                       
'mobile-overlay',
+                                                                       eventId,
+                                                                       
eventType,
+                                                                       true
+                                                               );
+                                                               
window.location.href = $primaryLink.attr( 'href' );
+                                                       } );
+                                               }
+                                               // Log notification impression
+                                               mw.echo.logger.logInteraction(
+                                                       
mw.echo.Logger.static.actions.notificationImpression,
+                                                       'mobile-overlay',
+                                                       eventId,
+                                                       eventType,
+                                                       true
+                                               );
+                                       } );
+                                       // Only fire 'mark as read' API call 
when unread notification
+                                       // count is not zero.  Question: why 
does this fire an API call
+                                       // for 'mark all as read', the overlay 
may not load all unread
+                                       // notifications
+                                       if ( 
result.query.notifications.rawcount !== 0 ) {
+                                               self.markAllAsRead();
+                                       }
+                               } else {
+                                       self.onError();
+                               }
+                       } ).fail( function () {
+                               self.onError();
+                       } );
+               }
+       }
+
+       OO.mfExtend( NotificationsOverlay, Overlay, {
                className: 'overlay notifications-overlay navigation-drawer',
                templatePartials: $.extend( {}, 
Overlay.prototype.templatePartials, {
                        content: mw.template.get( 
'mobile.notifications.overlay', 'content.hogan' )
@@ -42,86 +121,6 @@
                 */
                markAsRead: function () {
                        this.$badge.find( '.notification-count' ).remove();
-               },
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       var self = this;
-                       Overlay.prototype.initialize.apply( this, options );
-                       // Anchor tag that corresponds to a notifications badge
-                       this.$badge = options.$badge;
-                       // On error use the url as a fallback
-                       if ( options.error ) {
-                               this.onError();
-                       } else {
-                               // FIXME: Move to NotificationApi class
-                               api.get( {
-                                       action: 'query',
-                                       meta: 'notifications',
-                                       notformat: 'flyout',
-                                       notprop: 'index|list|count',
-                                       uselang: 'user'
-                               } ).done( function ( result ) {
-                                       var notifications;
-                                       if ( result.query && 
result.query.notifications ) {
-                                               notifications = $.map( 
result.query.notifications.list, function ( a ) {
-                                                       return {
-                                                               message: a['*'],
-                                                               timestamp: 
a.timestamp.mw,
-                                                               unread: ( 
a.hasOwnProperty( 'read' ) ? 'mw-echo-notification-read' : 
'mw-echo-notification-unread' )
-                                                       };
-                                               } ).sort( function ( a, b ) {
-                                                       return a.timestamp < 
b.timestamp ? 1 : -1;
-                                               } );
-                                               if ( notifications.length ) {
-                                                       options.notifications = 
notifications;
-                                               } else {
-                                                       options.errorMessage = 
mw.msg( 'echo-none' );
-                                               }
-
-                                               self.render( options );
-                                               self.$( '.mw-echo-notification' 
).each( function () {
-                                                       var $notification = $( 
this ),
-                                                               $primaryLink = 
$notification.find( '.mw-echo-notification-primary-link' ),
-                                                               eventId = 
$notification.attr( 'data-notification-event' ),
-                                                               eventType = 
$notification.attr( 'data-notification-type' );
-
-                                                       // If there is a 
primary link, make the entire notification clickable.
-                                                       if ( 
$primaryLink.length ) {
-                                                               
$notification.addClass( 'mw-echo-linked-notification' );
-                                                               
$notification.on( 'click', function () {
-                                                                       
mw.echo.logger.logInteraction(
-                                                                               
mw.echo.Logger.static.actions.notificationClick,
-                                                                               
'mobile-overlay',
-                                                                               
eventId,
-                                                                               
eventType,
-                                                                               
true
-                                                                       );
-                                                                       
window.location.href = $primaryLink.attr( 'href' );
-                                                               } );
-                                                       }
-                                                       // Log notification 
impression
-                                                       
mw.echo.logger.logInteraction(
-                                                               
mw.echo.Logger.static.actions.notificationImpression,
-                                                               
'mobile-overlay',
-                                                               eventId,
-                                                               eventType,
-                                                               true
-                                                       );
-                                               } );
-                                               // Only fire 'mark as read' API 
call when unread notification
-                                               // count is not zero.  
Question: why does this fire an API call
-                                               // for 'mark all as read', the 
overlay may not load all unread
-                                               // notifications
-                                               if ( 
result.query.notifications.rawcount !== 0 ) {
-                                                       self.markAllAsRead();
-                                               }
-                                       } else {
-                                               self.onError();
-                                       }
-                               } ).fail( function () {
-                                       self.onError();
-                               } );
-                       }
                },
                /**
                 * Mark notifications as read in the server. Make an API 
request.
diff --git a/resources/mobile.overlays/ContentOverlay.js 
b/resources/mobile.overlays/ContentOverlay.js
index eb90519..b09c0ce 100644
--- a/resources/mobile.overlays/ContentOverlay.js
+++ b/resources/mobile.overlays/ContentOverlay.js
@@ -1,7 +1,6 @@
 ( function ( M ) {
 
-       var ContentOverlay,
-               mContentOverlay,
+       var mContentOverlay,
                Overlay = M.require( 'mobile.overlays/Overlay' );
 
        /**
@@ -10,7 +9,11 @@
         * @class ContentOverlay
         * @extends Overlay
         */
-       ContentOverlay = Overlay.extend( {
+       function ContentOverlay() {
+               ContentOverlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( ContentOverlay, Overlay, {
                /** @inheritdoc */
                templatePartials: {},
                className: 'overlay content-overlay',
diff --git a/resources/mobile.overlays/LoadingOverlay.js 
b/resources/mobile.overlays/LoadingOverlay.js
index bfc9ac9..12ae158 100644
--- a/resources/mobile.overlays/LoadingOverlay.js
+++ b/resources/mobile.overlays/LoadingOverlay.js
@@ -1,14 +1,17 @@
 ( function ( M ) {
-       var LoadingOverlay,
-               Overlay = M.require( 'mobile.overlays/Overlay' );
+       var Overlay = M.require( 'mobile.overlays/Overlay' );
 
        /**
         * Overlay that initially shows loading animation until
-        ** caller hides it with .hide()
+        * caller hides it with .hide()
         * @class LoadingOverlay
         * @extends Overlay
         */
-       LoadingOverlay = Overlay.extend( {
+       function LoadingOverlay() {
+               Overlay.apply( this, arguments );
+       }
+
+       OO.mfExtend( LoadingOverlay, Overlay, {
                template: mw.template.get( 'mobile.overlays', 
'LoadingOverlay.hogan' )
        } );
 
diff --git a/resources/mobile.overlays/Overlay.js 
b/resources/mobile.overlays/Overlay.js
index d1c008e..6822f21 100644
--- a/resources/mobile.overlays/Overlay.js
+++ b/resources/mobile.overlays/Overlay.js
@@ -1,15 +1,13 @@
 /*jshint unused:vars */
 ( function ( M, $ ) {
 
-       var
-               View = M.require( 'mobile.view/View' ),
+       var View = M.require( 'mobile.view/View' ),
                Icon = M.require( 'mobile.startup/Icon' ),
                Button = M.require( 'mobile.startup/Button' ),
                Anchor = M.require( 'mobile.startup/Anchor' ),
                icons = M.require( 'mobile.startup/icons' ),
                browser = M.require( 'mobile.browser/browser' ),
-               $window = $( window ),
-               Overlay;
+               $window = $( window );
 
        /**
         * Mobile modal window
@@ -18,7 +16,18 @@
         * @uses Icon
         * @uses Button
         */
-       Overlay = View.extend( {
+       function Overlay() {
+               this.isIos = browser.isIos();
+               this.isIos8 = browser.isIos( 8 );
+               // https://phabricator.wikimedia.org/T106934
+               // tldr: closing keyboard doesn't trigger a blur event
+               if ( this.isIos8 ) {
+                       this.hasFixedHeader = false;
+               }
+               View.apply( this, arguments );
+       }
+
+       OO.mfExtend( Overlay, View, {
                /**
                 * Identify whether the element contains position fixed elements
                 * @property {Boolean}
@@ -105,17 +114,6 @@
                        this.$spinner.addClass( 'hidden' );
                },
 
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       this.isIos = browser.isIos();
-                       this.isIos8 = browser.isIos( 8 );
-                       // https://phabricator.wikimedia.org/T106934
-                       // tldr: closing keyboard doesn't trigger a blur event
-                       if ( this.isIos8 ) {
-                               this.hasFixedHeader = false;
-                       }
-                       View.prototype.initialize.apply( this, arguments );
-               },
                /** @inheritdoc */
                postRender: function () {
                        var self = this;
diff --git a/resources/mobile.pagelist.scripts/WatchstarPageList.js 
b/resources/mobile.pagelist.scripts/WatchstarPageList.js
index 0dc412a..9c6046c 100644
--- a/resources/mobile.pagelist.scripts/WatchstarPageList.js
+++ b/resources/mobile.pagelist.scripts/WatchstarPageList.js
@@ -1,7 +1,6 @@
 ( function ( M, $ ) {
 
-       var WatchstarPageList,
-               mWatchstar,
+       var mWatchstar,
                PageList = M.require( 'mobile.pagelist/PageList' ),
                Watchstar = M.require( 'mobile.watchstar/Watchstar' ),
                user = M.require( 'mobile.user/user' ),
@@ -16,19 +15,17 @@
         * @uses Watchstar
         * @extends View
         */
-       WatchstarPageList = PageList.extend( {
+       function WatchstarPageList( options ) {
+               this.wsGateway = new WatchstarGateway( options.api );
+               PageList.apply( this, arguments );
+       }
+
+       OO.mfExtend( WatchstarPageList, PageList, {
                /**
                 * @inheritdoc
                 * @cfg {Object} defaults Default options hash.
                 * @cfg {mw.Api} defaults.api
                 */
-               /**
-                * @inheritdoc
-                */
-               initialize: function ( options ) {
-                       this.wsGateway = new WatchstarGateway( options.api );
-                       PageList.prototype.initialize.apply( this, arguments );
-               },
                /**
                 * Retrieve pages
                 *
diff --git a/resources/mobile.pagelist/PageList.js 
b/resources/mobile.pagelist/PageList.js
index 1d09656..4c5d785 100644
--- a/resources/mobile.pagelist/PageList.js
+++ b/resources/mobile.pagelist/PageList.js
@@ -1,7 +1,6 @@
 ( function ( M, $ ) {
 
-       var PageList,
-               View = M.require( 'mobile.view/View' ),
+       var View = M.require( 'mobile.view/View' ),
                browser = M.require( 'mobile.browser/browser' );
 
        /**
@@ -9,7 +8,11 @@
         * @class PageList
         * @extends View
         */
-       PageList = View.extend( {
+       function PageList() {
+               View.apply( this, arguments );
+       }
+
+       OO.mfExtend( PageList, View, {
                /**
                 * @cfg {Object} defaults Default options hash.
                 * @cfg {Boolean} defaults.imagesDisabled whether to show 
images or not.
diff --git a/resources/mobile.references/ReferencesDrawer.js 
b/resources/mobile.references/ReferencesDrawer.js
index 0c3a14f..12b20f4 100644
--- a/resources/mobile.references/ReferencesDrawer.js
+++ b/resources/mobile.references/ReferencesDrawer.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var ReferencesDrawer,
-               Drawer = M.require( 'mobile.drawers/Drawer' ),
+       var Drawer = M.require( 'mobile.drawers/Drawer' ),
                Icon = M.require( 'mobile.startup/Icon' ),
                SchemaMobileWebUIClickTracking = M.require(
                        'mobile.loggingSchemas/SchemaMobileWebUIClickTracking' 
),
@@ -12,7 +11,11 @@
         * @extends Drawer
         * @uses Icon
         */
-       ReferencesDrawer = Drawer.extend( {
+       function ReferencesDrawer() {
+               Drawer.apply( this, arguments );
+       }
+
+       OO.mfExtend( ReferencesDrawer, Drawer, {
                /**
                 * @cfg {Object} defaults Default options hash.
                 * @cfg {String} defaults.cancelButton HTML of the button that 
closes the drawer.
diff --git a/resources/mobile.search/SearchOverlay.js 
b/resources/mobile.search/SearchOverlay.js
index 5283b0a..4d9553c 100644
--- a/resources/mobile.search/SearchOverlay.js
+++ b/resources/mobile.search/SearchOverlay.js
@@ -8,8 +8,7 @@
                SEARCH_DELAY = 300,
                $html = $( 'html' ),
                router = M.require( 'mobile.startup/router' ),
-               feedbackLink = mw.config.get( 'wgCirrusSearchFeedbackLink' ),
-               SearchOverlay;
+               feedbackLink = mw.config.get( 'wgCirrusSearchFeedbackLink' );
 
        /**
         * Overlay displaying search results
@@ -18,7 +17,20 @@
         * @uses SearchGateway
         * @uses Icon
         */
-       SearchOverlay = Overlay.extend( {
+       function SearchOverlay( options ) {
+               var self = this;
+               Overlay.call( this, options );
+               this.api = options.api;
+               this.gateway = new options.gatewayClass( this.api );
+
+               // FIXME: Remove when search registers route with overlay 
manager
+               // we need this because of the focus/delay hack in search.js
+               router.once( 'route', function () {
+                       self._hideOnRoute();
+               } );
+       }
+
+       OO.mfExtend( SearchOverlay, Overlay, {
                templatePartials: $.extend( {}, 
Overlay.prototype.templatePartials, {
                        anchor: Anchor.prototype.template,
                        icon: Icon.prototype.template
@@ -97,20 +109,6 @@
                                        ev.preventDefault();
                                        self._hideOnRoute();
                                }
-                       } );
-               },
-
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       var self = this;
-                       Overlay.prototype.initialize.call( this, options );
-                       this.api = options.api;
-                       this.gateway = new options.gatewayClass( this.api );
-
-                       // FIXME: Remove when search registers route with 
overlay manager
-                       // we need this because of the focus/delay hack in 
search.js
-                       router.once( 'route', function () {
-                               self._hideOnRoute();
                        } );
                },
 
diff --git a/resources/mobile.special.mobileoptions.scripts/mobileoptions.js 
b/resources/mobile.special.mobileoptions.scripts/mobileoptions.js
index b46ca07..438de06 100644
--- a/resources/mobile.special.mobileoptions.scripts/mobileoptions.js
+++ b/resources/mobile.special.mobileoptions.scripts/mobileoptions.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var Checkbox,
-               context = M.require( 'mobile.context/context' ),
+       var context = M.require( 'mobile.context/context' ),
                FontChanger = M.require( 'mobile.fontchanger/FontChanger' ),
                View = M.require( 'mobile.view/View' ),
                settings = M.require( 'mobile.settings/settings' );
@@ -10,7 +9,11 @@
         * @class Checkbox
         * @extends View
         */
-       Checkbox = View.extend( {
+       function Checkbox() {
+               View.apply( this, arguments );
+       }
+
+       OO.mfExtend( Checkbox, View, {
                template: mw.template.get( 
'mobile.special.mobileoptions.scripts', 'Checkbox.hogan' ),
                /**
                 * Save the current state of the checkbox to the settings
diff --git a/resources/mobile.startup/Anchor.js 
b/resources/mobile.startup/Anchor.js
index e987cbc..b7cdb6d 100644
--- a/resources/mobile.startup/Anchor.js
+++ b/resources/mobile.startup/Anchor.js
@@ -1,14 +1,17 @@
 ( function ( M ) {
 
-       var Anchor,
-               View = M.require( 'mobile.view/View' );
+       var View = M.require( 'mobile.view/View' );
 
        /**
         * A wrapper for creating an anchor.
         * @class Anchor
         * @extends View
         */
-       Anchor = View.extend( {
+       function Anchor() {
+               View.apply( this, arguments );
+       }
+
+       OO.mfExtend( Anchor, View, {
                /** @inheritdoc */
                isTemplateMode: true,
                /**
diff --git a/resources/mobile.startup/Button.js 
b/resources/mobile.startup/Button.js
index c1f2485..4cb799e 100644
--- a/resources/mobile.startup/Button.js
+++ b/resources/mobile.startup/Button.js
@@ -1,14 +1,20 @@
 ( function ( M ) {
 
-       var Button,
-               View = M.require( 'mobile.view/View' );
+       var View = M.require( 'mobile.view/View' );
 
        /**
         * A wrapper for creating a button.
         * @class Button
         * @extends View
         */
-       Button = View.extend( {
+       function Button( options ) {
+               if ( options.href ) {
+                       options.tagName = 'a';
+               }
+               View.call( this, options );
+       }
+
+       OO.mfExtend( Button, View, {
                /** @inheritdoc */
                isTemplateMode: true,
                /**
@@ -33,13 +39,6 @@
                        additionalClassNames: '',
                        href: undefined,
                        label: undefined
-               },
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       if ( options.href ) {
-                               options.tagName = 'a';
-                       }
-                       View.prototype.initialize.call( this, options );
                },
                template: mw.template.get( 'mobile.startup', 'button.hogan' )
        } );
diff --git a/resources/mobile.startup/Icon.js b/resources/mobile.startup/Icon.js
index ce03dfb..6f6de07 100644
--- a/resources/mobile.startup/Icon.js
+++ b/resources/mobile.startup/Icon.js
@@ -1,14 +1,23 @@
 ( function ( M, $ ) {
 
-       var View = M.require( 'mobile.view/View' ),
-               Icon;
+       var View = M.require( 'mobile.view/View' );
 
        /**
         * A wrapper for creating an icon.
         * @class Icon
         * @extends View
         */
-       Icon = View.extend( {
+       function Icon( options ) {
+               if ( options.hasText ) {
+                       options.modifier = 'mw-ui-icon-before';
+               }
+               if ( options.href ) {
+                       options.tagName = 'a';
+               }
+               View.call( this, options );
+       }
+
+       OO.mfExtend( Icon, View, {
                /** @inheritdoc */
                isTemplateMode: true,
                /**
@@ -47,16 +56,6 @@
                 */
                getGlyphClassName: function () {
                        return this.options.base + '-' + this.options.name;
-               },
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       if ( options.hasText ) {
-                               options.modifier = 'mw-ui-icon-before';
-                       }
-                       if ( options.href ) {
-                               options.tagName = 'a';
-                       }
-                       View.prototype.initialize.call( this, options );
                },
                /**
                 * Return the HTML representation of this view
diff --git a/resources/mobile.startup/Page.js b/resources/mobile.startup/Page.js
index 1fc513b..eedc3d1 100644
--- a/resources/mobile.startup/Page.js
+++ b/resources/mobile.startup/Page.js
@@ -1,7 +1,6 @@
 ( function ( HTML, M, $ ) {
 
-       var Page,
-               time = M.require( 'mobile.modifiedBar/time' ),
+       var time = M.require( 'mobile.modifiedBar/time' ),
                View = M.require( 'mobile.view/View' ),
                Section = M.require( 'mobile.startup/Section' ),
                Thumbnail = M.require( 'mobile.startup/Thumbnail' );
@@ -13,7 +12,29 @@
         * @uses Section
         * @extends View
         */
-       Page = View.extend( {
+       function Page( options ) {
+               var thumb;
+               this.options = options;
+               options.languageUrl = mw.util.getUrl( 
'Special:MobileLanguages/' + options.title );
+               View.call( this, options );
+               // Fallback if no displayTitle provided
+               options.displayTitle = this.getDisplayTitle();
+               // allow usage in templates.
+               // FIXME: Should View map all options to properties?
+               this.title = options.title;
+               this.displayTitle = options.displayTitle;
+               this.thumbnail = options.thumbnail;
+               this.url = options.url || mw.util.getUrl( options.title );
+               this.id = options.id;
+               this.isMissing = options.isMissing;
+               thumb = this.thumbnail;
+               if ( thumb && thumb.width ) {
+                       this.thumbnail.isLandscape = thumb.width > thumb.height;
+               }
+               this.wikidataDescription = options.wikidataDescription;
+       }
+
+       OO.mfExtend( Page, View, {
                /**
                 * @cfg {Object} defaults Default options hash.
                 * @cfg {Number} defaults.id Page ID. The default value of 0 
represents a new page.
@@ -59,31 +80,6 @@
                 * @inheritdoc
                 */
                isBorderBox: false,
-               /**
-                * @inheritdoc
-                */
-               initialize: function ( options ) {
-                       var thumb;
-
-                       this.options = options;
-                       options.languageUrl = mw.util.getUrl( 
'Special:MobileLanguages/' + options.title );
-                       View.prototype.initialize.apply( this, arguments );
-                       // Fallback if no displayTitle provided
-                       options.displayTitle = this.getDisplayTitle();
-                       // allow usage in templates.
-                       // FIXME: Should View map all options to properties?
-                       this.title = options.title;
-                       this.displayTitle = options.displayTitle;
-                       this.thumbnail = options.thumbnail;
-                       this.url = options.url || mw.util.getUrl( options.title 
);
-                       this.id = options.id;
-                       this.isMissing = options.isMissing;
-                       thumb = this.thumbnail;
-                       if ( thumb && thumb.width ) {
-                               this.thumbnail.isLandscape = thumb.width > 
thumb.height;
-                       }
-                       this.wikidataDescription = options.wikidataDescription;
-               },
                /**
                 * Retrieve the title that should be displayed to the user
                 * @method
diff --git a/resources/mobile.startup/Panel.js 
b/resources/mobile.startup/Panel.js
index f25f0c2..1bd2078 100644
--- a/resources/mobile.startup/Panel.js
+++ b/resources/mobile.startup/Panel.js
@@ -1,14 +1,17 @@
 ( function ( M ) {
 
-       var View = M.require( 'mobile.view/View' ),
-               Panel;
+       var View = M.require( 'mobile.view/View' );
 
        /**
         * An abstract class for a {@link View} that comprises a simple panel.
         * @class Panel
         * @extends View
         */
-       Panel = View.extend( {
+       function Panel() {
+               View.apply( this, arguments );
+       }
+
+       OO.mfExtend( Panel, View, {
                /** @inheritdoc */
                className: 'panel',
                // in milliseconds
diff --git a/resources/mobile.startup/Schema.js 
b/resources/mobile.startup/Schema.js
index 40b556b..bc04eea 100644
--- a/resources/mobile.startup/Schema.js
+++ b/resources/mobile.startup/Schema.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var Class = M.require( 'mobile.oo/Class' ),
-               settings = M.require( 'mobile.settings/settings' ),
+       var settings = M.require( 'mobile.settings/settings' ),
                BEACON_SETTING_KEY = 'mobileFrontend/beacon';
 
        /**
@@ -168,10 +167,6 @@
 
                deleteBeacon();
        };
-       // FIXME: Needed to give time for Gather to update
-       Schema.extend = Class.extend;
-       mw.log.deprecate( Schema, 'extend', Schema.extend,
-               'Schema.extend is deprecated. Do not use this. Use OO.mfExtend' 
);
 
        M.define( 'mobile.startup/Schema', Schema );
 
diff --git a/resources/mobile.startup/Section.js 
b/resources/mobile.startup/Section.js
index 5ee523d..e11130b 100644
--- a/resources/mobile.startup/Section.js
+++ b/resources/mobile.startup/Section.js
@@ -1,7 +1,6 @@
 ( function ( M, $ ) {
 
        var View = M.require( 'mobile.view/View' ),
-               Section,
                icons = M.require( 'mobile.startup/icons' );
 
        /**
@@ -9,7 +8,22 @@
         * @class Section
         * @extends View
         */
-       Section = View.extend( {
+       function Section( options ) {
+               var self = this;
+               options.tag = 'h' + options.level;
+               this.line = options.line;
+               this.text = options.text;
+               this.hasReferences = options.hasReferences || false;
+               this.id = options.id || null;
+               this.anchor = options.anchor;
+               this.children = [];
+               $.each( options.children || [], function () {
+                       self.children.push( new Section( this ) );
+               } );
+               View.call( this, options );
+       }
+
+       OO.mfExtend( Section, View, {
                template: mw.template.get( 'mobile.startup', 'Section.hogan' ),
                /**
                 * @cfg {Object} defaults Default options hash.
@@ -20,21 +34,6 @@
                        line: undefined,
                        text: '',
                        spinner: icons.spinner().toHtmlString()
-               },
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       var self = this;
-                       options.tag = 'h' + options.level;
-                       this.line = options.line;
-                       this.text = options.text;
-                       this.hasReferences = options.hasReferences || false;
-                       this.id = options.id || null;
-                       this.anchor = options.anchor;
-                       this.children = [];
-                       $.each( options.children || [], function () {
-                               self.children.push( new Section( this ) );
-                       } );
-                       View.prototype.initialize.apply( self, arguments );
                }
        } );
        M.define( 'mobile.startup/Section', Section );
diff --git a/resources/mobile.startup/Skin.js b/resources/mobile.startup/Skin.js
index 0d5c195..c2a06d1 100644
--- a/resources/mobile.startup/Skin.js
+++ b/resources/mobile.startup/Skin.js
@@ -1,7 +1,6 @@
 ( function ( M, $ ) {
 
-       var Skin,
-               browser = M.require( 'mobile.browser/browser' ),
+       var browser = M.require( 'mobile.browser/browser' ),
                View = M.require( 'mobile.view/View' );
 
        /**
@@ -12,7 +11,39 @@
         * @uses Browser
         * @uses Page
         */
-       Skin = View.extend( {
+       function Skin( options ) {
+               var self = this;
+
+               this.page = options.page;
+               this.name = options.name;
+               this.mainMenu = options.mainMenu;
+               View.call( this, options );
+               // Must be run after merging with defaults as must be defined.
+               this.tabletModules = options.tabletModules;
+
+               /**
+                * Tests current window size and if suitable loads styles and 
scripts specific for larger devices
+                *
+                * @method
+                * @ignore
+                */
+               function loadWideScreenModules() {
+                       if ( browser.isWideScreen() ) {
+                               // Adjust screen for tablets
+                               if ( self.page.inNamespace( '' ) ) {
+                                       mw.loader.using( self.tabletModules 
).always( function () {
+                                               self.off( '_resize' );
+                                               self.emit.call( self, 'changed' 
);
+                                       } );
+                               }
+                       }
+               }
+               M.on( 'resize', $.proxy( this, 'emit', '_resize' ) );
+               this.on( '_resize', loadWideScreenModules );
+               this.emit( '_resize' );
+       }
+
+       OO.mfExtend( Skin, View, {
                /**
                 * @inheritdoc
                 * Skin contains components that we do not control
@@ -91,40 +122,6 @@
                                        $el.add( '.overlay' ).height( 
scrollBottom );
                                }
                        } );
-               },
-               /**
-                * @inheritdoc
-                */
-               initialize: function ( options ) {
-                       var self = this;
-
-                       this.page = options.page;
-                       this.name = options.name;
-                       this.mainMenu = options.mainMenu;
-                       View.prototype.initialize.apply( this, arguments );
-                       // Must be run after merging with defaults as must be 
defined.
-                       this.tabletModules = options.tabletModules;
-
-                       /**
-                        * Tests current window size and if suitable loads 
styles and scripts specific for larger devices
-                        *
-                        * @method
-                        * @ignore
-                        */
-                       function loadWideScreenModules() {
-                               if ( browser.isWideScreen() ) {
-                                       // Adjust screen for tablets
-                                       if ( self.page.inNamespace( '' ) ) {
-                                               mw.loader.using( 
self.tabletModules ).always( function () {
-                                                       self.off( '_resize' );
-                                                       self.emit.call( self, 
'changed' );
-                                               } );
-                                       }
-                               }
-                       }
-                       M.on( 'resize', $.proxy( this, 'emit', '_resize' ) );
-                       this.on( '_resize', loadWideScreenModules );
-                       this.emit( '_resize' );
                },
                /**
                 * @inheritdoc
diff --git a/resources/mobile.startup/Thumbnail.js 
b/resources/mobile.startup/Thumbnail.js
index df7efce..ad6b9a8 100644
--- a/resources/mobile.startup/Thumbnail.js
+++ b/resources/mobile.startup/Thumbnail.js
@@ -1,8 +1,6 @@
 ( function ( M ) {
 
-       var
-               View = M.require( 'mobile.view/View' ),
-               Thumbnail;
+       var View = M.require( 'mobile.view/View' );
 
        /**
         * Representation of a thumbnail
@@ -10,7 +8,10 @@
         * @class Thumbnail
         * @extends View
         */
-       Thumbnail = View.extend( {
+       function Thumbnail() {
+               View.apply( this, arguments );
+       }
+       OO.mfExtend( Thumbnail, View, {
                /**
                 * @cfg {Object} defaults options
                 * @cfg {String} defaults.filename uri decoded filename 
including File: prefix associated with thumbnail
diff --git a/resources/mobile.talk.overlays/TalkOverlay.js 
b/resources/mobile.talk.overlays/TalkOverlay.js
index 6ce403c..4a388a0 100644
--- a/resources/mobile.talk.overlays/TalkOverlay.js
+++ b/resources/mobile.talk.overlays/TalkOverlay.js
@@ -1,154 +1,157 @@
 ( function ( M, $ ) {
-       var
-               TalkOverlayBase = M.require( 
'mobile.talk.overlays/TalkOverlayBase' ),
+       var TalkOverlayBase = M.require( 'mobile.talk.overlays/TalkOverlayBase' 
),
                Page = M.require( 'mobile.startup/Page' ),
                Anchor = M.require( 'mobile.startup/Anchor' ),
-               user = M.require( 'mobile.user/user' ),
+               user = M.require( 'mobile.user/user' );
+       /**
+        * Overlay for talk page
+        * @extends Overlay
+        * @class TalkOverlay
+        * @uses Page
+        * @uses TalkSectionOverlay
+        * @uses TalkSectionAddOverlay
+        */
+       function TalkOverlay() {
+               TalkOverlayBase.apply( this, arguments );
+       }
+
+       OO.mfExtend( TalkOverlay, TalkOverlayBase, {
+               templatePartials: $.extend( {}, 
TalkOverlayBase.prototype.templatePartials, {
+                       content: mw.template.get( 'mobile.talk.overlays', 
'content.hogan' )
+               } ),
                /**
-                * Overlay for talk page
-                * @extends Overlay
-                * @class TalkOverlay
-                * @uses Page
-                * @uses TalkSectionOverlay
-                * @uses TalkSectionAddOverlay
+                * @inheritdoc
+                * @cfg {Object} defaults Default options hash.
+                * @cfg {Array} defaults.headings A list of {Section} objects 
to render heading links
+                * for. If not set ajax request will be performed.
+                * @cfg {String} defaults.heading Heading for talk overlay.
+                * @cfg {String} defaults.leadHeading Heading for a discussion 
which has no heading
+                * (lead section of talk page).
+                * @cfg {String} defaults.headerButtonsListClassName Class name 
of the header buttons
+                * list
+                * @cfg {Array} defaults.headerButtons Objects that will be 
used as defaults for
+                * generating header buttons. Default list includes an 'add' 
button, which opens
+                * a new talk overlay.
                 */
-               TalkOverlay = TalkOverlayBase.extend( {
-                       templatePartials: $.extend( {}, 
TalkOverlayBase.prototype.templatePartials, {
-                               content: mw.template.get( 
'mobile.talk.overlays', 'content.hogan' )
-                       } ),
-                       /**
-                        * @inheritdoc
-                        * @cfg {Object} defaults Default options hash.
-                        * @cfg {Array} defaults.headings A list of {Section} 
objects to render heading links
-                        * for. If not set ajax request will be performed.
-                        * @cfg {String} defaults.heading Heading for talk 
overlay.
-                        * @cfg {String} defaults.leadHeading Heading for a 
discussion which has no heading
-                        * (lead section of talk page).
-                        * @cfg {String} defaults.headerButtonsListClassName 
Class name of the header buttons
-                        * list
-                        * @cfg {Array} defaults.headerButtons Objects that 
will be used as defaults for
-                        * generating header buttons. Default list includes an 
'add' button, which opens
-                        * a new talk overlay.
-                        */
-                       defaults: $.extend( {}, 
TalkOverlayBase.prototype.defaults, {
-                               headings: undefined,
-                               heading: '<strong>' + mw.msg( 
'mobile-frontend-talk-overlay-header' ) + '</strong>',
-                               leadHeading: mw.msg( 
'mobile-frontend-talk-overlay-lead-header' ),
-                               headerButtonsListClassName: 'overlay-action',
-                               headerButtons: [ {
-                                       href: '#/talk/new',
-                                       className: 'add continue hidden',
-                                       msg: mw.msg( 
'mobile-frontend-talk-add-overlay-submit' )
-                               } ],
-                               footerAnchor: new Anchor( {
-                                       progressive: true,
-                                       additionalClassNames: 'footer-link 
talk-fullpage',
-                                       label: mw.msg( 
'mobile-frontend-talk-fullpage' )
-                               } ).options
-                       } ),
+               defaults: $.extend( {}, TalkOverlayBase.prototype.defaults, {
+                       headings: undefined,
+                       heading: '<strong>' + mw.msg( 
'mobile-frontend-talk-overlay-header' ) + '</strong>',
+                       leadHeading: mw.msg( 
'mobile-frontend-talk-overlay-lead-header' ),
+                       headerButtonsListClassName: 'overlay-action',
+                       headerButtons: [ {
+                               href: '#/talk/new',
+                               className: 'add continue hidden',
+                               msg: mw.msg( 
'mobile-frontend-talk-add-overlay-submit' )
+                       } ],
+                       footerAnchor: new Anchor( {
+                               progressive: true,
+                               additionalClassNames: 'footer-link 
talk-fullpage',
+                               label: mw.msg( 'mobile-frontend-talk-fullpage' )
+                       } ).options
+               } ),
 
-                       /** @inheritdoc */
-                       postRender: function () {
-                               TalkOverlayBase.prototype.postRender.apply( 
this );
-                               this.$board = this.$( '.board' );
-                               this.$( '.talk-fullpage' ).attr( 'href', 
mw.util.getUrl( this.options.title ) )
-                                       .removeClass( 'hidden' );
-                               if ( !this.options.headings ) {
-                                       this._loadContent( this.options );
-                               }
-                               this._setupAddDiscussionButton( this.options );
-                               this.showHidden( '.initial-header' );
-                       },
-
-                       /**
-                        * Show a loading spinner
-                        * @method
-                        */
-                       showSpinner: function () {
-                               this.$board.hide();
-                               TalkOverlayBase.prototype.showSpinner.apply( 
this, arguments );
-                       },
-
-                       /**
-                        * Hide the loading spinner
-                        * @method
-                        */
-                       clearSpinner: function () {
-                               TalkOverlayBase.prototype.clearSpinner.apply( 
this, arguments );
-                               this.$board.show();
-                       },
-
-                       /**
-                        * Load content of the talk page into the overlay
-                        * @method
-                        * @param {Object} options for the overlay
-                        * @private
-                        */
-                       _loadContent: function ( options ) {
-                               var self = this;
-
-                               // show a spinner
-                               this.showSpinner();
-
-                               // clear actual content, if any
-                               this.$( '.topic-title-list' ).empty();
-
-                               this.pageGateway.getPage( options.title ).fail( 
function ( resp ) {
-                                       // If the API returns the error code 
'missingtitle', that means the
-                                       // talk page doesn't exist yet.
-                                       if ( resp === 'missingtitle' ) {
-                                               // Create an empty page for new 
pages
-                                               self._addContent( {
-                                                       title: options.title,
-                                                       sections: []
-                                               }, options );
-                                       } else {
-                                               // If the API request fails for 
any other reason, load the talk
-                                               // page manually rather than 
leaving the spinner spinning.
-                                               window.location = 
mw.util.getUrl( options.title );
-                                       }
-                               } ).done( function ( pageData ) {
-                                       self._addContent( pageData, options );
-                               } );
-                       },
-
-                       /**
-                        * Adds the content received from _loadContent to the 
Overlay and re-renders it.
-                        * @method
-                        * @private
-                        * @param {Object} pageData As returned from 
PageApi#getPage
-                        * @param {Object} options for the overlay
-                        */
-                       _addContent: function ( pageData, options ) {
-                               var page = new Page( pageData ),
-                                       sections = page.getSections();
-
-                               this.page = page;
-
-                               options.explanation = sections.length > 0 ? 
mw.msg( 'mobile-frontend-talk-explained' ) :
-                                       mw.msg( 
'mobile-frontend-talk-explained-empty' );
-                               options.headings = sections;
-
-                               // content is there so re-render and hide the 
spinner
-                               this.render( options );
-                               this.clearSpinner();
-                       },
-                       /**
-                        * Shows the add topic button to logged in users.
-                        * Ensures the overlay refreshes when a discussion is 
added.
-                        * @method
-                        * @private
-                        */
-                       _setupAddDiscussionButton: function () {
-                               var $add = this.$( '.overlay-action .add' );
-                               M.on( 'talk-discussion-added', $.proxy( this, 
'_loadContent', this.options ) );
-                               if ( !user.isAnon() ) {
-                                       $add.removeClass( 'hidden' );
-                               } else {
-                                       $add.remove();
-                               }
+               /** @inheritdoc */
+               postRender: function () {
+                       TalkOverlayBase.prototype.postRender.apply( this );
+                       this.$board = this.$( '.board' );
+                       this.$( '.talk-fullpage' ).attr( 'href', 
mw.util.getUrl( this.options.title ) )
+                               .removeClass( 'hidden' );
+                       if ( !this.options.headings ) {
+                               this._loadContent( this.options );
                        }
-               } );
+                       this._setupAddDiscussionButton( this.options );
+                       this.showHidden( '.initial-header' );
+               },
+
+               /**
+                * Show a loading spinner
+                * @method
+                */
+               showSpinner: function () {
+                       this.$board.hide();
+                       TalkOverlayBase.prototype.showSpinner.apply( this, 
arguments );
+               },
+
+               /**
+                * Hide the loading spinner
+                * @method
+                */
+               clearSpinner: function () {
+                       TalkOverlayBase.prototype.clearSpinner.apply( this, 
arguments );
+                       this.$board.show();
+               },
+
+               /**
+                * Load content of the talk page into the overlay
+                * @method
+                * @param {Object} options for the overlay
+                * @private
+                */
+               _loadContent: function ( options ) {
+                       var self = this;
+
+                       // show a spinner
+                       this.showSpinner();
+
+                       // clear actual content, if any
+                       this.$( '.topic-title-list' ).empty();
+
+                       this.pageGateway.getPage( options.title ).fail( 
function ( resp ) {
+                               // If the API returns the error code 
'missingtitle', that means the
+                               // talk page doesn't exist yet.
+                               if ( resp === 'missingtitle' ) {
+                                       // Create an empty page for new pages
+                                       self._addContent( {
+                                               title: options.title,
+                                               sections: []
+                                       }, options );
+                               } else {
+                                       // If the API request fails for any 
other reason, load the talk
+                                       // page manually rather than leaving 
the spinner spinning.
+                                       window.location = mw.util.getUrl( 
options.title );
+                               }
+                       } ).done( function ( pageData ) {
+                               self._addContent( pageData, options );
+                       } );
+               },
+
+               /**
+                * Adds the content received from _loadContent to the Overlay 
and re-renders it.
+                * @method
+                * @private
+                * @param {Object} pageData As returned from PageApi#getPage
+                * @param {Object} options for the overlay
+                */
+               _addContent: function ( pageData, options ) {
+                       var page = new Page( pageData ),
+                               sections = page.getSections();
+
+                       this.page = page;
+
+                       options.explanation = sections.length > 0 ? mw.msg( 
'mobile-frontend-talk-explained' ) :
+                               mw.msg( 'mobile-frontend-talk-explained-empty' 
);
+                       options.headings = sections;
+
+                       // content is there so re-render and hide the spinner
+                       this.render( options );
+                       this.clearSpinner();
+               },
+               /**
+                * Shows the add topic button to logged in users.
+                * Ensures the overlay refreshes when a discussion is added.
+                * @method
+                * @private
+                */
+               _setupAddDiscussionButton: function () {
+                       var $add = this.$( '.overlay-action .add' );
+                       M.on( 'talk-discussion-added', $.proxy( this, 
'_loadContent', this.options ) );
+                       if ( !user.isAnon() ) {
+                               $add.removeClass( 'hidden' );
+                       } else {
+                               $add.remove();
+                       }
+               }
+       } );
 
        M.define( 'mobile.talk.overlays/TalkOverlay', TalkOverlay );
 
diff --git a/resources/mobile.talk.overlays/TalkOverlayBase.js 
b/resources/mobile.talk.overlays/TalkOverlayBase.js
index 63ac261..0b39c8b 100644
--- a/resources/mobile.talk.overlays/TalkOverlayBase.js
+++ b/resources/mobile.talk.overlays/TalkOverlayBase.js
@@ -1,6 +1,5 @@
 ( function ( M ) {
-       var TalkOverlayBase,
-               PageGateway = M.require( 'mobile.startup/PageGateway' ),
+       var PageGateway = M.require( 'mobile.startup/PageGateway' ),
                Overlay = M.require( 'mobile.overlays/Overlay' );
 
        /**
@@ -10,14 +9,13 @@
         * @uses Page
         * @uses PageGateway
         */
-       TalkOverlayBase = Overlay.extend( {
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       this.pageGateway = new PageGateway( options.api );
-                       // FIXME: This should be using a gateway e.g. 
TalkGateway, PageGateway or EditorGateway
-                       this.editorApi = options.api;
-                       Overlay.prototype.initialize.apply( this, arguments );
-               }
+       function TalkOverlayBase( options ) {
+               this.pageGateway = new PageGateway( options.api );
+               // FIXME: This should be using a gateway e.g. TalkGateway, 
PageGateway or EditorGateway
+               this.editorApi = options.api;
+               Overlay.apply( this, arguments );
+       }
+       OO.mfExtend( TalkOverlayBase, Overlay, {
        } );
 
        M.define( 'mobile.talk.overlays/TalkOverlayBase', TalkOverlayBase );
diff --git a/resources/mobile.talk.overlays/TalkSectionAddOverlay.js 
b/resources/mobile.talk.overlays/TalkSectionAddOverlay.js
index 10e6220..8dbfe09 100644
--- a/resources/mobile.talk.overlays/TalkSectionAddOverlay.js
+++ b/resources/mobile.talk.overlays/TalkSectionAddOverlay.js
@@ -1,8 +1,7 @@
 ( function ( M, $ ) {
        var TalkOverlayBase = M.require( 'mobile.talk.overlays/TalkOverlayBase' 
),
                toast = M.require( 'mobile.toast/toast' ),
-               Icon = M.require( 'mobile.startup/Icon' ),
-               TalkSectionAddOverlay;
+               Icon = M.require( 'mobile.startup/Icon' );
 
        /**
         * Overlay for adding a talk section
@@ -10,7 +9,15 @@
         * @extends TalkOverlayBase
         * @uses Toast
         */
-       TalkSectionAddOverlay = TalkOverlayBase.extend( {
+       function TalkSectionAddOverlay( options ) {
+               TalkOverlayBase.apply( this, arguments );
+               this.title = options.title;
+               // Variable to indicate, if the overlay will be closed by the 
save function or by the user. If this is false and there is content in the 
input fields,
+               // the user will be asked, if he want to abandon his changes 
before we close the Overlay, otherwise the Overlay will be closed without any 
question.
+               this._saveHit = false;
+       }
+
+       OO.mfExtend( TalkSectionAddOverlay, TalkOverlayBase, {
                /**
                 * @inheritdoc
                 * @cfg {Object} defaults Default options hash.
@@ -43,14 +50,6 @@
                        'change .wikitext-editor, .summary': 'onTextInput',
                        'click .confirm-save': 'onSaveClick'
                } ),
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       TalkOverlayBase.prototype.initialize.apply( this, 
arguments );
-                       this.title = options.title;
-                       // Variable to indicate, if the overlay will be closed 
by the save function or by the user. If this is false and there is content in 
the input fields,
-                       // the user will be asked, if he want to abandon his 
changes before we close the Overlay, otherwise the Overlay will be closed 
without any question.
-                       this._saveHit = false;
-               },
                /** @inheritdoc */
                postRender: function () {
                        TalkOverlayBase.prototype.postRender.call( this );
diff --git a/resources/mobile.talk.overlays/TalkSectionOverlay.js 
b/resources/mobile.talk.overlays/TalkSectionOverlay.js
index 2962f9e..76fc304 100644
--- a/resources/mobile.talk.overlays/TalkSectionOverlay.js
+++ b/resources/mobile.talk.overlays/TalkSectionOverlay.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var TalkSectionOverlay,
-               TalkOverlayBase = M.require( 
'mobile.talk.overlays/TalkOverlayBase' ),
+       var TalkOverlayBase = M.require( 'mobile.talk.overlays/TalkOverlayBase' 
),
                popup = M.require( 'mobile.toast/toast' ),
                user = M.require( 'mobile.user/user' ),
                Page = M.require( 'mobile.startup/Page' ),
@@ -14,7 +13,11 @@
         * @uses Button
         * @uses Toast
         */
-       TalkSectionOverlay = TalkOverlayBase.extend( {
+       function TalkSectionOverlay() {
+               TalkOverlayBase.apply( this, arguments );
+       }
+
+       OO.mfExtend( TalkSectionOverlay, TalkOverlayBase, {
                templatePartials: $.extend( {}, 
TalkOverlayBase.prototype.templatePartials, {
                        header: mw.template.get( 'mobile.talk.overlays', 
'Section/header.hogan' ),
                        content: mw.template.get( 'mobile.talk.overlays', 
'Section/content.hogan' )
diff --git a/resources/mobile.toc/TableOfContents.js 
b/resources/mobile.toc/TableOfContents.js
index 07ecf16..2cdd17e 100644
--- a/resources/mobile.toc/TableOfContents.js
+++ b/resources/mobile.toc/TableOfContents.js
@@ -1,6 +1,5 @@
 ( function ( M ) {
-       var TableOfContents,
-               SchemaMobileWebUIClickTracking = M.require(
+       var SchemaMobileWebUIClickTracking = M.require(
                        'mobile.loggingSchemas/SchemaMobileWebUIClickTracking' 
),
                uiSchema = new SchemaMobileWebUIClickTracking(),
                View = M.require( 'mobile.view/View' ),
@@ -13,7 +12,11 @@
         * @uses Icon
         * @uses SchemaMobileWebClickTracking
         */
-       TableOfContents = View.extend( {
+       function TableOfContents() {
+               View.apply( this, arguments );
+       }
+
+       OO.mfExtend( TableOfContents, View, {
                templatePartials: {
                        tocHeading: mw.template.get( 'mobile.toc', 
'heading.hogan' )
                },
diff --git a/resources/mobile.view/View.js b/resources/mobile.view/View.js
index 10ce3c4..9f326ef 100644
--- a/resources/mobile.view/View.js
+++ b/resources/mobile.view/View.js
@@ -332,28 +332,6 @@
                }
        } );
 
-       /**
-        * Helper function for generating a View.
-        *
-        * @param {Object} prototype
-        * @return {View}
-        */
-       function extend( prototype ) {
-               var Child,
-                       Parent = this;
-
-               /**
-                * @ignore
-                */
-               Child = function () {
-                       Parent.apply( this, arguments );
-               };
-               Child.extend = extend;
-               OO.mfExtend( Child, this, prototype );
-               return Child;
-       }
-       View.extend = extend;
-
        $.each( [
                'append',
                'prepend',
diff --git a/resources/mobile.watchlist/WatchList.js 
b/resources/mobile.watchlist/WatchList.js
index 877be0d..acf0dcd 100644
--- a/resources/mobile.watchlist/WatchList.js
+++ b/resources/mobile.watchlist/WatchList.js
@@ -1,6 +1,5 @@
 ( function ( M, $ ) {
-       var WatchList,
-               WatchstarPageList = M.require( 
'mobile.pagelist.scripts/WatchstarPageList' ),
+       var WatchstarPageList = M.require( 
'mobile.pagelist.scripts/WatchstarPageList' ),
                InfiniteScroll = M.require( 
'mobile.infiniteScroll/InfiniteScroll' ),
                WatchListGateway = M.require( 
'mobile.watchlist/WatchListGateway' );
 
@@ -10,23 +9,23 @@
         * @class WatchList
         * @uses InfiniteScroll
         */
-       WatchList = WatchstarPageList.extend( {
+       function WatchList( options ) {
+               var lastTitle;
+
+               // Set up infinite scroll helper and listen to events
+               this.infiniteScroll = new InfiniteScroll();
+               this.infiniteScroll.on( 'load', $.proxy( this, '_loadPages' ) );
+
+               if ( options.el ) {
+                       lastTitle = this.getLastTitle( options.el );
+               }
+               this.gateway = new WatchListGateway( options.api, lastTitle );
+
+               WatchstarPageList.apply( this, arguments );
+       }
+
+       OO.mfExtend( WatchList, WatchstarPageList, {
                isBorderBox: false,
-               /** @inheritdoc */
-               initialize: function ( options ) {
-                       var lastTitle;
-
-                       // Set up infinite scroll helper and listen to events
-                       this.infiniteScroll = new InfiniteScroll();
-                       this.infiniteScroll.on( 'load', $.proxy( this, 
'_loadPages' ) );
-
-                       if ( options.el ) {
-                               lastTitle = this.getLastTitle( options.el );
-                       }
-                       this.gateway = new WatchListGateway( options.api, 
lastTitle );
-
-                       WatchstarPageList.prototype.initialize.apply( this, 
arguments );
-               },
                /** @inheritdoc */
                preRender: function () {
                        this.infiniteScroll.disable();
diff --git a/resources/mobile.watchstar/Watchstar.js 
b/resources/mobile.watchstar/Watchstar.js
index 79c3e06..87622e6 100644
--- a/resources/mobile.watchstar/Watchstar.js
+++ b/resources/mobile.watchstar/Watchstar.js
@@ -1,7 +1,6 @@
 ( function ( M ) {
 
-       var Watchstar,
-               View = M.require( 'mobile.view/View' ),
+       var View = M.require( 'mobile.view/View' ),
                SchemaMobileWebWatching = M.require( 
'mobile.loggingSchemas/SchemaMobileWebWatching' ),
                WatchstarGateway = M.require( 
'mobile.watchstar/WatchstarGateway' ),
                Icon = M.require( 'mobile.startup/Icon' ),
@@ -26,7 +25,32 @@
         * @uses WatchstarGateway
         * @uses Toast
         */
-       Watchstar = View.extend( {
+       function Watchstar( options ) {
+               var self = this,
+                       _super = View,
+                       page = options.page;
+
+               // FIXME: Remove default when Gather has been updated to use 
new gateway. (T113753)
+               options.api = options.api || new mw.Api();
+               this.gateway = new WatchstarGateway( options.api );
+
+               if ( user.isAnon() ) {
+                       _super.call( self, options );
+               } else if ( options.isWatched === undefined ) {
+                       this.gateway.loadWatchStatus( page.getId() ).done( 
function () {
+                               options.isWatched = self.gateway.isWatchedPage( 
page );
+                               _super.call( self, options );
+                       } );
+               } else {
+                       this.gateway.setWatchedPage( options.page, 
options.isWatched );
+                       _super.call( self, options );
+               }
+               this.schema = new SchemaMobileWebWatching( {
+                       funnel: options.funnel
+               } );
+       }
+
+       OO.mfExtend( Watchstar, View, {
                /**
                 * @inheritdoc
                 */
diff --git a/tests/qunit/mobile.overlays/test_Overlay.js 
b/tests/qunit/mobile.overlays/test_Overlay.js
index 580a5f6..a0f3d71 100644
--- a/tests/qunit/mobile.overlays/test_Overlay.js
+++ b/tests/qunit/mobile.overlays/test_Overlay.js
@@ -18,9 +18,13 @@
        } );
 
        QUnit.test( 'HTML overlay', 2, function ( assert ) {
-               var TestOverlay, overlay;
+               var overlay;
 
-               TestOverlay = Overlay.extend( {
+               function TestOverlay() {
+                       Overlay.apply( this, arguments );
+               }
+
+               OO.mfExtend( TestOverlay, Overlay, {
                        templatePartials: $.extend( 
Overlay.prototype.templatePartials, {
                                content: mw.template.compile( '<div 
class="content">YO</div>', 'hogan' )
                        } )
diff --git a/tests/qunit/mobile.view/test_View.js 
b/tests/qunit/mobile.view/test_View.js
index e9fe6f0..c266567 100644
--- a/tests/qunit/mobile.view/test_View.js
+++ b/tests/qunit/mobile.view/test_View.js
@@ -57,8 +57,12 @@
        } );
 
        QUnit.test( 'View.extend, with el property', 1, function ( assert ) {
-               var ChildView, $testEl, view;
-               ChildView = View.extend( {
+               var $testEl, view;
+               function ChildView() {
+                       View.apply( this, arguments );
+               }
+
+               OO.mfExtend( ChildView, View, {
                        firstHeading: function () {
                                return this.$( 'h1' ).text();
                        }
@@ -73,8 +77,12 @@
        } );
 
        QUnit.test( 'View.extend, with defined template', 4, function ( assert 
) {
-               var ChildView, view;
-               ChildView = View.extend( {
+               var view;
+               function ChildView() {
+                       View.apply( this, arguments );
+               }
+
+               OO.mfExtend( ChildView, View, {
                        className: 'my-class',
                        template: mw.template.compile( 
'<h1>{{title}}</h1><p>{{content}}</p>', 'xyz' ),
                        title: function () {
@@ -96,13 +104,21 @@
        } );
 
        QUnit.test( 'View.extend, with partials', 2, function ( assert ) {
-               var ParentView, ChildView, view;
+               var view;
 
-               ParentView = View.extend( {
+               function ParentView() {
+                       View.apply( this, arguments );
+               }
+
+               OO.mfExtend( ParentView, View, {
                        template: mw.template.compile( 
'<h1>{{title}}</h1>{{>content}}', 'xyz' )
                } );
 
-               ChildView = ParentView.extend( {
+               function ChildView() {
+                       ParentView.apply( this, arguments );
+               }
+
+               OO.mfExtend( ChildView, ParentView, {
                        templatePartials: {
                                content: mw.template.compile( 
'<p>{{text}}</p>', 'xyz' )
                        }
@@ -117,16 +133,24 @@
        } );
 
        QUnit.test( 'View.extend, extending partials', 1, function ( assert ) {
-               var ParentView, ChildView, view;
+               var view;
 
-               ParentView = View.extend( {
+               function ParentView() {
+                       View.apply( this, arguments );
+               }
+
+               OO.mfExtend( ParentView, View, {
                        templatePartials: {
                                a: 1,
                                b: 2
                        }
                } );
 
-               ChildView = ParentView.extend( {
+               function ChildView() {
+                       ParentView.apply( this, arguments );
+               }
+
+               OO.mfExtend( ChildView, ParentView, {
                        templatePartials: $.extend( 
ParentView.prototype.templatePartials, {
                                b: 3,
                                c: 4
@@ -142,16 +166,24 @@
        } );
 
        QUnit.test( 'View.extend, extending defaults', 1, function ( assert ) {
-               var ParentView, ChildView, view;
+               var view;
 
-               ParentView = View.extend( {
+               function ParentView() {
+                       View.apply( this, arguments );
+               }
+
+               OO.mfExtend( ParentView, View, {
                        defaults: {
                                a: 1,
                                b: 2
                        }
                } );
 
-               ChildView = ParentView.extend( {
+               function ChildView() {
+                       ParentView.apply( this, arguments );
+               }
+
+               OO.mfExtend( ChildView, ParentView, {
                        defaults: $.extend( ParentView.prototype.defaults, {
                                b: 3,
                                c: 4
@@ -169,8 +201,12 @@
        } );
 
        QUnit.test( 'View#preRender', 1, function ( assert ) {
-               var ChildView, view;
-               ChildView = View.extend( {
+               var view;
+               function ChildView() {
+                       View.apply( this, arguments );
+               }
+
+               OO.mfExtend( ChildView, View, {
                        template: mw.template.compile( '<p>{{text}}</p>', 'xyz' 
),
                        preRender: function () {
                                this.options.text = 'hello';
@@ -182,8 +218,12 @@
        } );
 
        QUnit.test( 'View#postRender', 1, function ( assert ) {
-               var ChildView, view, spy = this.sandbox.spy();
-               ChildView = View.extend( {
+               var view, spy = this.sandbox.spy();
+               function ChildView() {
+                       View.apply( this, arguments );
+               }
+
+               OO.mfExtend( ChildView, View, {
                        postRender: function () {
                                spy();
                        }
@@ -195,7 +235,12 @@
 
        QUnit.test( 'View#delegateEvents', 3, function ( assert ) {
 
-               var view, EventsView = View.extend( {
+               var view;
+               function EventsView() {
+                       View.apply( this, arguments );
+               }
+
+               OO.mfExtend( EventsView, View, {
                        template: mw.template.compile( 
'<p><span>test</span></p>', 'xyz' ),
                        events: {
                                'click p span': function ( ev ) {
@@ -229,15 +274,24 @@
        } );
 
        QUnit.test( 'View#render (with isTemplateMode)', 2, function ( assert ) 
{
-               var view, view2,
-                       TemplateModeView = View.extend( {
-                               template: mw.template.compile( '<p 
class="foo"><span>test</span></p>', 'html' ),
-                               isTemplateMode: true
-                       } ),
-                       ContainerView = View.extend( {
-                               className: 'bar',
-                               template: mw.template.compile( '<p 
class="foo"><span>test</span></p>', 'html' )
-                       } );
+               var view, view2;
+               function TemplateModeView() {
+                       View.apply( this, arguments );
+               }
+
+               OO.mfExtend( TemplateModeView, View, {
+                       template: mw.template.compile( '<p 
class="foo"><span>test</span></p>', 'html' ),
+                       isTemplateMode: true
+               } );
+
+               function ContainerView() {
+                       View.apply( this, arguments );
+               }
+
+               OO.mfExtend( ContainerView, View, {
+                       className: 'bar',
+                       template: mw.template.compile( '<p 
class="foo"><span>test</span></p>', 'html' )
+               } );
 
                view = new TemplateModeView();
                view2 = new ContainerView();
@@ -248,17 +302,21 @@
        } );
 
        QUnit.test( 'View#render events (with isTemplateMode)', 4, function ( 
assert ) {
-               var view,
-                       TemplateModeView = View.extend( {
-                               events: {
-                                       'click span': 'onClick'
-                               },
-                               onClick: function () {
-                                       this.$el.empty().text( 'hello world' );
-                               },
-                               template: mw.template.compile( '<p 
class="foo"><span>test</span></p>', 'html' ),
-                               isTemplateMode: true
-                       } );
+               var view;
+               function TemplateModeView() {
+                       View.apply( this, arguments );
+               }
+
+               OO.mfExtend( TemplateModeView, View, {
+                       events: {
+                               'click span': 'onClick'
+                       },
+                       onClick: function () {
+                               this.$el.empty().text( 'hello world' );
+                       },
+                       template: mw.template.compile( '<p 
class="foo"><span>test</span></p>', 'html' ),
+                       isTemplateMode: true
+               } );
 
                view = new TemplateModeView();
                // trigger event

-- 
To view, visit https://gerrit.wikimedia.org/r/265547
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I641f9f4145b0e96b33beefcef35bc2cfa243696d
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: master
Gerrit-Owner: Sumit <asthana.sumi...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to