| // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'dart:async'; |
| import 'dart:convert' show jsonDecode, jsonEncode; |
| import 'dart:html'; |
| |
| import 'usage_impl.dart'; |
| |
| /// An interface to a Google Analytics session, suitable for use in web apps. |
| /// |
| /// [analyticsUrl] is an optional replacement for the default Google Analytics |
| /// URL (`https://www.google-analytics.com/collect`). |
| /// |
| /// [batchingDelay] is used to control batching behaviour. Events will be sent |
| /// batches of 20 after the duration is over from when the first message was |
| /// sent. |
| /// |
| /// If [batchingDelay] is `Duration()` messages will be sent when control |
| /// returns to the event loop. |
| /// |
| /// Batched messages are sent in batches of up to 20 messages. |
| class AnalyticsHtml extends AnalyticsImpl { |
| AnalyticsHtml( |
| String trackingId, |
| String applicationName, |
| String applicationVersion, { |
| String? analyticsUrl, |
| Duration? batchingDelay, |
| }) : super( |
| trackingId, |
| HtmlPersistentProperties(applicationName), |
| HtmlPostHandler(), |
| applicationName: applicationName, |
| applicationVersion: applicationVersion, |
| analyticsUrl: analyticsUrl, |
| batchingDelay: batchingDelay, |
| ) { |
| var screenWidth = window.screen!.width; |
| var screenHeight = window.screen!.height; |
| |
| setSessionValue('sr', '${screenWidth}x$screenHeight'); |
| setSessionValue('sd', '${window.screen!.pixelDepth}-bits'); |
| setSessionValue('ul', window.navigator.language); |
| } |
| } |
| |
| typedef HttpRequestor = Future<HttpRequest> Function(String url, |
| {String? method, dynamic sendData}); |
| |
| class HtmlPostHandler extends PostHandler { |
| final HttpRequestor? mockRequestor; |
| |
| HtmlPostHandler({this.mockRequestor}); |
| |
| @override |
| String encodeHit(Map<String, dynamic> hit) { |
| var viewportWidth = document.documentElement!.clientWidth; |
| var viewportHeight = document.documentElement!.clientHeight; |
| return postEncode({...hit, 'vp': '${viewportWidth}x$viewportHeight'}); |
| } |
| |
| @override |
| Future<void> sendPost(String url, List<String> batch) async { |
| var data = batch.join('\n'); |
| Future<HttpRequest> Function(String, {String method, dynamic sendData}) |
| requestor = mockRequestor ?? HttpRequest.request; |
| try { |
| await requestor(url, method: 'POST', sendData: data); |
| } on Exception { |
| // Catch errors that can happen during a request, but that we can't do |
| // anything about, e.g. a missing internet connection. |
| } |
| } |
| |
| @override |
| void close() {} |
| } |
| |
| class HtmlPersistentProperties extends PersistentProperties { |
| late final Map<String, dynamic> _map; |
| |
| HtmlPersistentProperties(String name) : super(name) { |
| var str = window.localStorage[name]; |
| if (str == null || str.isEmpty) str = '{}'; |
| _map = jsonDecode(str) as Map<String, dynamic>; |
| } |
| |
| @override |
| dynamic operator [](String key) => _map[key]; |
| |
| @override |
| void operator []=(String key, dynamic value) { |
| if (value == null) { |
| _map.remove(key); |
| } else { |
| _map[key] = value; |
| } |
| |
| window.localStorage[name] = jsonEncode(_map); |
| } |
| |
| @override |
| void syncSettings() {} |
| } |