history 1.0.0

Pub Build Status codecov

History #

history lets you manage session history in any environment. It uses a subset of the HTML5 session history API and brings it to the VM and Browsers that don't support session History manipulation. history abstracts away the differences in environments using a minimal API. This lets you easily change the history stack, navigate to different locations in your app, confirm navigation changes using custom prompts, and persist any custom state you want between sessions.

Usage #

history provides 3 variants to use based on your environment:

  • MemoryHistory - For use in non-DOM environments such as the dart vm. All session information is stored in memory. This variant can be used in the browser if needed.
  • BrowserHistory - For use in modern browsers that support the HTML5 session history API. session information is stored using the browser's history API, allowing history manipulation from other sources to be synced with this history.
  • HashHistory - For use in legacy browsers. Relies on the hash-based paths and syncs with the browsers hashchange events. Custom states are not supported.

To use history, simply import and go!

// For use in Browser
import 'package:history/history.dart';
// For use in VM
// import 'package:history/vm.dart'; 

Confirmation confirmation = (_) => new Future.value(true);
MemoryHistory history = new MemoryHistory(getConfirmation: confirmation);

// Listen for changes
var sub = history.onChange.listen((updatedHistory) {
  var location = updatedHistory.location;
  print('Transitioned to ${location.path} with action ${updatedHistory.action}!');
  print('State associated with this location: ${location.state}');
});

// Manipulate the history
await history.push('/first');
await history.push('/second', 'with a state');
await history.replace('/third', {'with': 'a', 'state': 'object'});
await history.goBack();
await history.goForward();
await history.go(-1);

// Block transitions until they are confirmed by the user
history.block('Are you sure you want to navigate?');

// This call waits for a user confirmation before continuing
history.push('/confirmed');

// Use a more complex Prompt for more flexibilty
Prompt prompt = (Location l, Action a) {
  if (l.path == '/logout') {
    return Future.value('Logging out will cause you to lose all unsaved data!');
  } else if (a == Action.pop) {
    return Future.value('Are you sure you want to go back?');
  }
  return Future.value('Are you sure you want to navigate?');
};
history.block(prompt);

// Prints different prompts based on the transition
await history.goBack();
await history.push('/logout');

// Return to non-blocking mode
history.unblock();

// Stop listening
sub.cancel();

Examples #

Examples are available in the examples/ folder -- one for each type of history variant.

  • For Browser Examples, run pub get and pub run build_runner serve example. Then navigate to localhost:8080
  • For a VM Example, run pub get then run dart example/example_vm.dart

Inspiration #

This project is largely based on history, an npm package provided by React Training

Change Log #

All notable changes to this project will be documented here.

This project adheres to Semantic Versioning.

[v1.0.0] - 2018-10-19

Added #

  • Support for Dart 2!
  • Tooling using build_runner

Changed #

  • Updated examples to work with Dart 2

Removed #

  • Support for Dart 1.x

[v0.2.1] - 2018-7-18

Changed #

  • quiver dependency loosened

[v0.2.0] - 2018-7-15

Added #

  • Added Changelog

Changed #

  • Location how supports a dynamic state when using non-default constructor
  • BrowserHistory how uses window.confirm by default when no custom confirmation is passed

[v0.1.0] - 2018-7-14

Added #

  • Initial Release

example/example.dart

import 'dart:async';

import 'package:history/vm.dart';

Future<Null> main() async {
  Confirmation confirmation = (_) => new Future.value(true);

  MemoryHistory history = new MemoryHistory(getConfirmation: confirmation);

  // Listen for changes
  var sub = history.onChange.listen((updatedHistory) {
    var location = updatedHistory.location;
    print(
        'Transitioned to ${location.path} with action ${updatedHistory.action}!');
    print('State associated with this location: ${location.state}');
  });

  // Manipulate the history
  await history.push('/first');
  await history.push('/second', 'with a state');
  await history.replace('/third', {'with': 'a', 'state': 'object'});
  await history.goBack();
  await history.goForward();
  await history.go(-1);

  // Block transitions until they are confirmed by the user
  history.block('Are you sure you want to navigate?');

  // This call waits for a user confirmation before continuing
  history.push('/confirmed');

  // Use a more complex Prompt for more flexibilty
  Prompt prompt = (Location l, Action a) {
    if (l.path == '/logout') {
      return Future.value(
          'Logging out will cause you to lose all unsaved data!');
    } else if (a == Action.pop) {
      return Future.value('Are you sure you want to go back?');
    }
    return Future.value('Are you sure you want to navigate?');
  };
  history.block(prompt);

  // Prints different prompts based on the transition
  await history.goBack();
  await history.push('/logout');

  // Return to non-blocking mode
  history.unblock();

  // Stop listening
  sub.cancel();
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  history: ^1.0.0

2. Install it

You can install packages from the command line:

with pub:


$ pub get

Alternatively, your editor might support pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:history/history.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
0
Health:
Code health derived from static analysis. [more]
92
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
48
Learn more about scoring.

We analyzed this package on Jul 22, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.4.0
  • pana: 0.12.19

Platforms

Detected platforms: web

Primary library: package:history/history.dart with components: html.

Health suggestions

Fix lib/src/utils/dom_utils.dart. (-3.93 points)

Analysis of lib/src/utils/dom_utils.dart reported 8 hints, including:

line 51 col 10: Use contains instead of indexOf

line 51 col 44: Use contains instead of indexOf

line 52 col 9: Use contains instead of indexOf

line 53 col 9: Use contains instead of indexOf

line 54 col 9: Use contains instead of indexOf

Fix lib/src/core/location.dart. (-1.49 points)

Analysis of lib/src/core/location.dart reported 3 hints:

line 44 col 7: Don't explicitly initialize variables to null.

line 46 col 7: Don't explicitly initialize variables to null.

line 133 col 12: Don't explicitly initialize variables to null.

Fix lib/src/core/transition_manager.dart. (-1 points)

Analysis of lib/src/core/transition_manager.dart reported 2 hints:

line 29 col 11: Don't explicitly initialize variables to null.

line 37 col 3: Avoid return types on setters.

Fix additional 3 files with analysis or formatting issues. (-1.50 points)

Additional issues in the following files:

  • lib/src/browser/browser_transition_manager.dart (1 hint)
  • lib/src/browser/hash_history.dart (1 hint)
  • lib/src/browser/hash_transition_manager.dart (1 hint)

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0 <3.0.0
quiver >=0.14.0 <3.0.0 2.0.3
Transitive dependencies
matcher 0.12.5
meta 1.1.7
path 1.6.2
stack_trace 1.9.3
Dev dependencies
build_runner >=0.8.10 <2.0.0
build_test ^0.10.3+3
build_web_compilers >=0.3.6 <0.5.0
coverage ^0.12.0
dart_style ^1.0.7
dartdoc ^0.20.0
dependency_validator ^1.1.0
mockito ^3.0.0
shelf ^0.7.3
shelf_proxy ^0.1.0
test ^1.0.0
version ^1.0.3
webdev ^1.0.0

Admin