Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace history through hash with HTML5 History API (pushState) #30

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion v2/app/pivot/CxmlLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ var PivotCxmlLoader = Pivot.CxmlLoader = {
}
temp = secondLevel.getAttribute("ImgBase");
if (temp) {
imgBase = url.slice(0, url.lastIndexOf("/") + 1) + temp.replace("\\", "/");
var isAbsoluteURL = temp.indexOf('://') > 0 || temp.indexOf('//') === 0
imgBase = isAbsoluteURL ? temp : url.slice(0, url.lastIndexOf("/") + 1) + temp.replace("\\", "/");
}
secondLevel = secondLevel.childNodes;
n = secondLevel.length;
Expand Down
86 changes: 64 additions & 22 deletions v2/app/pivot/PivotView.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) Microsoft Corporation
// All rights reserved.
// All rights reserved.
// BSD License
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
Expand Down Expand Up @@ -35,10 +35,10 @@ PivotNumber_format, makeElement, addText, hasOwnProperty, PivotDatePicker, Pivot
* yourself, you should call this method rather than the Pivot.PivotViewer constructor.
* @method init
* @param div {HTMLElement} The container element
* @param useHash {bool} Whether to adjust the URL fragment to represent current filter state
* @param useHistory {bool} Whether to update the URL to represent current filter state
* @return {Pivot.PivotViewer}
*/
var Pivot_init = Pivot.init = function (div, useHash) {
var Pivot_init = Pivot.init = function (div, useHistory) {
// clear out the workspace we've been provided
while(div.firstChild) {
div.removeChild(div.firstChild);
Expand All @@ -50,6 +50,9 @@ var Pivot_init = Pivot.init = function (div, useHash) {
return;
}

// initial state
var hasStateBeenAppliedFromURL = false

// start by setting up some basics for our view
var inputElmt = makeElement("input", "pivot_input", div);
inputElmt.setAttribute("type", "checkbox"); // make it a checkbox so it won't bring up onscreen keyboard
Expand Down Expand Up @@ -950,22 +953,25 @@ var Pivot_init = Pivot.init = function (div, useHash) {
};
}
}
const isGridViewActive = gridButton.className.indexOf("pivot_activesort") !== -1
return JSON.stringify({
filters: filtersCopy,
search: activeSearch,
sortBy: sortBox.value,
view: (gridButton.className.indexOf("pivot_activesort") !== -1) ? "grid" : "graph"
view: isGridViewActive ? "grid" : "graph"
});
}

// apply a serialized set of filters. currently assumes that the viewer state is fresh
// (no filters applied yet, in grid view mode)
function deserializeFilters(filterData) {
function deserializeAndApplyFilters(filterData) {
filterData = JSON.parse(filterData);
var filters = filterData.filters;
var search = filterData.search;
var sortBy = filterData.sortBy;
var facetName;

onClearAll(false)
for (facetName in filters) {
if (hasOwnProperty.call(filters, facetName)) {
var filter = filters[facetName];
Expand Down Expand Up @@ -1003,9 +1009,41 @@ var Pivot_init = Pivot.init = function (div, useHash) {
if (filterData.view === "graph") {
graphButton.onclick();
}
if (filterData.view === "grid") {
gridButton.onclick();
}
refreshFilterPane();
}

function getQueryVariable(name) {
var query = location.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
if (decodeURIComponent(pair[0]) == name) {
return decodeURIComponent(pair[1]);
}
}
return null
}

function getPathWithState() {
return '?state=' + encodeURIComponent(serializeFilters())
}

function applyStateFromURL() {
const state = getQueryVariable('state')
if (!state) {
return
}

try {
deserializeAndApplyFilters(state);
} catch (error) {
Seadragon2.Debug.warn("Bad URL state");
}
}

// once we know about facets for the collection, we can build
// the rest of the UI. note that this can be reset at any time,
// if the current facets change. if the facets change, we expect
Expand Down Expand Up @@ -1117,16 +1155,11 @@ var Pivot_init = Pivot.init = function (div, useHash) {
facetOptions.style.overflow = "hidden";
}

// apply filters from the hash immediately
if (useHash) {
var hash = location.hash;
if (hash && hash.length > 2) {
try {
deserializeFilters(decodeURIComponent(hash.substr(1)));
} catch (e) {
Seadragon2.Debug.warn("bad URL hash");
}
}
// apply filters from URL
if (useHistory) {
hasStateBeenAppliedFromURL = true
history.replaceState(null, '', getPathWithState());
applyStateFromURL();
}
});

Expand All @@ -1138,11 +1171,20 @@ var Pivot_init = Pivot.init = function (div, useHash) {
}
});

// put the current filter state in the hash after any rearrange operation
if (useHash) {
// put the current filter state in the query after any rearrange operation
if (useHistory) {
viewer.addListener("finishedRearrange", function () {
location.hash = "#" + encodeURIComponent(serializeFilters());
if (hasStateBeenAppliedFromURL) {
hasStateBeenAppliedFromURL = false
return
}
history.pushState(null, '', getPathWithState());
});

window.addEventListener('popstate', function (event) {
hasStateBeenAppliedFromURL = true
applyStateFromURL()
})
}

return viewer;
Expand All @@ -1163,12 +1205,12 @@ addEventListener("load", function () {
for (i = 0; i < n; i++) {
div = viewers[i];
url = div.getAttribute("data-collection");
var useHash = div.getAttribute("data-use-hash");
useHash = useHash && useHash.toLowerCase() !== "false";
viewer = Pivot_init(div, useHash);
var useHistory = div.getAttribute("data-use-history");
useHistory = useHistory && useHistory.toLowerCase() !== "false";
viewer = Pivot_init(div, useHistory);
div.pivotViewer = viewer;
if (url) {
PivotCxmlLoader.load(viewer, url);
}
}
}, false);
}, false);
8 changes: 4 additions & 4 deletions v2/app/pivot/quickstart.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ <h2>Creating the Viewer</h2>

<code>&lt;div class="pivot_ajax_viewer"
data-collection="http://contoso.com/widgets.cxml"
data-use-hash="true"
data-use-history="true"
style="width:1000px;height:600px;border:2px solid gray"&gt;
Oops, something went wrong! Make sure Javascript is enabled.
&lt;/div&gt;</code>
Expand All @@ -69,8 +69,8 @@ <h2>Creating the Viewer</h2>
window's load event. The <code>data-collection</code> attribute can be either a relative or absolute URL, just be sure that your
server is returning an appropriate <code>Access-Control-Allow-Origin</code> header if you're using a collection hosted on another
domain. Feel free to style the div however you like, of course. If you resize it, the viewer should adjust itself
automatically. The <code>data-use-hash</code> attribute specifies that the viewer should change the URL hash to match its
current state, and should try to read the URL hash when the page is loaded. If you only have one PivotViewer on the page and it
automatically. The <code>data-use-history</code> attribute specifies that the viewer should change the URL to match its
current state, and should try to read the state from the URL when the page is loaded. If you only have one PivotViewer on the page and it
won't conflict with any other page functionality, it probably makes sense to turn this feature on.</p>

<p>If you use this method, you can skip the rest of this document because you already have a fully working viewer.</p>
Expand Down Expand Up @@ -541,4 +541,4 @@ <h2>Can I customize the details pane?</h2>
to modify the collapsed state of the details pane.</p>
</div>
</body>
</html>
</html>