mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-06-14 19:36:38 +10:00
361 lines
13 KiB
JavaScript
361 lines
13 KiB
JavaScript
(function(global) {
|
|
"use strict";
|
|
var eu = Windows.UI.Event.Util;
|
|
var anime = Windows.UI.Animation;
|
|
|
|
function PagePair(guideNode, pageNode, respHandler) {
|
|
var _guide = guideNode;
|
|
var _page = pageNode;
|
|
var _handler = respHandler || null;
|
|
Object.defineProperty(this, "guide", {
|
|
get: function() { return _guide; },
|
|
set: function(value) { _guide = value; }
|
|
});
|
|
Object.defineProperty(this, "page", {
|
|
get: function() { return _page; },
|
|
set: function(value) { _page = value; }
|
|
});
|
|
Object.defineProperty(this, "handler", {
|
|
get: function() { return _handler; },
|
|
set: function(value) { _handler = value; }
|
|
});
|
|
}
|
|
|
|
function PageManager() {
|
|
var dict = {};
|
|
var stack = [];
|
|
var current = -1;
|
|
var record = {}; // 记录哪些界面已经第一次加载过
|
|
var paramStack = [];
|
|
// scrollStack 与 stack 对齐:scrollStack[i] 对应 stack[i]
|
|
var scrollStack = [];
|
|
var nowScroll = 0;
|
|
var events = {
|
|
firstload: [],
|
|
beforeload: [],
|
|
load: [],
|
|
afterload: [],
|
|
willunload: [],
|
|
unload: []
|
|
};
|
|
|
|
function addHandler(type, fn) {
|
|
if (typeof fn !== "function") return;
|
|
events[type].push(fn);
|
|
}
|
|
|
|
function removeHandler(type, fn) {
|
|
var list = events[type];
|
|
for (var i = list.length - 1; i >= 0; i--) {
|
|
if (list[i] === fn) {
|
|
list.splice(i, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
function emit(type, arg) {
|
|
var list = events[type];
|
|
for (var i = 0; i < list.length; i++) {
|
|
try {
|
|
list[i](arg);
|
|
} catch (e) {}
|
|
}
|
|
}
|
|
|
|
function emitCancelable(type, arg) {
|
|
var list = events[type];
|
|
for (var i = 0; i < list.length; i++) {
|
|
try {
|
|
var r = list[i](arg);
|
|
if (r === false) return false;
|
|
} catch (e) {}
|
|
}
|
|
return true;
|
|
}
|
|
/**
|
|
* 添加载入事件
|
|
* @param {string} type 支持:"firstload"
|
|
"beforeload"
|
|
"load"
|
|
"afterload"
|
|
"willunload"
|
|
"unload"
|
|
|
|
* @param {function} fn
|
|
*/
|
|
this.addEventListener = function(type, fn) {
|
|
addHandler(type, fn);
|
|
};
|
|
/**
|
|
* 移除载入事件
|
|
* @param {string} type 支持:"firstload"
|
|
"beforeload"
|
|
"load"
|
|
"afterload"
|
|
"willunload"
|
|
"unload"
|
|
|
|
* @param {function} fn
|
|
*/
|
|
this.removeEventListener = function(type, fn) {
|
|
removeHandler(type, fn);
|
|
};
|
|
|
|
|
|
function guideClickHandler(e) {
|
|
var tag = this.__pageTag;
|
|
if (!tag) return;
|
|
if (this.classList.contains("selected")) return;
|
|
self.go(tag);
|
|
return;
|
|
var keys = Object.keys(dict);
|
|
var promises = [];
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
var pair = dict[key];
|
|
if (pair.guide.classList.contains("selected")) {
|
|
promises.push(anime.runAsync(
|
|
pair.page, [
|
|
anime.Keyframes.Opacity.hidden,
|
|
anime.Keyframes.Scale.down
|
|
]
|
|
).then(function(el) {
|
|
el.style.display = "none";
|
|
}));
|
|
}
|
|
}
|
|
this.classList.add("selected");
|
|
var after = Promise.join(promises);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
var pair = dict[key];
|
|
if (pair.guide.classList.contains("selected")) {
|
|
pair.page.style.display = "";
|
|
after.then(function() {
|
|
anime.runAsync(
|
|
pair.page, [
|
|
anime.Keyframes.Opacity.visible,
|
|
anime.Keyframes.Flyout.toLeft
|
|
]
|
|
);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
var self = this;
|
|
|
|
function _activate(tag, args, fromHistory) {
|
|
var pair = dict[tag];
|
|
if (!pair) throw "Page not found: " + tag;
|
|
if (!emitCancelable("beforeload", tag)) {
|
|
return;
|
|
}
|
|
var keys = Object.keys(dict);
|
|
var promises = [];
|
|
var oldTags = [];
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var k = keys[i];
|
|
var p = dict[k];
|
|
if (p.guide.classList.contains("selected") && k !== tag) {
|
|
if (!emitCancelable("willunload", k)) {
|
|
return;
|
|
}
|
|
oldTags.push(k);
|
|
promises.push(
|
|
(function(page, key) {
|
|
// 返回 anime.runAsync 产生的 Promise
|
|
return anime.runAsync(page, [anime.Keyframes.Opacity.hidden])
|
|
.then(function() {
|
|
page.style.display = "none";
|
|
page.style.opacity = 0;
|
|
page.style.height = 0;
|
|
emit("unload", key);
|
|
});
|
|
})(p.page, k)
|
|
);
|
|
p.guide.classList.remove("selected");
|
|
}
|
|
}
|
|
pair.guide.classList.add("selected");
|
|
pair.page.style.display = "";
|
|
emit("load", tag);
|
|
var after = Promise.join(promises);
|
|
after.then(function() {
|
|
if (!record[tag]) {
|
|
record[tag] = true;
|
|
emit("firstload", tag);
|
|
}
|
|
pair.page.style.opacity = 1;
|
|
if (pair.handler) {
|
|
// fix: use pair.handler
|
|
pair.handler(args);
|
|
}
|
|
try {
|
|
setTimeout(function(tnode) {
|
|
try {
|
|
tnode.scrollTop = nowScroll || 0;
|
|
} catch (ex) {}
|
|
}, 10, pair.page.parentNode);
|
|
} catch (ex) {}
|
|
return anime.runAsync(pair.page, [
|
|
anime.Keyframes.Opacity.visible,
|
|
anime.Keyframes.Flyout.toLeft
|
|
]).then(function() {
|
|
|
|
});
|
|
}).then(function() {
|
|
emit("afterload", tag);
|
|
});
|
|
}
|
|
this.register = function(tag, guideNode, pageNode, respHandler) {
|
|
pageNode.style.opacity = 0;
|
|
dict[tag] = new PagePair(guideNode, pageNode, respHandler);
|
|
guideNode.__pageTag = tag;
|
|
try {
|
|
eu.removeEvent(guideNode, "click", guideClickHandler);
|
|
eu.addEvent(guideNode, "click", guideClickHandler);
|
|
} catch (e) {}
|
|
};
|
|
this.edit = function(tag, pagePair) {
|
|
try {
|
|
if (dict[tag] && dict[tag].guide) {
|
|
dict[tag].guide.__pageTag = null;
|
|
}
|
|
} catch (e) {}
|
|
dict[tag] = pagePair;
|
|
try {
|
|
pagePair.guide.__pageTag = tag;
|
|
eu.removeEvent(pagePair.guide, "click", guideClickHandler);
|
|
eu.addEvent(pagePair.guide, "click", guideClickHandler);
|
|
} catch (e) {}
|
|
};
|
|
this.get = function(tag) {
|
|
return dict[tag];
|
|
};
|
|
this.getGuide = function(tag) {
|
|
return dict[tag].guide;
|
|
};
|
|
this.getPage = function(tag) {
|
|
return dict[tag].page;
|
|
};
|
|
this.getHandler = function(tag) {
|
|
return dict[tag].handler;
|
|
};
|
|
this.setGuide = function(tag, guideNode) {
|
|
try {
|
|
if (dict[tag] && dict[tag].guide) {
|
|
eu.removeEvent(dict[tag].guide, "click", guideClickHandler);
|
|
dict[tag].guide.__pageTag = null;
|
|
}
|
|
} catch (e) {}
|
|
dict[tag].guide = guideNode;
|
|
try {
|
|
guideNode.__pageTag = tag;
|
|
eu.removeEvent(guideNode, "click", guideClickHandler);
|
|
eu.addEvent(guideNode, "click", guideClickHandler);
|
|
} catch (e) {}
|
|
};
|
|
this.setPage = function(tag, pageNode) {
|
|
dict[tag].page = pageNode;
|
|
};
|
|
this.setHandler = function(tag, handler) {
|
|
dict[tag].handler = handler;
|
|
};
|
|
this.remove = function(tag) {
|
|
try {
|
|
try {
|
|
if (dict[tag] && dict[tag].guide) {
|
|
eu.removeEvent(dict[tag].guide, "click", guideClickHandler);
|
|
}
|
|
} catch (e) {}
|
|
delete dict[tag];
|
|
} catch (e) {}
|
|
};
|
|
this.clear = function() {
|
|
try {
|
|
var keys = Object.keys(dict);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
this.remove(keys[i]);
|
|
}
|
|
} catch (e) {}
|
|
};
|
|
this.jump = function(tag, args) {
|
|
_activate(tag, args, true);
|
|
};
|
|
this.go = function(tag, params) {
|
|
// limit history
|
|
if (stack.length > 300) {
|
|
stack.length = 0;
|
|
paramStack.length = 0;
|
|
scrollStack.length = 0;
|
|
current = -1;
|
|
}
|
|
// if we are in the middle, truncate forward history
|
|
if (current < stack.length - 1) {
|
|
stack.splice(current + 1);
|
|
paramStack.splice(current + 1);
|
|
scrollStack.splice(current + 1);
|
|
}
|
|
// save current page scrollTop
|
|
try {
|
|
if (current >= 0 && stack[current] && dict[stack[current]] && dict[stack[current]].page && dict[stack[current]].page.parentNode) {
|
|
scrollStack[current] = dict[stack[current]].page.parentNode.scrollTop;
|
|
}
|
|
} catch (e) {}
|
|
// push new entry
|
|
stack.push(tag);
|
|
paramStack.push(params);
|
|
// initialize scroll value for the new page (will be used if user goes back to it later)
|
|
scrollStack.push(0);
|
|
current++;
|
|
_activate(tag, params, false);
|
|
};
|
|
this.back = function() {
|
|
if (current <= 0) return false;
|
|
// save scroll of current page
|
|
try {
|
|
if (stack[current] && dict[stack[current]] && dict[stack[current]].page && dict[stack[current]].page.parentNode) {
|
|
scrollStack[current] = dict[stack[current]].page.parentNode.scrollTop;
|
|
}
|
|
} catch (e) {}
|
|
// move back
|
|
current--;
|
|
// restore scroll for new current
|
|
nowScroll = scrollStack[current] || 0;
|
|
_activate(stack[current], paramStack[current], true);
|
|
return true;
|
|
};
|
|
this.next = function() {
|
|
if (current >= stack.length - 1) return false;
|
|
// save scroll of current page
|
|
try {
|
|
if (stack[current] && dict[stack[current]] && dict[stack[current]].page && dict[stack[current]].page.parentNode) {
|
|
scrollStack[current] = dict[stack[current]].page.parentNode.scrollTop;
|
|
}
|
|
} catch (e) {}
|
|
// move forward
|
|
current++;
|
|
// restore scroll for new current
|
|
nowScroll = scrollStack[current] || 0;
|
|
_activate(stack[current], paramStack[current], true);
|
|
return true;
|
|
};
|
|
Object.defineProperty(this, "current", {
|
|
get: function() { return stack[current]; },
|
|
set: function(value) {
|
|
if (value < 0 || value >= stack.length) return;
|
|
current = value;
|
|
// restore scroll for assigned current
|
|
nowScroll = scrollStack[current] || 0;
|
|
_activate(stack[current], paramStack[current], true);
|
|
}
|
|
});
|
|
Object.defineProperty(this, "canback", {
|
|
get: function() { return current > 0; }
|
|
});
|
|
Object.defineProperty(this, "cannext", {
|
|
get: function() { return current < stack.length - 1; }
|
|
});
|
|
}
|
|
global.PageManager = PageManager;
|
|
})(this); |