mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-09-28 21:41:40 +00:00
Formalize settle concept
This commit is contained in:
parent
eb9ea0cbca
commit
ab1668d68b
1
TODO.md
1
TODO.md
@ -17,6 +17,7 @@
|
||||
* polling cancellation API 205 code
|
||||
* meta config tag
|
||||
* simple logging API
|
||||
* hx-toggle-class
|
||||
|
||||
* Testing
|
||||
* polling
|
||||
|
247
dist/htmx.js
vendored
247
dist/htmx.js
vendored
@ -117,6 +117,10 @@ var HTMx = HTMx || (function () {
|
||||
return getDocument().body.contains(elt);
|
||||
}
|
||||
|
||||
function concat(arr1, arr2) {
|
||||
return arr1.concat(arr2);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Node processing
|
||||
//====================================================================
|
||||
@ -152,19 +156,21 @@ var HTMx = HTMx || (function () {
|
||||
}
|
||||
|
||||
function handleOutOfBandSwaps(fragment) {
|
||||
var settleTasks = [];
|
||||
forEach(fragment.children, function(child){
|
||||
if (getAttributeValue(child, "hx-swap-oob") === "true") {
|
||||
var target = getDocument().getElementById(child.id);
|
||||
if (target) {
|
||||
var fragment = new DocumentFragment()
|
||||
fragment.append(child);
|
||||
swapOuterHTML(target, fragment);
|
||||
settleTasks = settleTasks.concat(swapOuterHTML(target, fragment));
|
||||
} else {
|
||||
child.parentNode.removeChild(child);
|
||||
triggerEvent(getDocument().body, "oobErrorNoTarget.hx", {id:child.id, content:child})
|
||||
}
|
||||
}
|
||||
})
|
||||
return settleTasks;
|
||||
}
|
||||
|
||||
function handleAttributes(parentNode, fragment) {
|
||||
@ -179,11 +185,7 @@ var HTMx = HTMx || (function () {
|
||||
});
|
||||
}
|
||||
});
|
||||
setTimeout(function () {
|
||||
forEach(attributeSwaps, function (swap) {
|
||||
swap.call();
|
||||
});
|
||||
}, 100);
|
||||
return attributeSwaps;
|
||||
}
|
||||
|
||||
function insertNodesBefore(parentNode, insertBefore, fragment) {
|
||||
@ -200,32 +202,37 @@ var HTMx = HTMx || (function () {
|
||||
|
||||
function swapOuterHTML(target, fragment) {
|
||||
if (target.tagName === "BODY") {
|
||||
swapInnerHTML(target, fragment);
|
||||
return swapInnerHTML(target, fragment);
|
||||
} else {
|
||||
insertNodesBefore(parentElt(target), target, fragment);
|
||||
var settleTasks = insertNodesBefore(parentElt(target), target, fragment);
|
||||
parentElt(target).removeChild(target);
|
||||
return settleTasks;
|
||||
}
|
||||
}
|
||||
|
||||
function swapPrepend(target, fragment) {
|
||||
insertNodesBefore(target, target.firstChild, fragment);
|
||||
return insertNodesBefore(target, target.firstChild, fragment);
|
||||
}
|
||||
|
||||
function swapPrependBefore(target, fragment) {
|
||||
insertNodesBefore(parentElt(target), target, fragment);
|
||||
return insertNodesBefore(parentElt(target), target, fragment);
|
||||
}
|
||||
|
||||
function swapAppend(target, fragment) {
|
||||
insertNodesBefore(target, null, fragment);
|
||||
return insertNodesBefore(target, null, fragment);
|
||||
}
|
||||
|
||||
function swapAppendAfter(target, fragment) {
|
||||
insertNodesBefore(parentElt(target), target.nextSibling, fragment);
|
||||
return insertNodesBefore(parentElt(target), target.nextSibling, fragment);
|
||||
}
|
||||
|
||||
function swapInnerHTML(target, fragment) {
|
||||
target.innerHTML = "";
|
||||
insertNodesBefore(target, null, fragment);
|
||||
var firstChild = target.firstChild;
|
||||
return insertNodesBefore(target, firstChild, fragment);
|
||||
while (firstChild.nextSibling) {
|
||||
target.removeChild(firstChild.nextSibling);
|
||||
}
|
||||
target.removeChild(firstChild);
|
||||
}
|
||||
|
||||
function maybeSelectFromResponse(elt, fragment) {
|
||||
@ -240,30 +247,20 @@ var HTMx = HTMx || (function () {
|
||||
return fragment;
|
||||
}
|
||||
|
||||
function swapResponse(target, elt, responseText, callBack) {
|
||||
|
||||
function swapResponse(target, elt, responseText) {
|
||||
var fragment = makeFragment(responseText);
|
||||
handleOutOfBandSwaps(fragment);
|
||||
var settleTasks = handleOutOfBandSwaps(fragment);
|
||||
|
||||
fragment = maybeSelectFromResponse(elt, fragment);
|
||||
|
||||
var swapStyle = getClosestAttributeValue(elt, "hx-swap");
|
||||
if (swapStyle === "outerHTML") {
|
||||
swapOuterHTML(target, fragment);
|
||||
} else if (swapStyle === "prepend") {
|
||||
swapPrepend(target, fragment);
|
||||
} else if (swapStyle === "prependBefore") {
|
||||
swapPrependBefore(target, fragment);
|
||||
} else if (swapStyle === "append") {
|
||||
swapAppend(target, fragment);
|
||||
} else if (swapStyle === "appendAfter") {
|
||||
swapAppendAfter(target, fragment);
|
||||
} else {
|
||||
swapInnerHTML(target, fragment);
|
||||
}
|
||||
|
||||
if(callBack) {
|
||||
callBack.call();
|
||||
switch(swapStyle) {
|
||||
case "outerHTML": return concat(settleTasks, swapOuterHTML(target, fragment));
|
||||
case "prepend": return concat(settleTasks, swapPrepend(target, fragment));
|
||||
case "prependBefore": return concat(settleTasks, swapPrependBefore(target, fragment));
|
||||
case "append": return concat(settleTasks, swapAppend(target, fragment));
|
||||
case "appendAfter": return concat(settleTasks, swapAppendAfter(target, fragment));
|
||||
default: return concat(settleTasks, swapInnerHTML(target, fragment));
|
||||
}
|
||||
}
|
||||
|
||||
@ -583,62 +580,78 @@ var HTMx = HTMx || (function () {
|
||||
//====================================================================
|
||||
// History Support
|
||||
//====================================================================
|
||||
|
||||
function makeHistoryId() {
|
||||
return Math.random().toString(36).substr(3, 9);
|
||||
}
|
||||
|
||||
function getHistoryElement() {
|
||||
var historyElt = getDocument().getElementsByClassName('hx-history-element');
|
||||
if (historyElt.length > 0) {
|
||||
return historyElt[0];
|
||||
} else {
|
||||
return getDocument().body;
|
||||
var historyElt = getDocument().querySelector('.hx-history-element');
|
||||
return historyElt || getDocument().body;
|
||||
}
|
||||
|
||||
function purgeOldestPaths(paths, historyTimestamps) {
|
||||
var paths = paths.sort(function (path1, path2) {
|
||||
return historyTimestamps[path2] - historyTimestamps[path1]
|
||||
});
|
||||
var slot = 0;
|
||||
forEach(paths, function (path) {
|
||||
slot++;
|
||||
if (slot > 20) {
|
||||
delete historyTimestamps[path];
|
||||
localStorage.removeItem(path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function bumpHistoryAccessDate(pathAndSearch) {
|
||||
var historyTimestamps = JSON.parse(localStorage.getItem("hx-history-timestamps")) || {};
|
||||
historyTimestamps[pathAndSearch] = Date.now;
|
||||
var paths = Object.keys(historyTimestamps);
|
||||
if (paths.length > 20) {
|
||||
purgeOldestPaths(paths, historyTimestamps);
|
||||
}
|
||||
localStorage.setItem("hx-history-timestamps", JSON.stringify(historyTimestamps));
|
||||
}
|
||||
|
||||
function saveLocalHistoryData(historyData) {
|
||||
localStorage.setItem('hx-history', JSON.stringify(historyData));
|
||||
}
|
||||
|
||||
function getLocalHistoryData() {
|
||||
var historyEntry = localStorage.getItem('hx-history');
|
||||
var historyData;
|
||||
if (historyEntry) {
|
||||
historyData = JSON.parse(historyEntry);
|
||||
} else {
|
||||
var initialId = makeHistoryId();
|
||||
historyData = {"current": initialId, "slots": [initialId]};
|
||||
saveLocalHistoryData(historyData);
|
||||
}
|
||||
return historyData;
|
||||
}
|
||||
|
||||
function newHistoryData() {
|
||||
var historyData = getLocalHistoryData();
|
||||
var newId = makeHistoryId();
|
||||
var slots = historyData.slots;
|
||||
if (slots.length > 20) {
|
||||
var toEvict = slots.shift();
|
||||
localStorage.removeItem('hx-history-' + toEvict);
|
||||
}
|
||||
slots.push(newId);
|
||||
historyData.current = newId;
|
||||
saveLocalHistoryData(historyData);
|
||||
}
|
||||
|
||||
function updateCurrentHistoryContent() {
|
||||
function saveHistory() {
|
||||
var elt = getHistoryElement();
|
||||
var historyData = getLocalHistoryData();
|
||||
history.replaceState({"hx-history-key": historyData.current}, getDocument().title, window.location.href);
|
||||
localStorage.setItem('hx-history-' + historyData.current, elt.innerHTML);
|
||||
var pathAndSearch = location.pathname+location.search;
|
||||
triggerEvent(getDocument().body, "historyUpdate.hx", {path:pathAndSearch, historyElement:elt});
|
||||
history.replaceState({}, getDocument().title, window.location.href);
|
||||
localStorage.setItem('hx-history-content-' + pathAndSearch, elt.innerHTML);
|
||||
bumpHistoryAccessDate(pathAndSearch);
|
||||
}
|
||||
|
||||
function restoreHistory(data) {
|
||||
var historyKey = data['hx-history-key'];
|
||||
var content = localStorage.getItem('hx-history-' + historyKey);
|
||||
var elt = getHistoryElement();
|
||||
swapInnerHTML(elt, makeFragment(content));
|
||||
function pushUrlIntoHistory(url) {
|
||||
history.pushState({}, "", url );
|
||||
}
|
||||
|
||||
function settleImmediately(settleTasks) {
|
||||
forEach(settleTasks, function (task) {
|
||||
task.call();
|
||||
});
|
||||
}
|
||||
|
||||
function loadHistoryFromServer(pathAndSearch) {
|
||||
triggerEvent(getDocument().body, "historyCacheMiss.hx", {path: pathAndSearch});
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('GET', pathAndSearch, true);
|
||||
request.onload = function () {
|
||||
triggerEvent(getDocument().body, "historyCacheMissLoad.hx", {path: pathAndSearch});
|
||||
if (this.status >= 200 && this.status < 400) {
|
||||
var fragment = makeFragment(this.response);
|
||||
fragment = fragment.querySelector('.hx-history-element') || fragment;
|
||||
settleImmediately(swapInnerHTML(getHistoryElement(), fragment));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function restoreHistory() {
|
||||
var pathAndSearch = location.pathname+location.search;
|
||||
triggerEvent(getDocument().body, "historyUpdate.hx", {path:pathAndSearch});
|
||||
var content = localStorage.getItem('hx-history-content-' + pathAndSearch);
|
||||
if (content) {
|
||||
bumpHistoryAccessDate(pathAndSearch);
|
||||
settleImmediately(swapInnerHTML(getHistoryElement(), makeFragment(content)));
|
||||
} else {
|
||||
loadHistoryFromServer(pathAndSearch);
|
||||
}
|
||||
}
|
||||
|
||||
function shouldPush(elt) {
|
||||
@ -646,21 +659,6 @@ var HTMx = HTMx || (function () {
|
||||
(elt.tagName === "A" && getInternalData(elt).boosted);
|
||||
}
|
||||
|
||||
function snapshotForCurrentHistoryEntry(elt) {
|
||||
if (shouldPush(elt)) {
|
||||
// TODO event to allow de-initialization of HTML elements in target
|
||||
updateCurrentHistoryContent();
|
||||
}
|
||||
}
|
||||
|
||||
function initNewHistoryEntry(elt, url) {
|
||||
if (shouldPush(elt)) {
|
||||
newHistoryData();
|
||||
history.pushState({}, "", url);
|
||||
updateCurrentHistoryContent();
|
||||
}
|
||||
}
|
||||
|
||||
function addRequestIndicatorClasses(elt) {
|
||||
mutateRequestIndicatorClasses(elt, "add");
|
||||
}
|
||||
@ -804,11 +802,14 @@ var HTMx = HTMx || (function () {
|
||||
if(!triggerEvent(elt, 'values.hx', {values: inputValues, target:target})) return endRequestLock();
|
||||
|
||||
// request type
|
||||
var requestURL;
|
||||
if (verb === 'get') {
|
||||
var noValues = Object.keys(inputValues).length === 0;
|
||||
xhr.open('GET', path + (noValues ? "" : "?" + urlEncode(inputValues)), true);
|
||||
requestURL = path + (noValues ? "" : "?" + urlEncode(inputValues));
|
||||
xhr.open('GET', requestURL, true);
|
||||
} else {
|
||||
xhr.open('POST', path, true);
|
||||
requestURL = path;
|
||||
xhr.open('POST', requestURL, true);
|
||||
setHeader(xhr,'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8', true);
|
||||
if (verb !== 'post') {
|
||||
setHeader(xhr, 'X-HTTP-Method-Override', verb.toUpperCase(), true);
|
||||
@ -841,30 +842,56 @@ var HTMx = HTMx || (function () {
|
||||
xhr.onload = function () {
|
||||
try {
|
||||
if (!triggerEvent(elt, 'beforeOnLoad.hx', {xhr: xhr, target: target})) return;
|
||||
snapshotForCurrentHistoryEntry(elt, path);
|
||||
var trigger = this.getResponseHeader("X-HX-Trigger");
|
||||
handleTrigger(elt, trigger);
|
||||
initNewHistoryEntry(elt, path);
|
||||
|
||||
handleTrigger(elt, this.getResponseHeader("X-HX-Trigger"));
|
||||
var pushedUrl = this.getResponseHeader("X-HX-Push")
|
||||
|
||||
var shouldSaveHistory = shouldPush(elt) || pushedUrl;
|
||||
|
||||
if (this.status >= 200 && this.status < 400) {
|
||||
// don't process 'No Content' response
|
||||
if (this.status !== 204) {
|
||||
// Success!
|
||||
var resp = this.response;
|
||||
if (!triggerEvent(elt, 'beforeSwap.hx', {xhr: xhr, target: target})) return;
|
||||
|
||||
// Save current page
|
||||
if (shouldSaveHistory) {
|
||||
saveHistory();
|
||||
}
|
||||
|
||||
target.classList.add("hx-swapping");
|
||||
var doSwap = function () {
|
||||
try {
|
||||
swapResponse(target, elt, resp, function () {
|
||||
target.classList.remove("hx-swapping");
|
||||
updateCurrentHistoryContent();
|
||||
triggerEvent(elt, 'afterSwap.hx', {xhr: xhr, target: target});
|
||||
});
|
||||
var settleTasks = swapResponse(target, elt, resp);
|
||||
target.classList.remove("hx-swapping");
|
||||
target.classList.add("hx-settling");
|
||||
triggerEvent(elt, 'afterSwap.hx', {xhr: xhr, target: target});
|
||||
|
||||
var doSettle = function(){
|
||||
forEach(settleTasks, function (task) {
|
||||
task.call();
|
||||
});
|
||||
target.classList.remove("hx-settling");
|
||||
// push URL and save new page
|
||||
pushUrlIntoHistory(pushedUrl || requestURL );
|
||||
saveHistory();
|
||||
triggerEvent(elt, 'afterSettle.hx', {xhr: xhr, target: target});
|
||||
}
|
||||
|
||||
var settleDelayStr = getAttributeValue(elt, "hx-settle-delay") || "100ms";
|
||||
if (settleDelayStr) {
|
||||
setTimeout(doSettle, parseInterval(settleDelayStr))
|
||||
} else {
|
||||
doSettle();
|
||||
}
|
||||
} catch (e) {
|
||||
triggerEvent(elt, 'swapError.hx', {xhr: xhr, response: xhr.response, status: xhr.status, target: target});
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
var swapDelayStr = getAttributeValue(elt, "hx-swap-delay");
|
||||
|
||||
var swapDelayStr = getAttributeValue(elt, "hx-swap-delay") || "100ms";
|
||||
if (swapDelayStr) {
|
||||
setTimeout(doSwap, parseInterval(swapDelayStr))
|
||||
} else {
|
||||
@ -908,7 +935,7 @@ var HTMx = HTMx || (function () {
|
||||
ready(function () {
|
||||
processNode(getDocument().body);
|
||||
window.onpopstate = function (event) {
|
||||
restoreHistory(event.state);
|
||||
restoreHistory();
|
||||
};
|
||||
})
|
||||
|
||||
|
2
dist/htmx.min.js
vendored
2
dist/htmx.min.js
vendored
File diff suppressed because one or more lines are too long
BIN
dist/htmx.min.js.gz
vendored
BIN
dist/htmx.min.js.gz
vendored
Binary file not shown.
159
src/htmx.js
159
src/htmx.js
@ -117,6 +117,10 @@ var HTMx = HTMx || (function () {
|
||||
return getDocument().body.contains(elt);
|
||||
}
|
||||
|
||||
function concat(arr1, arr2) {
|
||||
return arr1.concat(arr2);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Node processing
|
||||
//====================================================================
|
||||
@ -152,19 +156,21 @@ var HTMx = HTMx || (function () {
|
||||
}
|
||||
|
||||
function handleOutOfBandSwaps(fragment) {
|
||||
var settleTasks = [];
|
||||
forEach(fragment.children, function(child){
|
||||
if (getAttributeValue(child, "hx-swap-oob") === "true") {
|
||||
var target = getDocument().getElementById(child.id);
|
||||
if (target) {
|
||||
var fragment = new DocumentFragment()
|
||||
fragment.append(child);
|
||||
swapOuterHTML(target, fragment);
|
||||
settleTasks = settleTasks.concat(swapOuterHTML(target, fragment));
|
||||
} else {
|
||||
child.parentNode.removeChild(child);
|
||||
triggerEvent(getDocument().body, "oobErrorNoTarget.hx", {id:child.id, content:child})
|
||||
}
|
||||
}
|
||||
})
|
||||
return settleTasks;
|
||||
}
|
||||
|
||||
function handleAttributes(parentNode, fragment) {
|
||||
@ -179,15 +185,11 @@ var HTMx = HTMx || (function () {
|
||||
});
|
||||
}
|
||||
});
|
||||
setTimeout(function () {
|
||||
forEach(attributeSwaps, function (swap) {
|
||||
swap.call();
|
||||
});
|
||||
}, 100);
|
||||
return attributeSwaps;
|
||||
}
|
||||
|
||||
function insertNodesBefore(parentNode, insertBefore, fragment) {
|
||||
handleAttributes(parentNode, fragment);
|
||||
var settleTasks = handleAttributes(parentNode, fragment);
|
||||
while(fragment.childNodes.length > 0){
|
||||
var child = fragment.firstChild;
|
||||
parentNode.insertBefore(child, insertBefore);
|
||||
@ -196,36 +198,45 @@ var HTMx = HTMx || (function () {
|
||||
processNode(child);
|
||||
}
|
||||
}
|
||||
return settleTasks;
|
||||
}
|
||||
|
||||
function swapOuterHTML(target, fragment) {
|
||||
if (target.tagName === "BODY") {
|
||||
swapInnerHTML(target, fragment);
|
||||
return swapInnerHTML(target, fragment);
|
||||
} else {
|
||||
insertNodesBefore(parentElt(target), target, fragment);
|
||||
var settleTasks = insertNodesBefore(parentElt(target), target, fragment);
|
||||
parentElt(target).removeChild(target);
|
||||
return settleTasks;
|
||||
}
|
||||
}
|
||||
|
||||
function swapPrepend(target, fragment) {
|
||||
insertNodesBefore(target, target.firstChild, fragment);
|
||||
return insertNodesBefore(target, target.firstChild, fragment);
|
||||
}
|
||||
|
||||
function swapPrependBefore(target, fragment) {
|
||||
insertNodesBefore(parentElt(target), target, fragment);
|
||||
return insertNodesBefore(parentElt(target), target, fragment);
|
||||
}
|
||||
|
||||
function swapAppend(target, fragment) {
|
||||
insertNodesBefore(target, null, fragment);
|
||||
return insertNodesBefore(target, null, fragment);
|
||||
}
|
||||
|
||||
function swapAppendAfter(target, fragment) {
|
||||
insertNodesBefore(parentElt(target), target.nextSibling, fragment);
|
||||
return insertNodesBefore(parentElt(target), target.nextSibling, fragment);
|
||||
}
|
||||
|
||||
function swapInnerHTML(target, fragment) {
|
||||
target.innerHTML = "";
|
||||
insertNodesBefore(target, null, fragment);
|
||||
var firstChild = target.firstChild;
|
||||
var settleTasks = insertNodesBefore(target, firstChild, fragment);
|
||||
if (firstChild) {
|
||||
while (firstChild.nextSibling) {
|
||||
target.removeChild(firstChild.nextSibling);
|
||||
}
|
||||
target.removeChild(firstChild);
|
||||
}
|
||||
return settleTasks;
|
||||
}
|
||||
|
||||
function maybeSelectFromResponse(elt, fragment) {
|
||||
@ -240,30 +251,20 @@ var HTMx = HTMx || (function () {
|
||||
return fragment;
|
||||
}
|
||||
|
||||
function swapResponse(target, elt, responseText, callBack) {
|
||||
|
||||
function swapResponse(target, elt, responseText) {
|
||||
var fragment = makeFragment(responseText);
|
||||
handleOutOfBandSwaps(fragment);
|
||||
var settleTasks = handleOutOfBandSwaps(fragment);
|
||||
|
||||
fragment = maybeSelectFromResponse(elt, fragment);
|
||||
|
||||
var swapStyle = getClosestAttributeValue(elt, "hx-swap");
|
||||
if (swapStyle === "outerHTML") {
|
||||
swapOuterHTML(target, fragment);
|
||||
} else if (swapStyle === "prepend") {
|
||||
swapPrepend(target, fragment);
|
||||
} else if (swapStyle === "prependBefore") {
|
||||
swapPrependBefore(target, fragment);
|
||||
} else if (swapStyle === "append") {
|
||||
swapAppend(target, fragment);
|
||||
} else if (swapStyle === "appendAfter") {
|
||||
swapAppendAfter(target, fragment);
|
||||
} else {
|
||||
swapInnerHTML(target, fragment);
|
||||
}
|
||||
|
||||
if(callBack) {
|
||||
callBack.call();
|
||||
switch(swapStyle) {
|
||||
case "outerHTML": return concat(settleTasks, swapOuterHTML(target, fragment));
|
||||
case "prepend": return concat(settleTasks, swapPrepend(target, fragment));
|
||||
case "prependBefore": return concat(settleTasks, swapPrependBefore(target, fragment));
|
||||
case "append": return concat(settleTasks, swapAppend(target, fragment));
|
||||
case "appendAfter": return concat(settleTasks, swapAppendAfter(target, fragment));
|
||||
default: return concat(settleTasks, swapInnerHTML(target, fragment));
|
||||
}
|
||||
}
|
||||
|
||||
@ -604,7 +605,7 @@ var HTMx = HTMx || (function () {
|
||||
|
||||
function bumpHistoryAccessDate(pathAndSearch) {
|
||||
var historyTimestamps = JSON.parse(localStorage.getItem("hx-history-timestamps")) || {};
|
||||
historyTimestamps[pathAndSearch] = Date.now;
|
||||
historyTimestamps[pathAndSearch] = Date.now();
|
||||
var paths = Object.keys(historyTimestamps);
|
||||
if (paths.length > 20) {
|
||||
purgeOldestPaths(paths, historyTimestamps);
|
||||
@ -612,20 +613,23 @@ var HTMx = HTMx || (function () {
|
||||
localStorage.setItem("hx-history-timestamps", JSON.stringify(historyTimestamps));
|
||||
}
|
||||
|
||||
function saveForHistory() {
|
||||
function saveHistory() {
|
||||
var elt = getHistoryElement();
|
||||
var pathAndSearch = location.pathname+location.search;
|
||||
triggerEvent(getDocument().body, "historyUpdate.hx", {path:pathAndSearch});
|
||||
triggerEvent(getDocument().body, "historyUpdate.hx", {path:pathAndSearch, historyElement:elt});
|
||||
history.replaceState({}, getDocument().title, window.location.href);
|
||||
localStorage.setItem('hx-history-content-' + pathAndSearch, elt.innerHTML);
|
||||
localStorage.setItem('hx-history:' + pathAndSearch, elt.innerHTML);
|
||||
bumpHistoryAccessDate(pathAndSearch);
|
||||
}
|
||||
|
||||
function initNewHistoryEntry(elt, url) {
|
||||
if (shouldPush(elt)) {
|
||||
history.pushState({}, "", url );
|
||||
saveForHistory();
|
||||
}
|
||||
function pushUrlIntoHistory(url) {
|
||||
history.pushState({}, "", url );
|
||||
}
|
||||
|
||||
function settleImmediately(settleTasks) {
|
||||
forEach(settleTasks, function (task) {
|
||||
task.call();
|
||||
});
|
||||
}
|
||||
|
||||
function loadHistoryFromServer(pathAndSearch) {
|
||||
@ -637,18 +641,18 @@ var HTMx = HTMx || (function () {
|
||||
if (this.status >= 200 && this.status < 400) {
|
||||
var fragment = makeFragment(this.response);
|
||||
fragment = fragment.querySelector('.hx-history-element') || fragment;
|
||||
swapInnerHTML(getHistoryElement(), fragment);
|
||||
settleImmediately(swapInnerHTML(getHistoryElement(), fragment));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function restoreHistory() {
|
||||
var pathAndSearch = location.pathname+location.search;
|
||||
triggerEvent(getDocument().body, "historyUpdate.hx", {path:pathAndSearch});
|
||||
var content = localStorage.getItem('hx-history-content-' + pathAndSearch);
|
||||
triggerEvent(getDocument().body, "historyRestore.hx", {path:pathAndSearch});
|
||||
var content = localStorage.getItem('hx-history:' + pathAndSearch);
|
||||
if (content) {
|
||||
bumpHistoryAccessDate(pathAndSearch);
|
||||
swapInnerHTML(getHistoryElement(), makeFragment(content));
|
||||
settleImmediately(swapInnerHTML(getHistoryElement(), makeFragment(content)));
|
||||
} else {
|
||||
loadHistoryFromServer(pathAndSearch);
|
||||
}
|
||||
@ -659,14 +663,6 @@ var HTMx = HTMx || (function () {
|
||||
(elt.tagName === "A" && getInternalData(elt).boosted);
|
||||
}
|
||||
|
||||
function snapshotForCurrentHistoryEntry(elt) {
|
||||
if (shouldPush(elt)) {
|
||||
// TODO event to allow de-initialization of HTML elements in target
|
||||
saveForHistory();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function addRequestIndicatorClasses(elt) {
|
||||
mutateRequestIndicatorClasses(elt, "add");
|
||||
}
|
||||
@ -810,11 +806,14 @@ var HTMx = HTMx || (function () {
|
||||
if(!triggerEvent(elt, 'values.hx', {values: inputValues, target:target})) return endRequestLock();
|
||||
|
||||
// request type
|
||||
var requestURL;
|
||||
if (verb === 'get') {
|
||||
var noValues = Object.keys(inputValues).length === 0;
|
||||
xhr.open('GET', path + (noValues ? "" : "?" + urlEncode(inputValues)), true);
|
||||
requestURL = path + (noValues ? "" : "?" + urlEncode(inputValues));
|
||||
xhr.open('GET', requestURL, true);
|
||||
} else {
|
||||
xhr.open('POST', path, true);
|
||||
requestURL = path;
|
||||
xhr.open('POST', requestURL, true);
|
||||
setHeader(xhr,'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8', true);
|
||||
if (verb !== 'post') {
|
||||
setHeader(xhr, 'X-HTTP-Method-Override', verb.toUpperCase(), true);
|
||||
@ -847,29 +846,57 @@ var HTMx = HTMx || (function () {
|
||||
xhr.onload = function () {
|
||||
try {
|
||||
if (!triggerEvent(elt, 'beforeOnLoad.hx', {xhr: xhr, target: target})) return;
|
||||
snapshotForCurrentHistoryEntry(elt, path);
|
||||
var trigger = this.getResponseHeader("X-HX-Trigger");
|
||||
handleTrigger(elt, trigger);
|
||||
initNewHistoryEntry(elt, path);
|
||||
|
||||
handleTrigger(elt, this.getResponseHeader("X-HX-Trigger"));
|
||||
var pushedUrl = this.getResponseHeader("X-HX-Push")
|
||||
|
||||
var shouldSaveHistory = shouldPush(elt) || pushedUrl;
|
||||
|
||||
if (this.status >= 200 && this.status < 400) {
|
||||
// don't process 'No Content' response
|
||||
if (this.status !== 204) {
|
||||
// Success!
|
||||
var resp = this.response;
|
||||
if (!triggerEvent(elt, 'beforeSwap.hx', {xhr: xhr, target: target})) return;
|
||||
|
||||
// Save current page
|
||||
if (shouldSaveHistory) {
|
||||
saveHistory();
|
||||
}
|
||||
|
||||
target.classList.add("hx-swapping");
|
||||
var doSwap = function () {
|
||||
try {
|
||||
swapResponse(target, elt, resp, function () {
|
||||
target.classList.remove("hx-swapping");
|
||||
setTimeout(saveForHistory, 200);
|
||||
triggerEvent(elt, 'afterSwap.hx', {xhr: xhr, target: target});
|
||||
});
|
||||
var settleTasks = swapResponse(target, elt, resp);
|
||||
target.classList.remove("hx-swapping");
|
||||
target.classList.add("hx-settling");
|
||||
triggerEvent(elt, 'afterSwap.hx', {xhr: xhr, target: target});
|
||||
|
||||
var doSettle = function(){
|
||||
forEach(settleTasks, function (settleTask) {
|
||||
settleTask.call();
|
||||
});
|
||||
target.classList.remove("hx-settling");
|
||||
// push URL and save new page
|
||||
if (shouldSaveHistory) {
|
||||
pushUrlIntoHistory(pushedUrl || requestURL );
|
||||
saveHistory();
|
||||
}
|
||||
triggerEvent(elt, 'afterSettle.hx', {xhr: xhr, target: target});
|
||||
}
|
||||
|
||||
var settleDelayStr = getAttributeValue(elt, "hx-settle-delay") || "100ms";
|
||||
if (settleDelayStr) {
|
||||
setTimeout(doSettle, parseInterval(settleDelayStr))
|
||||
} else {
|
||||
doSettle();
|
||||
}
|
||||
} catch (e) {
|
||||
triggerEvent(elt, 'swapError.hx', {xhr: xhr, response: xhr.response, status: xhr.status, target: target});
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
var swapDelayStr = getAttributeValue(elt, "hx-swap-delay");
|
||||
if (swapDelayStr) {
|
||||
setTimeout(doSwap, parseInterval(swapDelayStr))
|
||||
|
@ -24,11 +24,13 @@
|
||||
<script src="scratch_server.js"></script>
|
||||
|
||||
<script>
|
||||
// this.server.respondWith("GET", "/test", "Clicked!");
|
||||
// var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
this.server.respondWith("GET", "/test", '<a hx-get="/test2">Click Me</a>');
|
||||
this.server.respondWith("GET", "/test2", "Clicked!");
|
||||
|
||||
this.server.respondWith("GET", "/test", '<div id="d1" style="color: red; margin: 100px">Foo</div>');
|
||||
make('<div hx-swap="outerHTML" hx-get="/test" hx-push-url="true" id="d1">Foo</div>');
|
||||
make('<div hx-get="/test">dd</div>')
|
||||
|
||||
// this.server.respondWith("GET", "/test", '<div id="d1" style="color: red; margin: 100px">Foo</div>');
|
||||
// make('<div hx-swap="outerHTML" hx-get="/test" hx-push-url="true" id="d1">Foo</div>');
|
||||
</script>
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user