diff --git a/docs/getting-started.md b/docs/getting-started.md index ec49e5c13..824a1b550 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -51,12 +51,12 @@ please [open an issue on GitHub](/support){: .alert-link}.
- Download for LEGO MINDSTORMS EV3 + Download for LEGO MINDSTORMS EV3

Other platforms

-Raspberry Pi 1 -Raspberry Pi 2 -BeagleBone +Raspberry Pi Model Zero/1 +Raspberry Pi Model 2/3 +BeagleBone

diff --git a/download.md b/download.md index 458bc6ed0..916b1544e 100644 --- a/download.md +++ b/download.md @@ -28,9 +28,9 @@ no-wrapper: true the primary focus of development.

- + - Download for EV3 + LEGO MINDSTORMS EV3
- + - Download for Raspberry Pi Model 0/1 + Raspberry Pi Model Zero/1
- + - Download for Raspberry Pi Model 2/3 + Raspberry Pi Model 2/3
@@ -75,9 +75,9 @@ no-wrapper: true

- + - Download for BeagleBone + BeagleBone
diff --git a/javascripts/api-cache.js b/javascripts/api-cache.js index 119e4476d..6179a1ec9 100644 --- a/javascripts/api-cache.js +++ b/javascripts/api-cache.js @@ -8,18 +8,20 @@ function supportsHtml5Storage() { } } -function getApiValue(endpointUrl, cacheTime, callback) { - try { - var cacheData = supportsHtml5Storage() ? JSON.parse(localStorage[cacheKey]) : null; - // This does an exact match for the URL given. Different spacing, duplicate slashes, - // alternate caps, etc. will result in the cache being bypassed. - if (cacheData && cacheData[endpointUrl] && Date.now() - cacheData[endpointUrl].dateRetrieved < cacheTime) { - callback(cacheData[endpointUrl].requestResult); - return; +function getApiValue(endpointUrl, cacheTime, callback, clearCache) { + if(clearCache != true) { + try { + var cacheData = supportsHtml5Storage() ? JSON.parse(localStorage[cacheKey]) : null; + // This does an exact match for the URL given. Different spacing, duplicate slashes, + // alternate caps, etc. will result in the cache being bypassed. + if (cacheData && cacheData[endpointUrl] && Date.now() - cacheData[endpointUrl].dateRetrieved < cacheTime) { + callback(cacheData[endpointUrl].requestResult); + return; + } + } + catch (e) { + // Ignore the error; if the saved JSON is invalid, we'll just request it from the server. } - } - catch (e) { - // Ignore the error; if the saved JSON is invalid, we'll just request it from the server. } console.log('No cached copy of API data for endpoint "' + endpointUrl + '" found. Downloading from remote server.'); diff --git a/javascripts/releases.js b/javascripts/releases.js index fc58d256f..51f0b6021 100644 --- a/javascripts/releases.js +++ b/javascripts/releases.js @@ -1,54 +1,89 @@ -// Cache will time out after 20 minutes -var releaseCacheTimeMillis = 20 * 60 * 1000; +// Cache will time out after five minutes +var releaseCacheTimeMillis = 5 * 60 * 1000; var releasePlatformRegexes = { - ev3: "ev3dev-jessie-ev3-generic-[\\d-]+\\.zip", - rpi: "ev3dev-jessie-rpi-generic-[\\d-]+\\.zip", - rpi2: "ev3dev-jessie-rpi2-generic-[\\d-]+\\.zip", - bone: "ev3dev-jessie-bone-generic-[\\d-]+\\.zip", + ev3: /ev3dev-jessie-ev3-generic-[\d-]+\.zip/, + rpi: /ev3dev-jessie-rpi-generic-[\d-]+\.zip/, + rpi2: /ev3dev-jessie-rpi2-generic-[\d-]+\.zip/, + bone: /ev3dev-jessie-bone-generic-[\d-]+\.zip/, } -function initDownloadLinks() { - getApiValue('https://api.github.com/repos/ev3dev/ev3dev/releases', releaseCacheTimeMillis, function (releases, error) { - if(error) { - console.error("Download links not available! Falling back to static content."); - $('.release-link-container').hide(); - $('.release-link-alt').show(); - +function loadReleasesByPlatform(successCallback, errorCallback) { + getApiValue('https://api.github.com/repos/ev3dev/ev3dev/releases', releaseCacheTimeMillis, function (releasesApiData, error) { + if (error) { + errorCallback(error); return; } - - releases.sort(function (a, b) { - if (Date.parse(a['created_at']) < Date.parse(b['created_at'])) - return 1; - if (Date.parse(a['created_at']) > Date.parse(b['created_at'])) - return -1; - - return 0; + + var releaseMap = {}; + releasesApiData.forEach(function (releaseApiData) { + releaseApiData['assets'].forEach(function (assetApiData) { + var assetPlatform = $.grep(Object.keys(releasePlatformRegexes), function (platId) { + return releasePlatformRegexes[platId].test(assetApiData['name']); + })[0]; + + if (!assetPlatform) + return true; + + if (!Array.isArray(releaseMap[assetPlatform])) + releaseMap[assetPlatform] = []; + + releaseMap[assetPlatform].push({ + releaseName: releaseApiData['name'], + assetName: assetApiData['name'], + creationDate: Date.parse(releaseApiData['created_at']), + platform: assetPlatform, + size: assetApiData['size'], + downloadUrl: assetApiData['browser_download_url'] + }); + }); }); - $('a[data-release-link-platform]').each(function (i, element) { + Object.keys(releaseMap).forEach(function (platformId) { + releaseMap[platformId].sort(function (a, b) { + return (b.creationDate > a.creationDate) - (b.creationDate < a.creationDate); + }); + }) + + successCallback(releaseMap); + }); +} + +function initDownloadLinks() { + loadReleasesByPlatform(function (releaseMap) { + + $('a[data-download-button-platform]').each(function (i, element) { var $linkElem = $(element); - var targetReleasePlatform = $linkElem.data('release-link-platform'); - if (!releasePlatformRegexes[targetReleasePlatform]) { - console.error('"' + targetReleasePlatform + '" is an invalid release target.'); + var targetReleasePlatform = $linkElem.data('download-button-platform'); + var targetRelease = (releaseMap[targetReleasePlatform] || [])[0]; + + if (!targetRelease) { + console.error('"' + targetReleasePlatform + '" is an invalid release target or no releases for the given platform exist.'); return true; } - var platformRegex = new RegExp(releasePlatformRegexes[targetReleasePlatform]); - - for (var releaseIndex in releases) { - var releaseAssets = releases[releaseIndex].assets; - for (var assetIndex in releaseAssets) { - if (platformRegex.test(releaseAssets[assetIndex].name)) { - $linkElem.attr('href', releaseAssets[assetIndex]['browser_download_url']); - var fileSize = releaseAssets[assetIndex]['size'] >> 20; - $('').text(' (' + fileSize + ' MiB)').appendTo($linkElem); - return true; - } - } + $linkElem.attr('href', targetRelease.downloadUrl); + $linkElem.addClass('btn-group-vertical download-button-container'); + + var $upperSection = $linkElem.children('.download-button-upper'); + if($upperSection.length <= 0) { + var $contents = $linkElem.contents(); + $upperSection = $('').addClass('btn btn-primary download-button-upper').appendTo($linkElem); + $contents.appendTo($upperSection); } + + $linkElem.children('.download-button-lower').remove(); + var $lowerSection = $('').addClass('btn download-button-lower').text(targetRelease.assetName).appendTo($linkElem); + + var fileSize = targetRelease.size >> 20; + $('').addClass('download-info-label badge').text(fileSize + ' MiB').appendTo($lowerSection); + }); + }, + function (error) { + console.error("Download links not available! Falling back to static content."); + $('.release-link-container').hide(); + $('.release-link-alt').show(); }); } @@ -57,8 +92,8 @@ $(document).ready(function () { // We do this as soon as the document loads so that the page flash is minimal. $('.release-link-alt').hide(); $('.release-link-container').show(); - - if ($('a[data-release-link-platform]').length > 0) { + + if ($('a[data-download-button-platform]').length > 0) { initDownloadLinks(); } }); \ No newline at end of file diff --git a/stylesheets/page-content.scss b/stylesheets/page-content.scss index a8563ef3a..3f9f640f1 100644 --- a/stylesheets/page-content.scss +++ b/stylesheets/page-content.scss @@ -30,8 +30,10 @@ margin: 5px 0 5px !important; } -.download-button-small { - margin: 0 6px; +.stacked-download-button { + margin-top: 7px; + margin-left: 15px; + margin-right: 15px; } .dark-bg { diff --git a/stylesheets/site-structure.scss b/stylesheets/site-structure.scss index 04fa6faa4..8c83717ea 100644 --- a/stylesheets/site-structure.scss +++ b/stylesheets/site-structure.scss @@ -152,6 +152,143 @@ ul + p, ol + p { font-size: 22px; } +.download-button-container { + text-decoration: none !important; + cursor: pointer; + touch-action: manipulation; + + * { + pointer-events: none; + } + + // The following styles are an adaptation of those for standard buttons; from mixins/_buttons.scss + // Darken percentages for the lower half are lessened manually because the lower half is already dark + &:focus, + &.focus { + .download-button-upper { + background-color: darken($brand-primary, 10%); + border-color: darken($brand-primary, 25%); + } + + .download-button-lower { + background-color: darken($gray, 7%); + border-color: darken($gray, 15%); + } + } + &:hover { + .download-button-upper { + background-color: darken($brand-primary, 10%); + border-color: darken($brand-primary, 12%); + } + + .download-button-lower { + background-color: darken($gray, 7%); + border-color: darken($gray, 9%); + } + } + + &:active, + &.active, + .open > &.dropdown-toggle { + .download-button-upper { + background-color: darken($brand-primary, 10%); + border-color: darken($brand-primary, 12%); + } + .download-button-lower { + background-color: darken($gray, 7%); + border-color: darken($gray, 9%); + } + + &:hover, + &:focus, + &.focus { + .download-button-upper { + background-color: darken($brand-primary, 17%); + border-color: darken($brand-primary, 25%); + } + .download-button-lower { + background-color: darken($gray, 13%); + border-color: darken($gray, 15%); + } + } + } + &.disabled, + &[disabled], + fieldset[disabled] & { + &, + &:hover, + &:focus, + &.focus, + &:active, + &.active { + .download-button-upper { + background-color: $brand-primary; + border-color: $brand-primary; + } + + .download-button-lower { + background-color: $gray; + border-color: $gray; + } + } + } + + .download-button-upper { + font-weight: bold; + } + + .download-button-lower { + background-color: $gray; + color: white; + + padding-top: 4px; + padding-bottom: 4px; + + .badge { + color: $gray; + background-color: white; + + padding: 2px 5px; + } + } + + &.btn-group-lg { + .download-button-upper { + font-size: 25px; + } + + .download-button-lower { + font-size: 85%; + height: 30px; + + .badge { + font-size: 11px; + margin-right: -10px; + margin-left: 10px; + } + } + } + + &.btn-group-md { + .download-button-upper { + font-size: 17px; + } + + .download-button-lower { + font-size: 75%; + height: 25px; + + .badge { + font-size: 10px; + margin-right: -10px; + margin-left: 10px; + } + } + } + + // small and extra-small download buttons are not used +} + // thanks http://stackoverflow.com/a/32490429/1976323 $margins: (xs: 0.5rem, sm: 1rem, md: 1.5rem, lg: 2rem, xl: 2.5rem);