Yuvipanda has uploaded a new change for review.

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


Change subject: Start using browserify for the JavaScript
......................................................................

Start using browserify for the JavaScript

- Contains gruntfile to do the compilation steps
- Unit tests have been separated out into bundle-test.js
- Adds package.json to help people get setup easily

Change-Id: Ibec6889e7a549d9107e21cf4cf77caa940702fc6
---
M wikipedia-it/src/main/java/org/wikipedia/test/BridgeTests.java
A wikipedia/assets/Gruntfile.js
M wikipedia/assets/bridge.js
A wikipedia/assets/bundle-test.js
A wikipedia/assets/bundle.js
M wikipedia/assets/index.html
M wikipedia/assets/main.js
A wikipedia/assets/package.json
A wikipedia/assets/tests.html
A wikipedia/assets/tests/inject.js
M wikipedia/assets/tests/pingback.js
M wikipedia/assets/transforms.js
12 files changed, 655 insertions(+), 213 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/apps/android/wikipedia 
refs/changes/99/108499/1

diff --git a/wikipedia-it/src/main/java/org/wikipedia/test/BridgeTests.java 
b/wikipedia-it/src/main/java/org/wikipedia/test/BridgeTests.java
index e84381f..05d41c9 100644
--- a/wikipedia-it/src/main/java/org/wikipedia/test/BridgeTests.java
+++ b/wikipedia-it/src/main/java/org/wikipedia/test/BridgeTests.java
@@ -26,7 +26,7 @@
             public void run() {
                 startActivity(new Intent(), null, null);
                 WebView webView = new WebView(getActivity());
-                bridge = new CommunicationBridge(webView, 
"file:///android_asset/index.html");
+                bridge = new CommunicationBridge(webView, 
"file:///android_asset/tests.html");
                 bridge.addListener("DOMLoaded", new 
CommunicationBridge.JSEventListener() {
                     @Override
                     public JSONObject onMessage(String messageType, JSONObject 
messagePayload) {
@@ -47,27 +47,20 @@
             public void run() {
                 startActivity(new Intent(), null, null);
                 WebView webView = new WebView(getActivity());
-                bridge = new CommunicationBridge(webView, 
"file:///android_asset/index.html");
+                bridge = new CommunicationBridge(webView, 
"file:///android_asset/tests.html");
                 final JSONObject payload = new JSONObject();
                 try {
-                    payload.put("src", 
"file:///android_asset/tests/pingback.js");
+                    payload.put("src", "./pingback");
                 } catch (JSONException e) {
                     throw new RuntimeException(e); // JESUS CHRIST, JAVA!
                 }
-                bridge.addListener("pingBackLoaded", new 
CommunicationBridge.JSEventListener() {
+                bridge.sendMessage("ping", payload);
+                bridge.addListener("pong", new 
CommunicationBridge.JSEventListener() {
                     @Override
                     public JSONObject onMessage(String messageType, JSONObject 
messagePayload) {
-                        assertEquals(messageType, "pingBackLoaded");
-                        bridge.sendMessage("ping", payload);
-                        bridge.addListener("pong", new 
CommunicationBridge.JSEventListener() {
-                            @Override
-                            public JSONObject onMessage(String messageType, 
JSONObject messagePayload) {
-                                assertEquals(messageType, "pong");
-                                assertEquals(messagePayload.toString(), 
payload.toString());
-                                completionLatch.countDown();
-                                return null;
-                            }
-                        });
+                        assertEquals(messageType, "pong");
+                        assertEquals(messagePayload.toString(), 
payload.toString());
+                        completionLatch.countDown();
                         return null;
                     }
                 });
diff --git a/wikipedia/assets/Gruntfile.js b/wikipedia/assets/Gruntfile.js
new file mode 100644
index 0000000..418f61c
--- /dev/null
+++ b/wikipedia/assets/Gruntfile.js
@@ -0,0 +1,17 @@
+module.exports = function( grunt ) {
+    grunt.initConfig( {
+        pkg: grunt.file.readJSON( "package.json" ),
+        browserify: {
+            dist: {
+                files: {
+                    "bundle.js": [ "main.js", "transforms.js", "bridge.js"],
+                    "bundle-test.js": [ "main.js", "bridge.js", "tests/*.js" ]
+                }
+            }
+        }
+    } );
+
+    grunt.loadNpmTasks( 'grunt-browserify' );
+
+    grunt.registerTask( 'default', [ 'browserify' ] );
+}
\ No newline at end of file
diff --git a/wikipedia/assets/bridge.js b/wikipedia/assets/bridge.js
index 07368c2..c7a2fa8 100644
--- a/wikipedia/assets/bridge.js
+++ b/wikipedia/assets/bridge.js
@@ -1,45 +1,36 @@
-( function() {
+function Bridge() {
+    this.eventHandlers = {};
+}
 
-    var Bridge = function() {
-        this.eventHandlers = {};
-    };
+// This is called directly from Java, and hence needs to be available
+Bridge.prototype.handleMessage = function( type, msgPointer ) {
+    var that = this;
+    var payload = JSON.parse( marshaller.getPayload( msgPointer ) );
+    if ( this.eventHandlers.hasOwnProperty( type ) ) {
+        this.eventHandlers[type].forEach( function( callback ) {
+            callback.call( that, payload );
+        } );
+    }
+};
 
-    Bridge.prototype.handleMessage = function( type, msgPointer ) {
-        var that = this;
-        var payload = JSON.parse( marshaller.getPayload( msgPointer ) );
-        if ( this.eventHandlers.hasOwnProperty( type ) ) {
-            this.eventHandlers[type].forEach( function( callback ) {
-                callback.call( that, payload );
-            } );
-        }
-    };
+Bridge.prototype.registerListener = function( messageType, callback ) {
+    if ( this.eventHandlers.hasOwnProperty( messageType ) ) {
+        this.eventHandlers[messageType].push( callback );
+    } else {
+        this.eventHandlers[messageType] = [ callback ];
+    }
+};
 
-    Bridge.prototype.registerListener = function( messageType, callback ) {
-        if ( this.eventHandlers.hasOwnProperty( messageType ) ) {
-            this.eventHandlers[messageType].push( callback );
-        } else {
-            this.eventHandlers[messageType] = [ callback ];
-        }
-    };
+Bridge.prototype.sendMessage = function( messageType, payload ) {
+    var messagePack = { type: messageType, payload: payload };
+    var ret = prompt( JSON.stringify( messagePack) );
+    if ( ret ) {
+        return JSON.parse( ret );
+    }
+};
 
-    Bridge.prototype.sendMessage = function( messageType, payload ) {
-        var messagePack = { type: messageType, payload: payload };
-        var ret = prompt( JSON.stringify( messagePack) );
-        if ( ret ) {
-            return JSON.parse( ret );
-        }
-    };
-
-    window.bridge = new Bridge();
-
-    bridge.registerListener( "injectScript", function( payload ) {
-        var script = document.createElement( "script" );
-        script.type = "text/javascript";
-        script.src = payload.src;
-        document.head.appendChild( script );
-    });
-
-    window.onload = function() {
-        bridge.sendMessage( "DOMLoaded", {} );
-    };
-} )();
\ No newline at end of file
+module.exports = new Bridge();
+// FIXME: Move this to somwehere else, eh?
+window.onload = function() {
+    module.exports.sendMessage( "DOMLoaded", {} );
+}
\ No newline at end of file
diff --git a/wikipedia/assets/bundle-test.js b/wikipedia/assets/bundle-test.js
new file mode 100644
index 0000000..5d128ca
--- /dev/null
+++ b/wikipedia/assets/bundle-test.js
@@ -0,0 +1,218 @@
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof 
require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw 
new Error("Cannot find module '"+o+"'")}var 
f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return 
s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof 
require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return 
s})({1:[function(require,module,exports){
+function Bridge() {
+    this.eventHandlers = {};
+}
+
+// This is called directly from Java, and hence needs to be available
+Bridge.prototype.handleMessage = function( type, msgPointer ) {
+    var that = this;
+    var payload = JSON.parse( marshaller.getPayload( msgPointer ) );
+    if ( this.eventHandlers.hasOwnProperty( type ) ) {
+        this.eventHandlers[type].forEach( function( callback ) {
+            callback.call( that, payload );
+        } );
+    }
+};
+
+Bridge.prototype.registerListener = function( messageType, callback ) {
+    if ( this.eventHandlers.hasOwnProperty( messageType ) ) {
+        this.eventHandlers[messageType].push( callback );
+    } else {
+        this.eventHandlers[messageType] = [ callback ];
+    }
+};
+
+Bridge.prototype.sendMessage = function( messageType, payload ) {
+    var messagePack = { type: messageType, payload: payload };
+    var ret = prompt( JSON.stringify( messagePack) );
+    if ( ret ) {
+        return JSON.parse( ret );
+    }
+};
+
+module.exports = new Bridge();
+window.onload = function() {
+    module.exports.sendMessage( "DOMLoaded", {} );
+}
+},{}],2:[function(require,module,exports){
+var bridge = require("./bridge");
+var transforms = require("./transforms");
+
+window.bridge = bridge;
+
+function forEach( list, fun ) {
+    // Hack from 
https://developer.mozilla.org/en-US/docs/Web/API/NodeList#Workarounds
+    // To let me use forEach on things like NodeList objects
+    Array.prototype.forEach.call( list, fun );
+}
+
+bridge.registerListener( "displayLeadSection", function( payload ) {
+    // This might be a refresh! Clear out all contents!
+    document.getElementById( "content" ).innerHTML = "";
+
+    var title = document.createElement( "h1" );
+    title.textContent = payload.title;
+    title.id = "heading_" + payload.section.id;
+    document.getElementById( "content" ).appendChild( title );
+
+    var content = document.createElement( "div" );
+    content.innerHTML = payload.section.text;
+    content.id = "#content_block_0";
+    content = transforms.transform( "lead", content );
+    document.getElementById( "content" ).appendChild( content );
+
+    document.getElementById( "loading_sections").className = "loading";
+});
+
+function elementsForSection( section ) {
+    var heading = document.createElement( "h" + ( section.toclevel + 1 ) );
+    heading.textContent = section.line;
+    heading.id = "heading_" + section.id;
+    heading.setAttribute( 'data-id', section.id );
+
+    var editButton = document.createElement( "a" );
+    editButton.setAttribute( 'data-id', section.id );
+    editButton.setAttribute( 'data-action', "edit_section" );
+    editButton.className = "edit_section_button";
+    heading.appendChild( editButton );
+
+    var content = document.createElement( "div" );
+    content.innerHTML = section.text;
+    content.id = "content_block_" + section.id;
+    content = transforms.transform( "body", content );
+
+    return [ heading, content ];
+}
+
+bridge.registerListener( "displaySection", function ( payload ) {
+    var content_wrapper = document.getElementById( "content" );
+
+    elementsForSection( payload.section ).forEach( function( element ) {
+        content_wrapper.appendChild( element );
+    });
+    if ( !payload.isLast ) {
+        bridge.sendMessage( "requestSection", { index: payload.index + 1 } );
+    } else {
+        document.getElementById( "loading_sections").className = "";
+    }
+});
+
+bridge.registerListener( "startSectionsDisplay", function( payload ) {
+    bridge.sendMessage( "requestSection", { index: 1 } );
+});
+
+bridge.registerListener( "displayAttribution", function( payload ) {
+    var lastUpdatedA = document.getElementById( "lastupdated" );
+    lastUpdatedA.innerText = payload.historyText;
+    lastUpdatedA.href = payload.historyTarget;
+    var licenseText = document.getElementById( "licensetext" );
+    licenseText.innerHTML = payload.licenseHTML;
+});
+
+bridge.registerListener( "requestImagesList", function ( payload ) {
+    var imageURLs = [];
+    var images = document.querySelectorAll( "img" );
+    for ( var i = 0; i < images.length; i++ ) {
+        imageURLs.push( images[i].src );
+    }
+    bridge.sendMessage( "imagesListResponse", { "images": imageURLs });
+} );
+
+bridge.registerListener( "scrollToSection", function ( payload ) {
+    var el = document.getElementById( "heading_" + payload.sectionID);
+    // Make sure there's exactly as much space on the left as on the top.
+    // The 48 accounts for the search bar
+    var scrollY = el.offsetTop - 48 - el.offsetLeft;
+    window.scrollTo(0, scrollY);
+});
+
+
+var actionHandlers = {
+    "edit_section": function( el, event ) {
+        bridge.sendMessage( 'editSectionClicked', { sectionID: 
el.getAttribute( 'data-id' ) } );
+        event.preventDefault();
+    }
+};
+
+document.onclick = function() {
+    if ( event.target.tagName === "A" ) {
+        if ( event.target.hasAttribute( "data-action" ) ) {
+            var action = event.target.getAttribute( "data-action" );
+            actionHandlers[ action ]( event.target, event );
+        } else {
+            bridge.sendMessage( 'linkClicked', { href: 
event.target.getAttribute( "href" ) });
+            event.preventDefault();
+        }
+    }
+};
+},{"./bridge":1,"./transforms":5}],3:[function(require,module,exports){
+var bridge = require("../bridge");
+bridge.registerListener( "injectScript", function( payload ) {
+    require(payload.src);
+});
+},{"../bridge":1}],4:[function(require,module,exports){
+var bridge = require("../bridge");
+console.log("Something!");
+bridge.registerListener( "ping", function( payload ) {
+    bridge.sendMessage( "pong", payload );
+});
+
+},{"../bridge":1}],5:[function(require,module,exports){
+var Transforms = function () {};
+
+// List of transformation functions by their target type
+var transformsByType = {
+    'lead': [
+        moveInfobox,
+        useLocalImagesForSavedPages
+    ],
+    'body': [
+        useLocalImagesForSavedPages
+    ]
+}
+
+function moveInfobox( leadContent ) {
+    // Move infobox to the bottom of the lead section
+    var infobox = leadContent.querySelector( "table.infobox" );
+    if ( infobox ) {
+        infobox.parentNode.removeChild( infobox );
+        var pTags = leadContent.getElementsByTagName( "p" );
+        if ( pTags.length ) {
+            pTags[0].appendChild( infobox );
+        } else {
+            leadContent.appendChild( infobox );
+        }
+    }
+    return leadContent;
+}
+
+function useLocalImagesForSavedPages( content ) {
+    var images = content.querySelectorAll( "img" );
+    function onError() {
+        var img = event.target;
+        // Only work on http or https URLs. If we do not have this check, we 
might go on an infinte loop
+        if ( img.src.substring( 0, 4 ) === "http" )  {
+            // if it is already not a file URL!
+            var resp = bridge.sendMessage( "imageUrlToFilePath", { "imageUrl": 
img.src } );
+            console.log( "new filepath is " + resp.filePath );
+            img.src = "file://" + resp.filePath;
+        }
+    }
+    for ( var i = 0; i < images.length; i++ ) {
+        images[i].onerror = onError;
+    }
+    return content;
+}
+
+Transforms.prototype.transform = function( type, content ) {
+    var transforms = transformsByType[ type ];
+    if ( transforms.length ) {
+        transforms.forEach( function ( transform ) {
+            content = transform( content );
+        } );
+    }
+    return content;
+};
+
+module.exports = new Transforms();
+},{}]},{},[2,1,3,4])
\ No newline at end of file
diff --git a/wikipedia/assets/bundle.js b/wikipedia/assets/bundle.js
new file mode 100644
index 0000000..4864b12
--- /dev/null
+++ b/wikipedia/assets/bundle.js
@@ -0,0 +1,206 @@
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof 
require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw 
new Error("Cannot find module '"+o+"'")}var 
f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return 
s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof 
require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return 
s})({1:[function(require,module,exports){
+function Bridge() {
+    this.eventHandlers = {};
+}
+
+// This is called directly from Java, and hence needs to be available
+Bridge.prototype.handleMessage = function( type, msgPointer ) {
+    var that = this;
+    var payload = JSON.parse( marshaller.getPayload( msgPointer ) );
+    if ( this.eventHandlers.hasOwnProperty( type ) ) {
+        this.eventHandlers[type].forEach( function( callback ) {
+            callback.call( that, payload );
+        } );
+    }
+};
+
+Bridge.prototype.registerListener = function( messageType, callback ) {
+    if ( this.eventHandlers.hasOwnProperty( messageType ) ) {
+        this.eventHandlers[messageType].push( callback );
+    } else {
+        this.eventHandlers[messageType] = [ callback ];
+    }
+};
+
+Bridge.prototype.sendMessage = function( messageType, payload ) {
+    var messagePack = { type: messageType, payload: payload };
+    var ret = prompt( JSON.stringify( messagePack) );
+    if ( ret ) {
+        return JSON.parse( ret );
+    }
+};
+
+module.exports = new Bridge();
+window.onload = function() {
+    module.exports.sendMessage( "DOMLoaded", {} );
+}
+},{}],2:[function(require,module,exports){
+var bridge = require("./bridge");
+var transforms = require("./transforms");
+
+window.bridge = bridge;
+
+function forEach( list, fun ) {
+    // Hack from 
https://developer.mozilla.org/en-US/docs/Web/API/NodeList#Workarounds
+    // To let me use forEach on things like NodeList objects
+    Array.prototype.forEach.call( list, fun );
+}
+
+bridge.registerListener( "displayLeadSection", function( payload ) {
+    // This might be a refresh! Clear out all contents!
+    document.getElementById( "content" ).innerHTML = "";
+
+    var title = document.createElement( "h1" );
+    title.textContent = payload.title;
+    title.id = "heading_" + payload.section.id;
+    document.getElementById( "content" ).appendChild( title );
+
+    var content = document.createElement( "div" );
+    content.innerHTML = payload.section.text;
+    content.id = "#content_block_0";
+    content = transforms.transform( "lead", content );
+    document.getElementById( "content" ).appendChild( content );
+
+    document.getElementById( "loading_sections").className = "loading";
+});
+
+function elementsForSection( section ) {
+    var heading = document.createElement( "h" + ( section.toclevel + 1 ) );
+    heading.textContent = section.line;
+    heading.id = "heading_" + section.id;
+    heading.setAttribute( 'data-id', section.id );
+
+    var editButton = document.createElement( "a" );
+    editButton.setAttribute( 'data-id', section.id );
+    editButton.setAttribute( 'data-action', "edit_section" );
+    editButton.className = "edit_section_button";
+    heading.appendChild( editButton );
+
+    var content = document.createElement( "div" );
+    content.innerHTML = section.text;
+    content.id = "content_block_" + section.id;
+    content = transforms.transform( "body", content );
+
+    return [ heading, content ];
+}
+
+bridge.registerListener( "displaySection", function ( payload ) {
+    var content_wrapper = document.getElementById( "content" );
+
+    elementsForSection( payload.section ).forEach( function( element ) {
+        content_wrapper.appendChild( element );
+    });
+    if ( !payload.isLast ) {
+        bridge.sendMessage( "requestSection", { index: payload.index + 1 } );
+    } else {
+        document.getElementById( "loading_sections").className = "";
+    }
+});
+
+bridge.registerListener( "startSectionsDisplay", function( payload ) {
+    bridge.sendMessage( "requestSection", { index: 1 } );
+});
+
+bridge.registerListener( "displayAttribution", function( payload ) {
+    var lastUpdatedA = document.getElementById( "lastupdated" );
+    lastUpdatedA.innerText = payload.historyText;
+    lastUpdatedA.href = payload.historyTarget;
+    var licenseText = document.getElementById( "licensetext" );
+    licenseText.innerHTML = payload.licenseHTML;
+});
+
+bridge.registerListener( "requestImagesList", function ( payload ) {
+    var imageURLs = [];
+    var images = document.querySelectorAll( "img" );
+    for ( var i = 0; i < images.length; i++ ) {
+        imageURLs.push( images[i].src );
+    }
+    bridge.sendMessage( "imagesListResponse", { "images": imageURLs });
+} );
+
+bridge.registerListener( "scrollToSection", function ( payload ) {
+    var el = document.getElementById( "heading_" + payload.sectionID);
+    // Make sure there's exactly as much space on the left as on the top.
+    // The 48 accounts for the search bar
+    var scrollY = el.offsetTop - 48 - el.offsetLeft;
+    window.scrollTo(0, scrollY);
+});
+
+
+var actionHandlers = {
+    "edit_section": function( el, event ) {
+        bridge.sendMessage( 'editSectionClicked', { sectionID: 
el.getAttribute( 'data-id' ) } );
+        event.preventDefault();
+    }
+};
+
+document.onclick = function() {
+    if ( event.target.tagName === "A" ) {
+        if ( event.target.hasAttribute( "data-action" ) ) {
+            var action = event.target.getAttribute( "data-action" );
+            actionHandlers[ action ]( event.target, event );
+        } else {
+            bridge.sendMessage( 'linkClicked', { href: 
event.target.getAttribute( "href" ) });
+            event.preventDefault();
+        }
+    }
+};
+},{"./bridge":1,"./transforms":3}],3:[function(require,module,exports){
+var Transforms = function () {};
+
+// List of transformation functions by their target type
+var transformsByType = {
+    'lead': [
+        moveInfobox,
+        useLocalImagesForSavedPages
+    ],
+    'body': [
+        useLocalImagesForSavedPages
+    ]
+}
+
+function moveInfobox( leadContent ) {
+    // Move infobox to the bottom of the lead section
+    var infobox = leadContent.querySelector( "table.infobox" );
+    if ( infobox ) {
+        infobox.parentNode.removeChild( infobox );
+        var pTags = leadContent.getElementsByTagName( "p" );
+        if ( pTags.length ) {
+            pTags[0].appendChild( infobox );
+        } else {
+            leadContent.appendChild( infobox );
+        }
+    }
+    return leadContent;
+}
+
+function useLocalImagesForSavedPages( content ) {
+    var images = content.querySelectorAll( "img" );
+    function onError() {
+        var img = event.target;
+        // Only work on http or https URLs. If we do not have this check, we 
might go on an infinte loop
+        if ( img.src.substring( 0, 4 ) === "http" )  {
+            // if it is already not a file URL!
+            var resp = bridge.sendMessage( "imageUrlToFilePath", { "imageUrl": 
img.src } );
+            console.log( "new filepath is " + resp.filePath );
+            img.src = "file://" + resp.filePath;
+        }
+    }
+    for ( var i = 0; i < images.length; i++ ) {
+        images[i].onerror = onError;
+    }
+    return content;
+}
+
+Transforms.prototype.transform = function( type, content ) {
+    var transforms = transformsByType[ type ];
+    if ( transforms.length ) {
+        transforms.forEach( function ( transform ) {
+            content = transform( content );
+        } );
+    }
+    return content;
+};
+
+module.exports = new Transforms();
+},{}]},{},[2,3,1])
\ No newline at end of file
diff --git a/wikipedia/assets/index.html b/wikipedia/assets/index.html
index c7c40a9..5f07156 100644
--- a/wikipedia/assets/index.html
+++ b/wikipedia/assets/index.html
@@ -2,9 +2,7 @@
 <html>
 <head>
     <base href="https://wikipedia.org"; /> <!-- Force links to resolve with 
https as protocol, rather than file:// -->
-    <script src="file:///android_asset/bridge.js"></script>
-    <script src="file:///android_asset/transforms.js"></script>
-    <script src="file:///android_asset/main.js"></script>
+    <script src="file:///android_asset/bundle.js"></script>
 
     <link rel="stylesheet" type="text/css" 
href="file:///android_asset/pagestyles.css"> </link>
     <link rel="stylesheet" type="text/css" 
href="file:///android_asset/ui.css"> </link>
diff --git a/wikipedia/assets/main.js b/wikipedia/assets/main.js
index 202fda6..89431ed 100644
--- a/wikipedia/assets/main.js
+++ b/wikipedia/assets/main.js
@@ -1,108 +1,110 @@
-( function() {
-    function forEach( list, fun ) {
-        // Hack from 
https://developer.mozilla.org/en-US/docs/Web/API/NodeList#Workarounds
-        // To let me use forEach on things like NodeList objects
-        Array.prototype.forEach.call( list, fun );
-    }
+var bridge = require("./bridge");
+var transforms = require("./transforms");
 
-    bridge.registerListener( "displayLeadSection", function( payload ) {
-        // This might be a refresh! Clear out all contents!
-        document.getElementById( "content" ).innerHTML = "";
+window.bridge = bridge;
 
-        var title = document.createElement( "h1" );
-        title.textContent = payload.title;
-        title.id = "heading_" + payload.section.id;
-        document.getElementById( "content" ).appendChild( title );
+function forEach( list, fun ) {
+    // Hack from 
https://developer.mozilla.org/en-US/docs/Web/API/NodeList#Workarounds
+    // To let me use forEach on things like NodeList objects
+    Array.prototype.forEach.call( list, fun );
+}
 
-        var content = document.createElement( "div" );
-        content.innerHTML = payload.section.text;
-        content.id = "#content_block_0";
-        content = transforms.transform( "lead", content );
-        document.getElementById( "content" ).appendChild( content );
+bridge.registerListener( "displayLeadSection", function( payload ) {
+    // This might be a refresh! Clear out all contents!
+    document.getElementById( "content" ).innerHTML = "";
 
-        document.getElementById( "loading_sections").className = "loading";
+    var title = document.createElement( "h1" );
+    title.textContent = payload.title;
+    title.id = "heading_" + payload.section.id;
+    document.getElementById( "content" ).appendChild( title );
+
+    var content = document.createElement( "div" );
+    content.innerHTML = payload.section.text;
+    content.id = "#content_block_0";
+    content = transforms.transform( "lead", content );
+    document.getElementById( "content" ).appendChild( content );
+
+    document.getElementById( "loading_sections").className = "loading";
+});
+
+function elementsForSection( section ) {
+    var heading = document.createElement( "h" + ( section.toclevel + 1 ) );
+    heading.textContent = section.line;
+    heading.id = "heading_" + section.id;
+    heading.setAttribute( 'data-id', section.id );
+
+    var editButton = document.createElement( "a" );
+    editButton.setAttribute( 'data-id', section.id );
+    editButton.setAttribute( 'data-action', "edit_section" );
+    editButton.className = "edit_section_button";
+    heading.appendChild( editButton );
+
+    var content = document.createElement( "div" );
+    content.innerHTML = section.text;
+    content.id = "content_block_" + section.id;
+    content = transforms.transform( "body", content );
+
+    return [ heading, content ];
+}
+
+bridge.registerListener( "displaySection", function ( payload ) {
+    var content_wrapper = document.getElementById( "content" );
+
+    elementsForSection( payload.section ).forEach( function( element ) {
+        content_wrapper.appendChild( element );
     });
-
-    function elementsForSection( section ) {
-        var heading = document.createElement( "h" + ( section.toclevel + 1 ) );
-        heading.textContent = section.line;
-        heading.id = "heading_" + section.id;
-        heading.setAttribute( 'data-id', section.id );
-
-        var editButton = document.createElement( "a" );
-        editButton.setAttribute( 'data-id', section.id );
-        editButton.setAttribute( 'data-action', "edit_section" );
-        editButton.className = "edit_section_button";
-        heading.appendChild( editButton );
-
-        var content = document.createElement( "div" );
-        content.innerHTML = section.text;
-        content.id = "content_block_" + section.id;
-        content = transforms.transform( "body", content );
-
-        return [ heading, content ];
+    if ( !payload.isLast ) {
+        bridge.sendMessage( "requestSection", { index: payload.index + 1 } );
+    } else {
+        document.getElementById( "loading_sections").className = "";
     }
+});
 
-    bridge.registerListener( "displaySection", function ( payload ) {
-        var content_wrapper = document.getElementById( "content" );
+bridge.registerListener( "startSectionsDisplay", function( payload ) {
+    bridge.sendMessage( "requestSection", { index: 1 } );
+});
 
-        elementsForSection( payload.section ).forEach( function( element ) {
-            content_wrapper.appendChild( element );
-        });
-        if ( !payload.isLast ) {
-            bridge.sendMessage( "requestSection", { index: payload.index + 1 } 
);
+bridge.registerListener( "displayAttribution", function( payload ) {
+    var lastUpdatedA = document.getElementById( "lastupdated" );
+    lastUpdatedA.innerText = payload.historyText;
+    lastUpdatedA.href = payload.historyTarget;
+    var licenseText = document.getElementById( "licensetext" );
+    licenseText.innerHTML = payload.licenseHTML;
+});
+
+bridge.registerListener( "requestImagesList", function ( payload ) {
+    var imageURLs = [];
+    var images = document.querySelectorAll( "img" );
+    for ( var i = 0; i < images.length; i++ ) {
+        imageURLs.push( images[i].src );
+    }
+    bridge.sendMessage( "imagesListResponse", { "images": imageURLs });
+} );
+
+bridge.registerListener( "scrollToSection", function ( payload ) {
+    var el = document.getElementById( "heading_" + payload.sectionID);
+    // Make sure there's exactly as much space on the left as on the top.
+    // The 48 accounts for the search bar
+    var scrollY = el.offsetTop - 48 - el.offsetLeft;
+    window.scrollTo(0, scrollY);
+});
+
+
+var actionHandlers = {
+    "edit_section": function( el, event ) {
+        bridge.sendMessage( 'editSectionClicked', { sectionID: 
el.getAttribute( 'data-id' ) } );
+        event.preventDefault();
+    }
+};
+
+document.onclick = function() {
+    if ( event.target.tagName === "A" ) {
+        if ( event.target.hasAttribute( "data-action" ) ) {
+            var action = event.target.getAttribute( "data-action" );
+            actionHandlers[ action ]( event.target, event );
         } else {
-            document.getElementById( "loading_sections").className = "";
-        }
-    });
-
-    bridge.registerListener( "startSectionsDisplay", function( payload ) {
-        bridge.sendMessage( "requestSection", { index: 1 } );
-    });
-
-    bridge.registerListener( "displayAttribution", function( payload ) {
-        var lastUpdatedA = document.getElementById( "lastupdated" );
-        lastUpdatedA.innerText = payload.historyText;
-        lastUpdatedA.href = payload.historyTarget;
-        var licenseText = document.getElementById( "licensetext" );
-        licenseText.innerHTML = payload.licenseHTML;
-    });
-
-    bridge.registerListener( "requestImagesList", function ( payload ) {
-        var imageURLs = [];
-        var images = document.querySelectorAll( "img" );
-        for ( var i = 0; i < images.length; i++ ) {
-            imageURLs.push( images[i].src );
-        }
-        bridge.sendMessage( "imagesListResponse", { "images": imageURLs });
-    } );
-
-    bridge.registerListener( "scrollToSection", function ( payload ) {
-        var el = document.getElementById( "heading_" + payload.sectionID);
-        // Make sure there's exactly as much space on the left as on the top.
-        // The 48 accounts for the search bar
-        var scrollY = el.offsetTop - 48 - el.offsetLeft;
-        window.scrollTo(0, scrollY);
-    });
-
-
-    var actionHandlers = {
-        "edit_section": function( el, event ) {
-            bridge.sendMessage( 'editSectionClicked', { sectionID: 
el.getAttribute( 'data-id' ) } );
+            bridge.sendMessage( 'linkClicked', { href: 
event.target.getAttribute( "href" ) });
             event.preventDefault();
         }
-    };
-
-    document.onclick = function() {
-        if ( event.target.tagName === "A" ) {
-            if ( event.target.hasAttribute( "data-action" ) ) {
-                var action = event.target.getAttribute( "data-action" );
-                actionHandlers[ action ]( event.target, event );
-            } else {
-                bridge.sendMessage( 'linkClicked', { href: 
event.target.getAttribute( "href" ) });
-                event.preventDefault();
-            }
-        }
-    };
-
-} )();
\ No newline at end of file
+    }
+};
\ No newline at end of file
diff --git a/wikipedia/assets/package.json b/wikipedia/assets/package.json
new file mode 100644
index 0000000..f11d1f6
--- /dev/null
+++ b/wikipedia/assets/package.json
@@ -0,0 +1,10 @@
+{
+    "name": "wikipedia-android",
+    "description": "JS files required for the Wikipedia Android app",
+    "repository": "https://gerrit.wikimedia.org/r/apps/android/wikipedia";,
+    "version": "0.1.0",
+    "devDependencies": {
+        "grunt": "~0.4.2",
+        "grunt-browserify": "~1.3.0"
+    }
+}
\ No newline at end of file
diff --git a/wikipedia/assets/tests.html b/wikipedia/assets/tests.html
new file mode 100644
index 0000000..6c22b1b
--- /dev/null
+++ b/wikipedia/assets/tests.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="file:///android_asset/bundle-test.js"></script>
+</head>
+</html>
\ No newline at end of file
diff --git a/wikipedia/assets/tests/inject.js b/wikipedia/assets/tests/inject.js
new file mode 100644
index 0000000..ea40844
--- /dev/null
+++ b/wikipedia/assets/tests/inject.js
@@ -0,0 +1,4 @@
+var bridge = require("../bridge");
+bridge.registerListener( "injectScript", function( payload ) {
+    require(payload.src);
+});
\ No newline at end of file
diff --git a/wikipedia/assets/tests/pingback.js 
b/wikipedia/assets/tests/pingback.js
index 9895cbc..6315f5f 100644
--- a/wikipedia/assets/tests/pingback.js
+++ b/wikipedia/assets/tests/pingback.js
@@ -1,6 +1,5 @@
-(function() {
-    bridge.registerListener( "ping", function( payload ) {
-        bridge.sendMessage( "pong", payload );
-    });
-    bridge.sendMessage( "pingBackLoaded", {} );
-} )();
+var bridge = require("../bridge");
+console.log("Something!");
+bridge.registerListener( "ping", function( payload ) {
+    bridge.sendMessage( "pong", payload );
+});
diff --git a/wikipedia/assets/transforms.js b/wikipedia/assets/transforms.js
index 3074f31..9dae591 100644
--- a/wikipedia/assets/transforms.js
+++ b/wikipedia/assets/transforms.js
@@ -1,59 +1,57 @@
-( function() {
-    var Transforms = function () {};
+var Transforms = function () {};
 
-    // List of transformation functions by their target type
-    var transformsByType = {
-        'lead': [
-            moveInfobox,
-            useLocalImagesForSavedPages
-        ],
-        'body': [
-            useLocalImagesForSavedPages
-        ]
+// List of transformation functions by their target type
+var transformsByType = {
+    'lead': [
+        moveInfobox,
+        useLocalImagesForSavedPages
+    ],
+    'body': [
+        useLocalImagesForSavedPages
+    ]
+}
+
+function moveInfobox( leadContent ) {
+    // Move infobox to the bottom of the lead section
+    var infobox = leadContent.querySelector( "table.infobox" );
+    if ( infobox ) {
+        infobox.parentNode.removeChild( infobox );
+        var pTags = leadContent.getElementsByTagName( "p" );
+        if ( pTags.length ) {
+            pTags[0].appendChild( infobox );
+        } else {
+            leadContent.appendChild( infobox );
+        }
     }
+    return leadContent;
+}
 
-    function moveInfobox( leadContent ) {
-        // Move infobox to the bottom of the lead section
-        var infobox = leadContent.querySelector( "table.infobox" );
-        if ( infobox ) {
-            infobox.parentNode.removeChild( infobox );
-            var pTags = leadContent.getElementsByTagName( "p" );
-            if ( pTags.length ) {
-                pTags[0].appendChild( infobox );
-            } else {
-                leadContent.appendChild( infobox );
-            }
+function useLocalImagesForSavedPages( content ) {
+    var images = content.querySelectorAll( "img" );
+    function onError() {
+        var img = event.target;
+        // Only work on http or https URLs. If we do not have this check, we 
might go on an infinte loop
+        if ( img.src.substring( 0, 4 ) === "http" )  {
+            // if it is already not a file URL!
+            var resp = bridge.sendMessage( "imageUrlToFilePath", { "imageUrl": 
img.src } );
+            console.log( "new filepath is " + resp.filePath );
+            img.src = "file://" + resp.filePath;
         }
-        return leadContent;
     }
-
-    function useLocalImagesForSavedPages( content ) {
-        var images = content.querySelectorAll( "img" );
-        function onError() {
-            var img = event.target;
-            // Only work on http or https URLs. If we do not have this check, 
we might go on an infinte loop
-            if ( img.src.substring( 0, 4 ) === "http" )  {
-                // if it is already not a file URL!
-                var resp = bridge.sendMessage( "imageUrlToFilePath", { 
"imageUrl": img.src } );
-                console.log( "new filepath is " + resp.filePath );
-                img.src = "file://" + resp.filePath;
-            }
-        }
-        for ( var i = 0; i < images.length; i++ ) {
-            images[i].onerror = onError;
-        }
-        return content;
+    for ( var i = 0; i < images.length; i++ ) {
+        images[i].onerror = onError;
     }
+    return content;
+}
 
-    Transforms.prototype.transform = function( type, content ) {
-        var transforms = transformsByType[ type ];
-        if ( transforms.length ) {
-            transforms.forEach( function ( transform ) {
-                content = transform( content );
-            } );
-        }
-        return content;
-    };
+Transforms.prototype.transform = function( type, content ) {
+    var transforms = transformsByType[ type ];
+    if ( transforms.length ) {
+        transforms.forEach( function ( transform ) {
+            content = transform( content );
+        } );
+    }
+    return content;
+};
 
-    window.transforms = new Transforms();
-}) ();
\ No newline at end of file
+module.exports = new Transforms();
\ No newline at end of file

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ibec6889e7a549d9107e21cf4cf77caa940702fc6
Gerrit-PatchSet: 1
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Yuvipanda <yuvipa...@gmail.com>

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

Reply via email to