History and Deep Linking

Whenever a user performs an action in a Weavy app, the current state will be pushed to the browser history. These actions include opening/closing apps and all navigation that takes place within an app (e.g. opening a file preview, navigating to the details page for a post, etc.) The benefit of tracking the current state is that it enables back and forward navigation for actions that take place in Weavy apps.
You can take advantage of the default behaviour or write your own logic that interacts with the browser history.

You can find more in-depth information about the History API on MDN Web Docs.

The History Event

Whenever the state of a Weavy app changes, the history event is triggered. This event holds data about the current state and the appropriate action to take; either push a new entry to the browser's session history stack or replace the existing one.

ActionDescription
pushThis indicates that the state should added as a new entry to the browser's session history stack. For example when an app has been opened.
replaceWhen the state is just updated, but no new history entry should be generated.

Weavy State

The Weavy state contains an array of all the panels, their location (URL) and if they are opened or closed and when the state was changed last (if it has been changed). There is also an aggregated state, the globalState, with the combined states of all loaded Weavy instances in the session.

Name Description
state : weavyState

The state of the weavy instance

action : string

Indicates what the intention of the history state is "push" or "replace"

url : string

The URL to set in the browser history.

globalState : weavyState

The current combined global state for all weavy instances.

Panel state

Each app essentialy has a panel for displaying it's content. Also the preview and content viewer have panels underneath. The Weavy state contains the states of all the panels in the instance. Each panel state has information about whether the panel is open and which location it currently has.

If the panel state hasn't been changed since weavy was initially loaded, the changedAt property will be null. Verkar vara undefined snarare än null...

var panelState = {
  id: "panel-app-123__wy-41d751e8",
  panelId: "app-123",
  isOpen: true,
  location: "/e/apps/123,
  weavyId: "wy-41d751e8",
  weavyUri: "wvy://app-123@wy-41d751e8/e/apps/123",
  changedAt: 1614596627434
}

Cancelling a History Entry

If you do not want actions in Weavy apps to generate a history entry you can prevent the creation of these by returning event.preventDefault() within the event handler for the history event:

weavy.on("history", function (event, history) {
    event.preventDefault();
});

Deep Linking

The deeplinks plugin responds to the History event and generates links with a hash that can be used to recover the current state using an URL. You may also use this event to handle the browser state generation and deep links in your own code.

To produce URLs that you can copy and share you can use the built-in plugin that generates deep links. It's disabled by default, so you need to enable it to take advantage of the deep linking functionality.

The default setting for the deeplinks plugin is to only restore the last app (panel) the user integrated with. You can restore all apps that the user has integrated with by specifying the multiple option. The generated hash will then contain information so that the state of multiple apps can be restored when loading the URL. For instance if you have multiple apps open on a specific page.

// Url with last opened panel only
var weavy = new Weavy({ 
  plugins: { 
    deeplinks: true 
  }
})
// Url with all opened panels
var weavy = new Weavy({ 
  plugins: { 
    deeplinks: {
      multiple: true
    }
  }
})

The Weavy URI

The state location for each panel is stored as a weavy URI. The URI contains information about the location, which panel it belongs to and may also contain the id of the weavy instance if specified. When reopened, only a matching panel will open the location.

When specifying an id for your weavy instance, the id gets added to the weavy URIs and when opened again, the URI will only open in a weavy instance with a matching id. This is useful if you have multiple weavy instances. If you don't have an id specified in your weavy instance, the id is omitted in the weavy URI and it may be opened in any weavy instance.

"wvy://app-123@wvy-id/e/apps/123"

A weavy URI may also be opened directly using weavy.history.openUri("wvy://app-123@wvy-id/e/apps/123")

Custom Deep Linking

To enable users to link to a specific page in an app, preview or a whole state combined, you should enable deep links and use them together with the history event. The deeplink plugin provided in weavy may enable all of this for you if configured. It will add the deep link as a hash fragment to your current location URL and use the hash to open panels directly from the URL when loading the page.

If you have a single page app that already is using deep links or if you simply want to customize the generated URLs, you can utilize the history event to provide any URL you like.

For the history event you will get data containing the states of all the current panels and also the URL that will be used for the location in the browser. Simply modify the URL in the event data and return the data to provide a custom URL.

// Modify the history URL to include the last opened panel and return the data
weavy.on("history", function (e, history) {
    // Get only panels that has been interactively opened/closed (changedAt) and is currently open.
    var allOpenPanels = history.globalState.panels.filter(function (panelState) { 
        return panelState.changedAt && panelState.isOpen; 
    });
    var lastOpenPanel = allOpenPanels.pop();
    
    // Set the URL
    if (lastOpenPanel) {
        // Set the hash to the last opened panel
        history.url = "#" + lastOpenPanel.weavyUri;
    } else {
        // Remove the hash if no changed panel is open
        history.url = history.url.split("#")[0];
    }

    // Return the modified data to apply it
    return history;
});

Restoring states from an URL

You may pass the Weavy state data back to Weavy to restore the state. Opening a state will only restore the state and not generate any new history state. The state stored in the browser history state is automatically opened and restored on reload or when navigating back and forward in the browser history.

Opening a weavy state will replace any existing app states.

If you are using the deeplinks plugin, it will automatically restore the panels from a generated history URL.

When you are providing a custom URL in the history event, you likely want to be able to restore the state from the URL on page load. If you are involving one or several weavy URI's in your URL it's easy to get the state back from these by passing the weavy URI to the weavy.history.getStateFromUri(weavyUri) function. You can alternatively build up your own weavy state object.

When you have constructed your weavy state you can set it to the browser state by updating the state using weavy.history.setBrowserState(weavyState, "replace") during page load. Weavy will then read the state and open it automatically when loading.

// Check if there already is a browser state defined
var state = weavy.history.getBrowserState();

// Set a state from the URL if no state is present
if (!state && window.location.hash) {
    // Try to parse a weavy uri from the hash
    var weavyUris = window.location.hash.replace(/^#/, "");
    var urlState = weavy.history.getStateFromWeavyUri(weavyUris);

    if (urlState.panels.length) {
        weavy.debug("deeplinks: setting initial state");
        weavy.history.setBrowserState(urlState, "replace");
    }
}