From 837437097c1d0d1390b1750b7e44e6b319171c77 Mon Sep 17 00:00:00 2001 From: TC Date: Thu, 28 Jul 2016 15:00:05 -0700 Subject: [PATCH] Add webpack with single file loading --- .gitignore | 1 + README.md | 8 + bundle.js | 436 +++++++++++++++++++++++++++ events/break-free/index.html | 6 +- events/index.html | 6 +- events/living-dangerously/index.html | 6 +- index.html | 10 +- js/action-kit-service.js | 10 +- js/config.js | 2 +- js/control-shift-service.js | 10 +- js/icon-service.js | 4 +- js/script.js | 17 +- js/template-service.js | 4 +- webpack.config.js | 12 + 14 files changed, 493 insertions(+), 39 deletions(-) create mode 100644 bundle.js create mode 100644 webpack.config.js diff --git a/.gitignore b/.gitignore index 303fc17..3829562 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ *~ .idea .DS_Store +node_modules/ diff --git a/README.md b/README.md index a510e29..c1eb13b 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,11 @@ 1. Make sure you have `bower` [installed](https://bower.io/#install-bower): `npm install -g bower` 2. Run `bower install` to download all dependencies +3. Make sure you have `webpack` and `webpack-dev-server` installed: `npm install -g webpack webpack-dev-server` + +## Running the server + +1. Run `webpack-dev-server --progress --colors` +2. Go to [http://localhost:8080/webpack-dev-server/](http://localhost:8080/webpack-dev-server/) +3. Webpack bundles the files once they are changed, so no need to restart the server to pickup new code! + diff --git a/bundle.js b/bundle.js new file mode 100644 index 0000000..ba5b89a --- /dev/null +++ b/bundle.js @@ -0,0 +1,436 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { + + document.write(__webpack_require__(1)); + +/***/ }, +/* 1 */ +/***/ function(module, exports) { + + var getMegamapArgs = function() { + var argsStr = window.location.search.replace(/^\?/, ''); + var embedArgsStr = $("script[src='bundle.js']").data("map-args") || ''; + + if (argsStr) { + argsStr += '&' + embedArgsStr; + } else { + argsStr = embedArgsStr; + } + + var pairs = argsStr.replace(/^\?/, '').split('&'); + var args = {}; + unesc = unescape; + if (typeof(decodeURIComponent) != 'undefined') + unesc = decodeURIComponent; + for (var i = 0; i < pairs.length; ++i) { + pair = pairs[i].split('='); + if (pair[0]) { + if (pair[1]) + pair[1] = unesc(pair[1].replace(/\+/g, ' ')); + var key = unesc(pair[0].replace(/\+/g, ' ')); + if (key == "layer") { + if (!args[key]) { + args[key] = []; + } + args[key].push(pair[1]); + } else { + args[key] = pair[1]; + } + } + } + return args; + }; + + var args = getMegamapArgs(); + + if (args.css) { + var _x = document.createElement("link"); + _x.rel = "stylesheet"; + _x.type = "text/css"; + _x.href = args.css; + document.body.appendChild(_x) + } + + var lat = parseFloat(args.lat) || 0, + lng = parseFloat(args.lng) || 0, + zoom = parseInt(args.zoom) || 2, + locate = (args.gl !== "n"), + searchZoom = parseInt(args.searchZoom) || 8, + layerControl = args.lc !== "n", + layerControlAlwaysShown = args.lc !== "h", + addMarkerControl = args.amc !== "n", + hidePastEvents = args.hpe !== "n", + dateAttribute = args.dateAttr || "date", + layersToShow = args.layer, + markerClusterRadius = parseInt(args.clusterRadius) || 80, + public_data_layer_queue = [], + public_data_layers = {}, + form_templates = {}, + MAP_waiting = 0, + layers = {}, + clusters, + icons = {}; + + var map = new L.Map('map', { + "zoomControl": false, + "maxZoom": 16 + }).setView([lat, lng], zoom); + if (locate) { + map.locate({ + setView: true, + maxZoom: 10 + }); + } + map.scrollWheelZoom.disable(); + + L.esri.basemapLayer("Streets").addTo(map); + + var $controlContainer = $(map._controlContainer); + + if ($controlContainer.children('.leaflet-top.leaflet-center').length == 0) { + $controlContainer.append('
'); + map._controlCorners.topcenter = $controlContainer + .children('.leaflet-top.leaflet-center').first()[0]; + } + new L.Control.GeoSearch({ + provider: new L.GeoSearch.Provider.Google(), + "zoomLevel": searchZoom, + "showMarker": false, + "searchLabel": 'search for address...', + "position": 'topcenter' + }).addTo(map); + + // Here's the Tabletop feed + // First we'll initialize Tabletop with our spreadsheet + var jqueryNoConflict = jQuery; + + jqueryNoConflict(document).ready(function() { + var scriptTag = $("script[src='bundle.js']"); + var root_spreadsheet = scriptTag.data("spreadsheet"); + + fetchActionKitData(args.actionkit, function(actionKitLayerGroups) { + $.extend(layers, actionKitLayerGroups); + Object.keys(actionKitLayerGroups).forEach(function(campaignName) { + icons[campaignName] = getEventIcon(); + }); + + fetchControlShiftData(args.controlshift, function(controlShiftLayerGroups) { + $.extend(layers, controlShiftLayerGroups); + Object.keys(controlShiftLayerGroups).forEach(function(category) { + icons[category] = getPetitionIcon(); + }); + + initializeTabletopObject(root_spreadsheet); + }); + }); + }); + + // Pull data from Google spreadsheet + // And push to our startUpLeaflet function + function initializeTabletopObject(dataSpreadsheet) { + Tabletop.init({ + key: dataSpreadsheet, + callback: startUpLeafet, + debug: false + //proxy: "//ejucovy.github.io/megamap-data" + }); + } + // This function gets our data from our spreadsheet + // Then gets it ready for Leaflet. + // It creates the marker, sets location + // And plots on it on our map + function startUpLeafet(spreadsheetData) { + var fallbackTemplate = ''; + var default_template = Handlebars.compile($("#handlebars_template").html() || fallbackTemplate); + + var templates = {}; + for (var i = 0; i < spreadsheetData.Layers.elements.length; ++i) { + var row = spreadsheetData.Layers.elements[i]; + if (row.Template) { + templates[row.Type] = Handlebars.compile(row.Template); + } + if (row.PublicSubmissionForm) { + form_templates[row.Type] = Handlebars.compile(row.PublicSubmissionForm); + } + if (row.PublicSubmissionSpreadsheet) { + public_data_layer_queue.push(row.Type); + public_data_layers[row.Type] = row.PublicSubmissionSpreadsheet; + } + } + + for (var i = 0; i < spreadsheetData.Markers.elements.length; ++i) { + var row = spreadsheetData.Markers.elements[i]; + icons[row.type] = L.icon({ + iconUrl: row.iconurl, + iconSize: [parseInt(row.iconwidth), parseInt(row.iconheight)], + iconAnchor: [parseInt(row.iconanchorx), parseInt(row.iconanchory)], + popupAnchor: [parseInt(row.popupanchorx), parseInt(row.popupanchory)], + shadowUrl: row.shadowurl, + shadowSize: [parseInt(row.shadowwidth), parseInt(row.shadowheight)], + shadowAnchor: [parseInt(row.shadowanchorx), parseInt(row.shadowanchory)], + }); + } + + // Initialize some layers by hand to force a certain display order + if (!args.notmainpage) { + layers['Local Groups'] = L.layerGroup(); + } + + clusters = L.markerClusterGroup({ + maxClusterRadius: markerClusterRadius + }); + + var testDate = new Date(); + testDate.setHours(testDate.getHours() - 12); + $.each(spreadsheetData, function(data_type, elements) { + if (data_type == "Markers" || data_type == "Layers") { + return; + } + var tabletopData = elements.elements; + for (var num = 0; num < tabletopData.length; num++) { + var dataLat = tabletopData[num].latitude; + var dataLong = tabletopData[num].longitude; + if (!dataLat || !dataLong || !parseFloat(dataLat) || !parseFloat(dataLong)) { + continue; + } + var date = tabletopData[num][dateAttribute]; + if (hidePastEvents && date) { + date = new Date(date); + if (!isNaN(date.getTime())) { + if (date <= testDate) { + continue; + } + } + } + var marker_location = new L.LatLng(dataLat, dataLong); + if (icons[data_type]) { + var layer = new L.Marker(marker_location, { + "icon": icons[data_type] + }); + } else { + var layer = new L.Marker(marker_location); + } + // Create the popup by rendering handlebars template + var popup = templates[data_type] && templates[data_type](tabletopData[num]); + // Add to our marker + if (popup) { + layer.bindPopup(popup); + } + + var layerGroup = layers[data_type]; + if (typeof(layerGroup) === "undefined") { + layers[data_type] = layerGroup = L.layerGroup(); + } + + // Add marker to our to map + layerGroup.addLayer(layer); + } + }); + + nextStepInMapSetup(); + } + + function fetchPublicDataSpreadsheets() { + var data_type = public_data_layer_queue.pop(); + + if (public_data_layers[data_type] && (!layersToShow || $.inArray(data_type, layersToShow) !== -1)) { + MAP_waiting += 1; + Tabletop.init({ + key: public_data_layers[data_type], + callback: function(public_data) { + + var testDate = new Date(); + testDate.setHours(testDate.getHours() - 12); + + for (var i = 0; i < public_data.length; ++i) { + var public_row = public_data[i]; + + var date = public_row[dateAttribute]; + if (hidePastEvents && date) { + date = new Date(date); + if (!isNaN(date.getTime())) { + if (date <= testDate) { + continue; + } + } + } + + var marker_location = new L.LatLng(public_row.latitude, public_row.longitude); + + if (icons[data_type]) { + var layer = new L.Marker(marker_location, { + "icon": icons[data_type] + }); + } else { + var layer = new L.Marker(marker_location); + } + // Create the popup by rendering handlebars template + var popup = (templates[data_type] || default_template)(public_row); + // Add to our marker + layer.bindPopup(popup); + + var layerGroup = layers[data_type]; + + if (typeof(layerGroup) === "undefined") { + layers[data_type] = layerGroup = L.layerGroup(); + } + + // Add marker to our to map + layerGroup.addLayer(layer); + clusters.removeLayers(layerGroup.getLayers()); + clusters.addLayers(layerGroup.getLayers()); + } + --MAP_waiting; + nextStepInMapSetup(); + }, + simpleSheet: true, + debug: false + //proxy: "//350dotorg.github.io/megamap-data" + }); + } + + } + + function populateMap() { + var uiLayers = {}; + $.each(layers, function(i, n) { + if (!layersToShow || ($.inArray(i, layersToShow) !== -1)) { + clusters.addLayers(n.getLayers()); + uiLayers[i] = L.layerGroup().addTo(map); + } + }); + + clusters.addTo(map); + + if (layerControl) { + var _control = L.control.legendlayers(null, uiLayers, icons).addTo(map); + if (layerControlAlwaysShown) { + $(_control._container) + .addClass("leaflet-control-layers-always-expanded"); + } + } + + if (addMarkerControl) { + var allowed = {}, + numAllowed = 0; + $.each(uiLayers, function(i, n) { + if (form_templates[i] && public_data_layers[i]) { + allowed[i] = n; + ++numAllowed; + } + }); + if (numAllowed) { + L.control.addmarker(allowed, icons).addTo(map); + } + } + new L.Control.Zoom({ + position: 'topleft' + }).addTo(map); + + // https://github.com/Leaflet/Leaflet.markercluster/issues/145#issuecomment-19439160 + map.on("overlayadd", function(e) { + clusters.addLayers(layers[e.name].getLayers()); + }).on("overlayremove", function(e) { + clusters.removeLayers(layers[e.name].getLayers()); + }).on("addmarker_geosearch_showlocation", function(e) { + var lat = e.Location.Y, + lng = e.Location.X, + text = e.Location.Label, + layer = e.Layer; + + var form_template = form_templates[layer.name]; + e.Marker.bindPopup(form_template({ + lat: lat, + lng: lng, + location: text, + query: e.Query + })).fire("click"); + }); + + } + + function nextStepInMapSetup() { + if (public_data_layer_queue && public_data_layer_queue.length) { + if (MAP_waiting) { + window.setTimeout(nextStepInMapSetup, 200); + return false; + } else { + fetchPublicDataSpreadsheets(); + } + } else { + populateMap(); + } + } + + // Toggle for 'About this map' and X buttons + // Only visible on mobile + isVisibleDescription = false; + // Grab header, then content of sidebar + sidebarHeader = $('.sidebar_header').html(); + sidebarContent = $('.sidebar_content').html(); + // Then grab credit information + creditsContent = $('.leaflet-control-attribution').html(); + $('.toggle_description').click(function() { + if (isVisibleDescription === false) { + $('.description_box_cover').show(); + // Add Sidebar header into our description box + // And 'Scroll to read more...' text on wide mobile screen + $('.description_box_header').html(sidebarHeader + '
Scroll to read more...
'); + // Add the rest of our sidebar content, credit information + $('.description_box_text').html(sidebarContent + '
'); + $('#caption_box').html('Credits: ' + creditsContent); + $('.description_box').show(); + isVisibleDescription = true; + } else { + $('.description_box').hide(); + $('.description_box_cover').hide(); + isVisibleDescription = false; + } + }); + + +/***/ } +/******/ ]); \ No newline at end of file diff --git a/events/break-free/index.html b/events/break-free/index.html index fc08c06..3be2499 100644 --- a/events/break-free/index.html +++ b/events/break-free/index.html @@ -68,10 +68,6 @@ {{ description }} - - - - @@ -86,7 +82,7 @@ + src="bundle.js"> diff --git a/events/index.html b/events/index.html index db024fe..a80cd49 100644 --- a/events/index.html +++ b/events/index.html @@ -72,10 +72,6 @@ {{ description }} - - - - @@ -90,7 +86,7 @@ + src="bundle.js"> diff --git a/events/living-dangerously/index.html b/events/living-dangerously/index.html index f09016a..48296de 100644 --- a/events/living-dangerously/index.html +++ b/events/living-dangerously/index.html @@ -83,10 +83,6 @@ {{ description }} - - - - @@ -101,6 +97,6 @@ + src="bundle.js"> diff --git a/index.html b/index.html index 9d58f3d..b7e06e9 100755 --- a/index.html +++ b/index.html @@ -61,12 +61,6 @@ - - - - - - @@ -80,7 +74,9 @@
- + + + diff --git a/js/action-kit-service.js b/js/action-kit-service.js index 7302349..76126b7 100644 --- a/js/action-kit-service.js +++ b/js/action-kit-service.js @@ -1,4 +1,8 @@ -function fetchActionKitData(campaignsString, callback) { +var config = require("./config.js"); +var iconService = require("./icon-service.js"); +var templateService = require("./template-service.js"); + +module.exports.fetchActionKitData = function fetchActionKitData(campaignsString, callback) { if (!campaignsString) { callback({}); return; @@ -6,7 +10,7 @@ function fetchActionKitData(campaignsString, callback) { var separator = '|'; var campaigns = campaignsString.split(separator); - var compiledTemplate = Handlebars.compile(getActionKitTemplate()); + var compiledTemplate = Handlebars.compile(templateService.getActionKitTemplate()); var layerGroups = {}; var actionKitRequests = []; @@ -20,7 +24,7 @@ function fetchActionKitData(campaignsString, callback) { if (data.events) { data.events.forEach(function(event) { if (event.latitude && event.longitude) { - var marker = L.marker([event.latitude, event.longitude], {icon: getEventIcon()}); + var marker = L.marker([event.latitude, event.longitude], {icon: iconService.getEventIcon()}); event.start_time = moment(event.start_time, 'H:mm:ss').format("h:mma"); event.event_date = moment(event.event_date).format("MMMM D, YYYY"); marker.bindPopup(compiledTemplate(event)); diff --git a/js/config.js b/js/config.js index 3f899bb..7b1a02c 100644 --- a/js/config.js +++ b/js/config.js @@ -1,3 +1,3 @@ -var config = { +module.exports = { actionKitUrl: 'https://act.350.org/event/' }; diff --git a/js/control-shift-service.js b/js/control-shift-service.js index cef5b7e..db760be 100644 --- a/js/control-shift-service.js +++ b/js/control-shift-service.js @@ -1,15 +1,19 @@ +var config = require("./config.js"); +var iconService = require("./icon-service.js"); +var templateService = require("./template-service.js"); + var urlSeparator = ':'; var categorySeparator = '|'; var characterLimit = 200; -var compiledTemplate = Handlebars.compile(getControlShiftTemplate()); +var compiledTemplate = Handlebars.compile(templateService.getControlShiftTemplate()); var firstPageRequests = []; var allPageRequests = []; var layerGroups = {}; -function fetchControlShiftData(categoriesString, callback) { +module.exports.fetchControlShiftData = function(categoriesString, callback) { if (!categoriesString) { callback({}); return; @@ -83,7 +87,7 @@ function createCampaignMarkers(data) { var location = petition.location; if (location.latitude && location.longitude) { - var marker = L.marker([location.latitude, location.longitude], {icon: getPetitionIcon()}); + var marker = L.marker([location.latitude, location.longitude], {icon: iconService.getPetitionIcon()}); marker.bindPopup(compiledTemplate(petition)); markers.addLayer(marker); } diff --git a/js/icon-service.js b/js/icon-service.js index 0f46206..ab6460b 100644 --- a/js/icon-service.js +++ b/js/icon-service.js @@ -1,11 +1,11 @@ -function getEventIcon() { +module.exports.getEventIcon = function() { return L.icon({ iconUrl: 'images/calendar-icon.png', iconSize: [32, 36] }); } -function getPetitionIcon() { +module.exports.getPetitionIcon = function() { return L.icon({ iconUrl: 'images/petition-icon.png', iconSize: [32, 36] diff --git a/js/script.js b/js/script.js index 69832df..1a226de 100755 --- a/js/script.js +++ b/js/script.js @@ -1,6 +1,11 @@ +var config = require("./config.js"); +var iconService = require("./icon-service.js"); +var actionKitService = require("./action-kit-service.js"); +var controlShiftService = require("./control-shift-service.js"); + var getMegamapArgs = function() { var argsStr = window.location.search.replace(/^\?/, ''); - var embedArgsStr = $("script[src='js/script.js']").data("map-args") || ''; + var embedArgsStr = $("script[src='bundle.js']").data("map-args") || ''; if (argsStr) { argsStr += '&' + embedArgsStr; @@ -96,19 +101,19 @@ new L.Control.GeoSearch({ var jqueryNoConflict = jQuery; jqueryNoConflict(document).ready(function() { - var scriptTag = $("script[src='js/script.js']"); + var scriptTag = $("script[src='bundle.js']"); var root_spreadsheet = scriptTag.data("spreadsheet"); - fetchActionKitData(args.actionkit, function(actionKitLayerGroups) { + actionKitService.fetchActionKitData(args.actionkit, function(actionKitLayerGroups) { $.extend(layers, actionKitLayerGroups); Object.keys(actionKitLayerGroups).forEach(function(campaignName) { - icons[campaignName] = getEventIcon(); + icons[campaignName] = iconService.getEventIcon(); }); - fetchControlShiftData(args.controlshift, function(controlShiftLayerGroups) { + controlShiftService.fetchControlShiftData(args.controlshift, function(controlShiftLayerGroups) { $.extend(layers, controlShiftLayerGroups); Object.keys(controlShiftLayerGroups).forEach(function(category) { - icons[category] = getPetitionIcon(); + icons[category] = iconService.getPetitionIcon(); }); initializeTabletopObject(root_spreadsheet); diff --git a/js/template-service.js b/js/template-service.js index 91dd26c..2cf1a57 100644 --- a/js/template-service.js +++ b/js/template-service.js @@ -1,4 +1,4 @@ -function getActionKitTemplate() { +module.exports.getActionKitTemplate = function() { return '