Quellcode durchsuchen

Offline mode

master
Flo Smilari vor 4 Jahren
Ursprung
Commit
1d35dc8d81

+ 9
- 0
Components/DoneImage.razor Datei anzeigen

@@ -0,0 +1,9 @@
@page "/doneimage"
<div class="text-center">
<img src="./images/done.png" class="w-50" alt="Done!" />
</div>
@code {
}

+ 9
- 0
Components/FailureImage.razor Datei anzeigen

@@ -0,0 +1,9 @@
@page "/failureimage"
<div class="text-center">
<img src="./images/failure.png" class="w-50" alt="Failure!" />
</div>
@code {
}

+ 38
- 0
Components/OnlineStatusIndicator.razor Datei anzeigen

@@ -0,0 +1,38 @@
@using cwebplusApp.Shared.Services;
@implements IDisposable;
@inject OnlineStatusProvider OnlineStatusProvider;
<div class="row no-gutters w-100 justify-content-end" style="position: absolute;">
@if (isOffline) {
<MatIcon Style="padding-right:0.5rem">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M21 11l2-2c-3.73-3.73-8.87-5.15-13.7-4.31l2.58 2.58c3.3-.02 6.61 1.22 9.12 3.73zm-2 2c-1.08-1.08-2.36-1.85-3.72-2.33l3.02 3.02.7-.69zM9 17l3 3 3-3c-1.65-1.66-4.34-1.66-6 0zM3.41 1.64L2 3.05 5.05 6.1C3.59 6.83 2.22 7.79 1 9l2 2c1.23-1.23 2.65-2.16 4.17-2.78l2.24 2.24C7.79 10.89 6.27 11.74 5 13l2 2c1.35-1.35 3.11-2.04 4.89-2.06l7.08 7.08 1.41-1.41L3.41 1.64z" />
</svg>
</MatIcon>
}
</div>
@code {
private bool isOffline;
public void Dispose() {
OnlineStatusProvider.RemoveOnlineStatusChangeCallBack(OnOnlineStatusChanged);
}
protected override void OnInitialized() {
base.OnInitialized();
OnlineStatusProvider.AddOnlineStatusChangeCallBack(OnOnlineStatusChanged);
OnOnlineStatusChanged(OnlineStatusProvider.Online);
}
private void OnOnlineStatusChanged(bool isOnline) {
this.isOffline = !isOnline;
StateHasChanged();
}
}

+ 3
- 2
Pages/CaritasServiceFundVeloFoundConclusion.razor Datei anzeigen

@@ -2,12 +2,13 @@
@using cwebplusApp.Shared.Services;
@using cwebplusApp.Shared.Models;
@using cwebplusApp.Components;
@inject NavigationManager NavigationManager;
@inject IStringLocalizer<Resources> i18n;
@inject PageHistoryManager PageHistoryManager;
@inject ReportDataProvider ReportDataProvider;
@inject ILFBicycleRest ILFBicycleRest;
@inject IBicycleRestService IBicycleRestService;
@inject Toaster Toaster;
@inject AppState AppState;
@@ -65,7 +66,7 @@
base.OnInitialized();
PageHistoryManager.AddPageToHistory(NavigationManager.Uri);
try {
response = await ILFBicycleRest.SendFoundReport(ReportDataProvider.Report);
response = await IBicycleRestService.SendFoundReport(ReportDataProvider.Report);
responseOk = System.Net.HttpStatusCode.OK == response.StatusCode ? true : false;
} catch (HttpRequestException ex) {
response = new(i18n.GetString("FoundBike"), new string[] { ex.Message });

+ 30
- 17
Pages/CaritasServiceFundVeloFoundKeyDataPage.razor Datei anzeigen

@@ -1,6 +1,7 @@
@page "/fundvelo/keydata/Found"
@inherits CaritasServiceFundVeloKeyDataPageBase
@implements IDisposable;
@using cwebplusApp.Shared.Models;
@using cwebplusApp.Shared.Services;
@@ -15,6 +16,7 @@
@inject Toaster Toaster
@inject IJSRuntime JS
@inject ReportDataProvider ReportDataProvider
@inject OnlineStatusProvider OnlineStatusProvider
<div class="row px-3 h-100">
<div class="row no-gutters align-items-center justify-content-center w-100" style="padding-top:1em">
@@ -68,23 +70,25 @@
</MatCard>
</div>
</div>
<div class="mat-layout-grid-cell mat-layout-grid-cell-span-1 justify-content-center" style="text-align: center">
<MatRipple class="inputfile-mat-ripple" Color="@MatRippleColor.Default" @onclick="InitializeMapPosition">
<label>
<svg xmlns="http://www.w3.org/2000/svg" height="48px" width="48px" viewBox="0 0 24 24" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M13 3.06V1h-2v2.06C6.83 3.52 3.52 6.83 3.06 11H1v2h2.06c.46 4.17 3.77 7.48 7.94 7.94V23h2v-2.06c4.17-.46 7.48-3.77 7.94-7.94H23v-2h-2.06c-.46-4.17-3.77-7.48-7.94-7.94zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z" />
<circle cx="12" cy="12" opacity=".3" r="2" />
<path d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z" />
</svg>
</label>
</MatRipple>
</div>
<div class="mat-layout-grid-cell mat-layout-grid-cell-span-3">
<div class="w-100 fv-osm-tile map-wrapper">
<Map @ref="mapRef" MapOptions="@mapOptions" AfterRender="AfterRenderMap"></Map>
@if (OnlineStatusProvider.Online) {
<div class="mat-layout-grid-cell mat-layout-grid-cell-span-1 justify-content-center" style="text-align: center">
<MatRipple class="inputfile-mat-ripple" Color="@MatRippleColor.Default" @onclick="InitializeMapPosition">
<label>
<svg xmlns="http://www.w3.org/2000/svg" height="48px" width="48px" viewBox="0 0 24 24" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none" />
<path d="M13 3.06V1h-2v2.06C6.83 3.52 3.52 6.83 3.06 11H1v2h2.06c.46 4.17 3.77 7.48 7.94 7.94V23h2v-2.06c4.17-.46 7.48-3.77 7.94-7.94H23v-2h-2.06c-.46-4.17-3.77-7.48-7.94-7.94zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z" />
<circle cx="12" cy="12" opacity=".3" r="2" />
<path d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z" />
</svg>
</label>
</MatRipple>
</div>
</div>
<div class="mat-layout-grid-cell mat-layout-grid-cell-span-3">
<div class="w-100 fv-osm-tile map-wrapper">
<Map @ref="mapRef" MapOptions="@mapOptions" AfterRender="AfterRenderMap"></Map>
</div>
</div>
}
<div class="mat-layout-grid-cell mat-layout-grid-cell-span-4-phone mat-layout-grid-cell-span-8-tablet mat-layout-grid-cell-span-4-desktop">
<div class="mat-layout-grid-inner">
<div class="mat-layout-grid-cell mat-layout-grid-cell-span-4-phone mat-layout-grid-cell-span-4-tablet mat-layout-grid-cell-span-12-desktop">
@@ -190,6 +194,10 @@
private string remark;
private bool abholadresseIsNotContact;
public void Dispose() {
OnlineStatusProvider.RemoveOnlineStatusChangeCallBack(OnOnlineStatusChanged);
}
protected async override void OnInitialized() {
base.OnInitialized();
await GetColors();
@@ -197,6 +205,11 @@
await GetBrands();
refreshGUIFromDto();
PageHistoryManager.AddPageToHistory(NavigationManager.Uri);
OnlineStatusProvider.AddOnlineStatusChangeCallBack(OnOnlineStatusChanged);
StateHasChanged();
}
private void OnOnlineStatusChanged(bool isOnline) {
StateHasChanged();
}
@@ -296,7 +309,7 @@
bicycleGeoPosition.Longitude = report.GeographicInfo.Longitude;
imgUrl = report.FotoString;
selectedColor = Array.Find(Colors, color => color.Id == report.FarbeId);
selectedBrand = String.IsNullOrEmpty(report.NeueMarke) ? Array.Find(Brands, brand => brand.Id == report.MarkeId): new Brand(-999, report.NeueMarke);
selectedBrand = String.IsNullOrEmpty(report.NeueMarke) ? Array.Find(Brands, brand => brand.Id == report.MarkeId) : new Brand(-999, report.NeueMarke);
selectedBcType = Array.Find(BicycleTypes, bcType => bcType.Id == report.TypId);
frameNumber = report.RahmenNummer;
remark = report.Bemerkung;

+ 3
- 2
Pages/CaritasServiceFundVeloMissingConclusion.razor Datei anzeigen

@@ -2,12 +2,13 @@
@using cwebplusApp.Shared.Services;
@using cwebplusApp.Shared.Models;
@using cwebplusApp.Components;
@inject NavigationManager NavigationManager;
@inject IStringLocalizer<Resources> i18n;
@inject PageHistoryManager PageHistoryManager;
@inject ReportDataProvider ReportDataProvider;
@inject ILFBicycleRest ILFBicycleRest;
@inject IBicycleRestService IBicycleRestService;
@inject Toaster Toaster;
@inject AppState AppState;
@@ -94,7 +95,7 @@
base.OnInitialized();
PageHistoryManager.AddPageToHistory(NavigationManager.Uri);
try {
response = await ILFBicycleRest.SendMissingReport(ReportDataProvider.Report);
response = await IBicycleRestService.SendMissingReport(ReportDataProvider.Report);
responseOk = System.Net.HttpStatusCode.OK == response.StatusCode ? true : false;
} catch (HttpRequestException ex) {
response = new(i18n.GetString("MissingBike"), new string[] { ex.Message });

+ 2
- 3
Pages/IndexPage.razor Datei anzeigen

@@ -1,7 +1,6 @@
@page "/"
@using cwebplusApp.Shared.Services;
@using System.Threading;
@using Microsoft.Extensions.Configuration;
@inject NavigationManager NavigationManager;
@@ -11,7 +10,7 @@
@inject MasterDataService MasterDataService;
@inject Toaster Toaster;
@inject IConfiguration Configuration;
@inject ILFBicycleRest ILFBicycleRest;
@inject IBicycleRestService IBicycleRestService;
<div class="row h-100 justify-content-center">
@@ -52,7 +51,7 @@
showProgressCircle = true;
StateHasChanged();
try {
ILFBicycleRest.Initialize(Configuration);
IBicycleRestService.Initialize(Configuration);
await MasterDataService.SynchronizeMasterdata();
} catch (Exception) {
Toaster.ShowWarning(i18n.GetString("Warning.Masterdata.Title"), i18n.GetString("Warning.Masterdata.Msg"));

+ 2
- 1
Program.cs Datei anzeigen

@@ -18,10 +18,11 @@ namespace CaritasPWA {
builder.Services.AddMatBlazor();
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddSingleton<ILFBicycleRest, LFBicycleRest>();
builder.Services.AddSingleton<IBicycleRestService, BicycleRestService>();
builder.Services.AddSingleton<AppState>();
builder.Services.AddSingleton<PageHistoryManager>();
builder.Services.AddSingleton<ReportDataProvider>();
builder.Services.AddSingleton<OnlineStatusProvider>();
builder.Services.AddScoped<Toaster>();
builder.Services.AddScoped<UserDataProvider>();
builder.Services.AddScoped<MasterDataService>();

+ 2
- 1
Shared/NavMenu.razor Datei anzeigen

@@ -1,4 +1,5 @@
@using cwebplusApp.Shared.Services;
@using cwebplusApp.Components;
@inject AppState AppState;
@inject NavigationManager NavigationManager;
@@ -66,10 +67,10 @@
</MatList>
</MatDrawer>
</MatDrawerContainer>
</MatAppBarContent>
</MatAppBarContainer>
</div>
<OnlineStatusIndicator />
}

+ 104
- 0
Shared/Services/BicycleRestService.cs Datei anzeigen

@@ -0,0 +1,104 @@
using cwebplusApp.Shared.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace cwebplusApp.Shared.Services {
// REST interface responsible to submit lost or found reports and get the available master data.
public class BicycleRestService : IBicycleRestService {
private static readonly string VERSION = "v1";
private HttpClient httpClient;
[Inject]
public IConfiguration Configuration { get; set; }
public void Initialize(IConfiguration configuration) {
this.Configuration = configuration;
string hostBaseUrl = Configuration.GetValue<string>("host_base_url");
if (!String.IsNullOrEmpty(hostBaseUrl)) {
this.httpClient = new HttpClient { BaseAddress = new Uri(hostBaseUrl) };
}
}
public async Task<List<ColorItem>> GetColors() {
if (httpClient != null) {
string subResourceUrl = Configuration.GetValue<string>("subresource_url_colors");
if (!String.IsNullOrEmpty(subResourceUrl)) {
HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName));
if (httpResult.StatusCode == System.Net.HttpStatusCode.OK) {
ColorItem[] colors = JsonConvert.DeserializeObject<ColorItem[]>(await httpResult.Content.ReadAsStringAsync());
return new List<ColorItem>(colors);
}
throw new HttpRequestException("HTTP error " + httpResult.StatusCode);
}
}
throw new HttpRequestException("HTTP client not initialized!");
}
public async Task<List<BicycleType>> GetBicycleTypes() {
if (httpClient != null) {
string subResourceUrl = Configuration.GetValue<string>("subresource_url_types");
if (!String.IsNullOrEmpty(subResourceUrl)) {
HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName));
if (httpResult.StatusCode == System.Net.HttpStatusCode.OK) {
BicycleType[] bicycleTypes = JsonConvert.DeserializeObject<BicycleType[]>(await httpResult.Content.ReadAsStringAsync());
return new List<BicycleType>(bicycleTypes);
}
throw new HttpRequestException("HTTP error " + httpResult.StatusCode);
}
}
throw new HttpRequestException("HTTP client not initialized!");
}
public async Task<List<Brand>> GetBrands() {
if (httpClient != null) {
string subResourceUrl = Configuration.GetValue<string>("subresource_url_brands");
if (!String.IsNullOrEmpty(subResourceUrl)) {
HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName));
if (httpResult.StatusCode == System.Net.HttpStatusCode.OK) {
Brand[] brands = JsonConvert.DeserializeObject<Brand[]>(await httpResult.Content.ReadAsStringAsync());
return new List<Brand>(brands);
}
throw new HttpRequestException("HTTP error " + httpResult.StatusCode);
}
}
throw new HttpRequestException("HTTP client not initialized!");
}
public async Task<ReportResponse> SendFoundReport(Report report) {
string subResourceUrl = Configuration.GetValue<string>("subresource_url_foundreport");
return await SendReport(report, subResourceUrl);
}
public async Task<ReportResponse> SendMissingReport(Report report) {
string subResourceUrl = Configuration.GetValue<string>("subresource_url_missingreport");
return await SendReport(report, subResourceUrl);
}
protected async Task<ReportResponse> SendReport(Report report, string subResourceUrl) {
if (httpClient != null) {
if (!String.IsNullOrEmpty(subResourceUrl)) {
string reportJson = JsonConvert.SerializeObject(report);
HttpContent content = new StringContent(reportJson, Encoding.UTF8, "application/json");
HttpResponseMessage httpResult = await httpClient.PostAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName), content);
string msg = await httpResult.Content.ReadAsStringAsync();
ReportResponse response = JsonConvert.DeserializeObject<ReportResponse>(msg);
response.StatusCode = httpResult.StatusCode;
return response;
}
}
throw new HttpRequestException("HTTP client not initialized!");
}
}
}

+ 21
- 0
Shared/Services/IBicycleRestService.cs Datei anzeigen

@@ -0,0 +1,21 @@
using cwebplusApp.Shared.Models;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace cwebplusApp.Shared.Services {
public interface IBicycleRestService {
void Initialize(IConfiguration configuration);
Task<List<ColorItem>> GetColors();
Task<List<BicycleType>> GetBicycleTypes();
Task<List<Brand>> GetBrands();
Task<ReportResponse> SendFoundReport(Report report);
Task<ReportResponse> SendMissingReport(Report report);
}
}

+ 20
- 14
Shared/Services/MasterDataService.cs Datei anzeigen

@@ -10,13 +10,14 @@ using System.Threading.Tasks;
namespace cwebplusApp.Shared.Services {
public class MasterDataService {
private readonly ILFBicycleRest _lFBicycleRest;
private readonly IBicycleRestService _bicycleRestService;
private readonly IJSRuntime _jsRuntime;
private readonly IStringLocalizer<Resources> _i18n;
private readonly OnlineStatusProvider _onlineStatusProvider;
private const string KeyNameColors = "colors";
private const string KeyNameBcTypes = "bicycleTypes";
private const string KeyNameBrands = "brands";
private readonly IJSRuntime _jsRuntime;
private readonly IStringLocalizer<Resources> _i18n;
private bool _initializedColors;
private bool _initializedBcTypes;
private bool _initializedBrands;
@@ -40,10 +41,11 @@ namespace cwebplusApp.Shared.Services {
public event EventHandler Changed;
public MasterDataService(IJSRuntime jsRuntime, ILFBicycleRest lFBicycleRest, IStringLocalizer<Resources> i18n) {
public MasterDataService(IJSRuntime jsRuntime, IBicycleRestService bicycleRestService, IStringLocalizer<Resources> i18n, OnlineStatusProvider onlineStatusProvider) {
_jsRuntime = jsRuntime;
_lFBicycleRest = lFBicycleRest;
_bicycleRestService = bicycleRestService;
_i18n = i18n;
_onlineStatusProvider = onlineStatusProvider;
_firstActivation = true;
_brands = Defaults.GetBrandDefaults(_i18n).ToArray();
_colors = Defaults.GetColorDefaults(_i18n).ToArray();
@@ -51,17 +53,21 @@ namespace cwebplusApp.Shared.Services {
}
public async Task SynchronizeMasterdata() {
try {
await SynchronizeColors();
await SynchronizeBcTypes();
await SynchronizeBrands();
} finally {
_firstActivation = false;
if (_onlineStatusProvider.Online) {
try {
await SynchronizeColors();
await SynchronizeBcTypes();
await SynchronizeBrands();
} finally {
_firstActivation = false;
}
} else {
throw new Exception("No internet connection available!");
}
}
public async Task SynchronizeColors() {
ColorItem[] colors = (await _lFBicycleRest.GetColors()).ToArray();
ColorItem[] colors = (await _bicycleRestService.GetColors()).ToArray();
if (colors != null && colors.Length > 0) {
_colors = colors;
await SaveColorsToStorage(colors);
@@ -69,7 +75,7 @@ namespace cwebplusApp.Shared.Services {
}
public async Task SynchronizeBcTypes() {
BicycleType[] bicycleTypes = (await _lFBicycleRest.GetBicycleTypes()).ToArray();
BicycleType[] bicycleTypes = (await _bicycleRestService.GetBicycleTypes()).ToArray();
if (bicycleTypes != null && bicycleTypes.Length > 0) {
_bicycleTypes = bicycleTypes;
await SaveBcTypesToStorage(bicycleTypes);
@@ -77,7 +83,7 @@ namespace cwebplusApp.Shared.Services {
}
public async Task SynchronizeBrands() {
Brand[] brands = (await _lFBicycleRest.GetBrands()).ToArray();
Brand[] brands = (await _bicycleRestService.GetBrands()).ToArray();
if (brands != null && brands.Length > 0) {
_brands = brands;
await SaveBrandsToStorage(brands);

+ 39
- 0
Shared/Services/OnlineStatusProvider.cs Datei anzeigen

@@ -0,0 +1,39 @@
using Microsoft.JSInterop;
using System.Collections.Generic;
namespace cwebplusApp.Shared.Services {
public class OnlineStatusProvider {
public bool Online { get => online; }
public delegate void OnlineStatusChangeCallBack(bool online);
public IJSRuntime JSRuntime { get; set; }
private bool online;
private HashSet<OnlineStatusChangeCallBack> OnlineStatusChangeCallBacks;
public OnlineStatusProvider(IJSRuntime jSRuntime) {
this.JSRuntime = jSRuntime;
OnlineStatusChangeCallBacks = new();
var dotNetObjRef = DotNetObjectReference.Create(this);
JSRuntime.InvokeVoidAsync("registerOnlineStatusHandler", dotNetObjRef);
}
[JSInvokable]
public void SetOnlineStatus(bool isOnline) {
this.online = isOnline;
foreach (OnlineStatusChangeCallBack OnlineStatusCallBack in OnlineStatusChangeCallBacks) {
OnlineStatusCallBack?.Invoke(isOnline);
}
}
public void AddOnlineStatusChangeCallBack(OnlineStatusChangeCallBack listener) {
OnlineStatusChangeCallBacks.Add(listener);
}
public void RemoveOnlineStatusChangeCallBack(OnlineStatusChangeCallBack listener) {
OnlineStatusChangeCallBacks.Remove(listener);
}
}
}

+ 9
- 0
wwwroot/index.html Datei anzeigen

@@ -54,6 +54,15 @@
await component.invokeMethodAsync("OnStorageUpdated", e.key);
});
}
function registerOnlineStatusHandler(dotNetObjRef) {
function onlineStatusHandler() {
dotNetObjRef.invokeMethodAsync("SetOnlineStatus", navigator.onLine);
};
onlineStatusHandler();
window.addEventListener("online", onlineStatusHandler);
window.addEventListener("offline", onlineStatusHandler);
}
</script>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"

+ 50
- 2
wwwroot/service-worker.js Datei anzeigen

@@ -92,7 +92,21 @@ self.addEventListener('fetch', event => {
cache.put(event.request, response.clone());
return response;
});
});
}).catch(function () {
var cr;
console.log('catch network fetch failure 1');
event.waitUntil(
caches.match(event.request).then(cacheRes => {
console.log('catch network fetch failure 2');
console.log(cacheRes);
cr = cacheRes;
})
);
console.log('catch network fetch failure 3');
console.log(cr);
return cr;
//fromCache(event.request);
})
} else {
event.respondWith(
caches.match(event.request).then(cacheRes => {
@@ -100,4 +114,38 @@ self.addEventListener('fetch', event => {
})
);
}
});
});
//self.addEventListener('fetch', event => {
// if (event.request.url.endsWith(appsettings_url)) {
// networkOrCache(event.request);
// } else {
// event.respondWith(
// caches.match(event.request).then(cacheRes => {
// return cacheRes || fetch(event.request);
// })
// );
// }
//});
//function networkOrCache(request) {
// return fetch(request).then(function (response) {
// caches.open(staticCacheName).then(function (cache) {
// console.log('update cache');
// cache.put(request, response.clone());
// });
// return response.ok ? response : fromCache(request);
// //}).catch(function () {
// // return fromCache(request);
// });
//}
//function fromCache(request) {
// return caches.open(staticCacheName).then(function (cache) {
// return cache.match(request).then(function (matching) {
// return matching || Promise.reject('request-not-in-cache');
// });
// });
//}

Laden…
Abbrechen
Speichern