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