mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +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); |