Updated manager and added appx manifest reader.

This commit is contained in:
Bruce
2026-01-24 22:06:55 +08:00
parent 75cb72964d
commit 503ece1c64
60 changed files with 4980 additions and 3819 deletions

View File

@@ -12,6 +12,18 @@
DarkModeBackgroundColor='#001629' />
</VisualElements>
</Application>
<Application Id='Manager'>
<VisualElements
DisplayName='Package Manager'
Logo='Settings.Assets\Logo.png'
SmallLogo='Settings.Assets\SmallLogo.png'
ForegroundText='light'
BackgroundColor='#159d9d'>
<DefaultTile ShowName='allLogos' />
<SplashScreen Image="VisualElements\splash\settings\splashscreen.png"
BackgroundColor="#159d9d" DarkModeBackgroundColor='#2e1e5c' />
</VisualElements>
</Application>
<Application Id='Settings'>
<VisualElements
DisplayName='Settings'

Binary file not shown.

View File

@@ -170,7 +170,7 @@
element.style.animation = generateAnimeString(swKeyFrames, uMillisecond, swTimingFunc, uDelayMs, swIteration, swDirection, swFillMode, swPlayState);
element.addEventListener("animationend", function() {
element.style.animation = "";
complete();
complete(element);
});
});
}

396
shared/html/js/appbar.js Normal file
View File

@@ -0,0 +1,396 @@
(function(global) {
"use strict";
// 基类:提供 element 管理与基础 dispose 行为
function PMAppBarBaseMember() {
var _element = null;
Object.defineProperty(this, "element", {
configurable: true, // <- 关键:允许子类重定义该属性
enumerable: false,
get: function() { return _element; },
set: function(value) {
_element = value;
try {
if (_element) {
// 让 DOM 节点可以反查到对应的 member
_element.appBarMember = this;
}
} catch (e) {}
}
});
// 可被子类或外部调用来从 DOM 中移除自身
this.dispose = function() {
try {
if (this.element && this.element.parentNode) {
this.element.parentNode.removeChild(this.element);
}
} catch (e) {}
};
}
function PMAppBarCommand() {
PMAppBarBaseMember.call(this);
var _button = document.createElement("button");
var _iconcontainer = document.createElement("span");
var _iconnode = document.createElement("span");
var _labelnode = document.createElement("span");
_button.appendChild(_iconcontainer);
_iconcontainer.appendChild(_iconnode);
_button.appendChild(_labelnode);
_button.classList.add("win-command");
_button.setAttribute("role", "menuitem");
_iconcontainer.classList.add("win-commandicon");
_iconcontainer.classList.add("win-commandring");
_iconnode.classList.add("win-commandimage");
_labelnode.classList.add("win-label");
_iconcontainer.tabIndex = -1;
_iconnode.tabIndex = -1;
_labelnode.tabIndex = -1;
_button.classList.add("win-global");
Windows.UI.Event.Util.addEvent(_button, "keydown", function(event) {
if (event.keyCode === 13) {
_button.click();
}
});
Object.defineProperty(this, "element", {
get: function() { return _button; },
set: function(value) { _button = value; }
});
Object.defineProperty(this, "icon", {
get: function() { return _iconnode.innerHTML; },
set: function(value) { _iconnode.innerHTML = value; }
});
Object.defineProperty(this, "label", {
get: function() { return _labelnode.textContent; },
set: function(value) { _labelnode.textContent = value; }
});
Object.defineProperty(this, "onclick", {
get: function() { return _button.onclick; },
set: function(value) { _button.onclick = value; }
});
Object.defineProperty(this, "selectable", {
get: function() { return _button.classList.contains("win-selectable"); },
set: function(value) {
try { Windows.UI.Event.Util.removeEvent(this.element, "click", selectHandler); } catch (e) {}
_button.classList.toggle("win-selectable", value);
if (!value) {
if (_button.classList.contains("win-selected")) {
_button.classList.remove("win-selected");
}
}
if (value) Windows.UI.Event.Util.addEvent(this.element, "click", selectHandler);
else Windows.UI.Event.Util.removeEvent(this.element, "click", selectHandler);
}
});
Object.defineProperty(this, "selected", {
get: function() { return _button.classList.contains("win-selected"); },
set: function(value) { _button.classList.toggle("win-selected", value); }
});
Object.defineProperty(this, "disabled", {
get: function() { try { return this.element.disabled; } catch (e) { return false; } },
set: function(value) { try { this.element.disabled = value; } catch (e) {} }
});
// global 或 selection (始终显示或有选择时显示)
Object.defineProperty(this, "section", {
get: function() {
if (_button.classList.contains("win-global")) return "global";
if (_button.classList.contains("win-selection")) return "selection";
return "none";
},
set: function(value) {
_button.classList.remove("win-global");
_button.classList.remove("win-selection");
if (value == "global") _button.classList.add("win-global");
if (value == "selection") _button.classList.add("win-selection");
}
});
function selectHandler(event) {
_button.classList.toggle("win-selected");
}
this.addEventListener = function(type, listener) {
try { Windows.UI.Event.Util.addEvent(this.element, type, listener); } catch (e) {}
};
this.removeEventListener = function(type, listener) {
try { Windows.UI.Event.Util.removeEvent(this.element, type, listener); } catch (e) {}
};
}
function PMAppBarSeparator() {
PMAppBarBaseMember.call(this);
var _hr = document.createElement("hr");
_hr.classList.add("win-command");
_hr.classList.add("win-global");
_hr.setAttribute("role", "separator");
Object.defineProperty(this, "element", {
get: function() { return _hr; },
set: function(value) { _hr = value; }
});
}
function PMAppBar(container) {
var _container = container;
var _enable = true;
function init(node) {
var classNames = [
"win-overlay",
"win-commandlayout",
"win-appbar",
"appbar"
]
try {
for (var i = 0; i < classNames.length; i++) {
if (!node.classList.contains(classNames[i]))
node.classList.add(classNames[i]);
}
} catch (e) {}
try {
node.appBarControl = this;
} catch (e) {}
}
Object.defineProperty(this, "element", {
get: function() { return _container; },
set: function(value) {
_container = value;
init(value);
// 将已有成员渲染到新的容器中
try {
// 先移除所有成员 DOM如果之前挂载过
for (var i = 0; i < this._members.length; i++) {
try {
var mEl = this._members[i].element;
if (mEl && mEl.parentNode === _container) {
_container.removeChild(mEl);
}
} catch (e) {}
}
// 重新挂载所有成员,按数组顺序
for (i = 0; i < this._members.length; i++) {
try {
var el = this._members[i].element;
if (el) _container.appendChild(el);
} catch (e) {}
}
} catch (e) {}
}
});
// 成员管理
this._members = [];
// 返回内部数组引用(只读语义上)
Object.defineProperty(this, "members", {
get: function() { return this._members; }
});
// 添加成员到末尾,返回索引;若失败返回 -1
this.add = function(member) {
if (!member || !member.element) return -1;
this._members.push(member);
try {
if (_container) _container.appendChild(member.element);
} catch (e) {}
this._updateSelectionVisibility();
return this._members.length - 1;
};
this.addMember = this.add; // alias
// 在指定索引处插入(如果 index 为 undefined 或超范围,则 append
this.insertAt = function(member, index) {
if (!member || !member.element) return -1;
var len = this._members.length;
if (typeof index !== "number" || index < 0 || index > len) {
return this.add(member);
}
this._members.splice(index, 0, member);
try {
if (_container) {
var refNode = _container.childNodes[index] || null;
_container.insertBefore(member.element, refNode);
}
} catch (e) {}
this._updateSelectionVisibility();
return index;
};
// remove 接受成员对象或索引
this.remove = function(memberOrIndex) {
var idx = -1;
if (typeof memberOrIndex === "number") {
idx = memberOrIndex;
} else {
idx = this._members.indexOf(memberOrIndex);
}
if (idx < 0 || idx >= this._members.length) return false;
var removed = this._members.splice(idx, 1)[0];
try {
if (removed && removed.element && removed.element.parentNode) {
removed.element.parentNode.removeChild(removed.element);
}
} catch (e) {}
this._updateSelectionVisibility();
return true;
};
// 替换指定索引的成员,返回 true/false
this.replaceAt = function(index, member) {
if (!member || !member.element) return false;
if (typeof index !== "number" || index < 0 || index >= this._members.length) return false;
var old = this._members[index];
this._members[index] = member;
try {
if (_container && old && old.element) {
// 如果 old.element 在容器中,直接 replaceChild
if (old.element.parentNode === _container) {
_container.replaceChild(member.element, old.element);
} else {
// 备用:在位置 index 插入
var ref = _container.childNodes[index] || null;
_container.insertBefore(member.element, ref);
}
} else if (_container) {
// 没有 old 元素,直接 append
_container.appendChild(member.element);
}
} catch (e) {}
this._updateSelectionVisibility();
return true;
};
this.getMember = function(index) {
return this._members[index];
};
this.indexOf = function(member) {
return this._members.indexOf(member);
};
this.clear = function() {
while (this._members.length) {
var m = this._members.shift();
try {
if (m && m.element && m.element.parentNode) {
m.element.parentNode.removeChild(m.element);
}
} catch (e) {}
}
};
var timer = null;
var isupdating = false;
function waitTimer(ms) {
clearTimeout(timer);
isupdating = true;
timer = setTimeout(function(t) {
isupdating = false;
t = null;
}, ms, timer);
}
Object.defineProperty(this, "isupdating", {
get: function() { return isupdating; }
});
var touchHide = document.createElement("div");
touchHide.classList.add("appbar-touchhide");
touchHide.style.display = "none";
Windows.UI.Event.Util.addEvent(touchHide, "click", function(event) {
touchHide.style.display = "none";
this.hide();
}.bind(this));
document.body.appendChild(touchHide);
function showTouchHide() {
if (touchHide == null || touchHide == void 0) {
touchHide = document.createElement("div");
touchHide.classList.add("appbar-touchhide");
}
touchHide.style.display = "";
}
function hideTouchHide() {
touchHide.style.display = "none";
}
this.show = function() {
try {
if (!_enable) return;
if (!this.element.classList.contains("show"))
this.element.classList.add("show");
waitTimer(500);
showTouchHide();
} catch (e) {}
};
this.hide = function() {
try {
if (this.element.classList.contains("show"))
this.element.classList.remove("show");
waitTimer(500);
hideTouchHide();
} catch (e) {}
};
this.setSelectionActive = function(active) {
this._hasSelection = !!active;
this._updateSelectionVisibility();
};
this._updateSelectionVisibility = function() {
for (var i = 0; i < this._members.length; i++) {
var el = this._members[i].element;
if (el && el.classList && el.classList.contains("win-selection")) {
el.style.display = this._hasSelection ? "" : "none";
}
}
};
Object.defineProperty(this, "enabled", {
get: function() { return _enable; },
set: function(value) {
_enable = value;
if (!value) {
this.hide();
}
}
});
Object.defineProperty(this, "isshowing", {
get: function() { return this.element.classList.contains("show"); },
set: function(value) {
if (value) {
this.show();
} else {
this.hide();
}
}
});
this._eventShowHandler = function(event) {
if (!this.isshowing) this.show();
else this.hide();
};
this._eventHideHandler = function(event) {
this.hide();
};
var EventUtil = Windows.UI.Event.Util;
var self = this;
EventUtil.addEvent(document, "contextmenu", function(event) {
self._eventShowHandler(event);
event.preventDefault();
});
var pressTimer = null;
EventUtil.addEvent(document, "mousedown", function(event) {
if (!self._enable) return;
pressTimer = setTimeout(function(e) {
self._eventShowHandler(e);
event.preventDefault();
}, 600, event);
});
EventUtil.addEvent(document, "mouseup", function() {
clearTimeout(pressTimer);
});
}
global.AppBar = {
AppBar: PMAppBar,
Command: PMAppBarCommand,
Separator: PMAppBarSeparator,
BaseMember: PMAppBarBaseMember
};
})(this);

479
shared/html/js/datasrc.js Normal file
View File

@@ -0,0 +1,479 @@
(function(global) {
"use strict";
global.DataView = {
ChangeType: {
add: "add",
remove: "remove",
change: "change",
clear: "clear",
move: "move",
sort: "sort",
},
};
var childAnimeDuration = 120;
var parentAnimeDuration = 400;
function showItemAmine(node) {
return Windows.UI.Animation.runAsync(node, [
Windows.UI.Animation.Keyframes.Scale.up,
Windows.UI.Animation.Keyframes.Opacity.visible,
], childAnimeDuration);
}
function hideItemAmine(node) {
return Windows.UI.Animation.runAsync(node, [
Windows.UI.Animation.Keyframes.Scale.down,
Windows.UI.Animation.Keyframes.Opacity.hidden,
], childAnimeDuration);
}
function updateItemAmine(node, updateCallback) {
return Windows.UI.Animation.runAsync(node, [
Windows.UI.Animation.Keyframes.Opacity.hidden,
Windows.UI.Animation.Keyframes.Scale.down
], 120).then(function() {
if (updateCallback && typeof updateCallback === 'function') {
updateCallback(node);
}
return Windows.UI.Animation.runAsync(node, [
Windows.UI.Animation.Keyframes.Opacity.visible,
Windows.UI.Animation.Keyframes.Scale.up
], 120);
}).then(function() {
return node;
});
}
function PMChangeEvent(type, datas, detailOperation) {
this.type = type; // ChangeType
this.datas = datas || []; // 受影响的数据
this.detail = detailOperation || null;
}
function PMDataSource() {
var _list = [];
var _listeners = [];
this.subscribe = function(fn) {
if (typeof fn === "function") {
_listeners.push(fn);
}
};
function emit(evt) {
for (var i = 0; i < _listeners.length; i++) {
_listeners[i](evt);
}
}
this.add = function(item) {
_list.push(item);
emit(new PMChangeEvent(
DataView.ChangeType.add, [item], { index: _list.length - 1 }
));
};
this.removeAt = function(index) {
if (index < 0 || index >= _list.length) return;
var item = _list.splice(index, 1)[0];
emit(new PMChangeEvent(
DataView.ChangeType.remove, [item], { index: index }
));
};
this.changeAt = function(index, newItem) {
if (index < 0 || index >= _list.length) return;
_list[index] = newItem;
emit(new PMChangeEvent(
DataView.ChangeType.change, [newItem], { index: index }
));
};
this.clear = function() {
_list.length = 0;
emit(new PMChangeEvent(
DataView.ChangeType.clear
));
};
this.move = function(from, to) {
if (from === to ||
from < 0 || to < 0 ||
from >= _list.length || to >= _list.length) {
return;
}
var item = _list.splice(from, 1)[0];
_list.splice(to, 0, item);
emit(new PMChangeEvent(
DataView.ChangeType.move, [item], { from: from, to: to }
));
};
this.sort = function(compareFn) {
_list.sort(compareFn);
emit(new PMChangeEvent(
DataView.ChangeType.sort,
_list.slice(0), { compare: compareFn }
));
};
this.get = function() {
return _list.slice(0);
};
this.addList = function(list, keySelector) {
if (!list || !list.length) return;
var added = [];
var changed = [];
var useKey = keySelector !== void 0;
var getKey;
if (keySelector === null) {
getKey = function(item) {
return item && item.id;
};
} else if (typeof keySelector === "function") {
getKey = keySelector;
}
for (var i = 0; i < list.length; i++) {
var item = list[i];
if (!useKey) {
_list.push(item);
added.push({ item: item, index: _list.length - 1 });
continue;
}
var key = getKey(item);
if (key === void 0) {
_list.push(item);
added.push({ item: item, index: _list.length - 1, key: key });
continue;
}
var found = -1;
for (var j = 0; j < _list.length; j++) {
if (getKey(_list[j]) === key) {
found = j;
break;
}
}
if (found >= 0) {
_list[found] = item;
changed.push({ item: item, index: found, key: key });
} else {
_list.push(item);
added.push({ item: item, index: _list.length - 1, key: key });
}
}
// 统一发出一个事件
if (added.length > 0) {
emit(new PMChangeEvent(DataView.ChangeType.add, added));
}
if (changed.length > 0) {
emit(new PMChangeEvent(DataView.ChangeType.change, changed));
}
};
this.updateList = function(list, fnGetKey) {
if (!list) list = [];
var getKey;
if (fnGetKey === null) {
getKey = function(item) {
return item && item.id;
};
} else if (typeof fnGetKey === "function") {
getKey = fnGetKey;
} else {
// 不提供 key直接整体替换
_list = list.slice(0);
emit(new PMChangeEvent(
DataView.ChangeType.clear
));
emit(new PMChangeEvent(
DataView.ChangeType.add,
list.map(function(item, index) {
return { item: item, index: index };
})
));
return;
}
var oldList = _list;
var newList = list;
var oldKeyIndex = {};
var newKeyIndex = {};
var i;
// 建立旧列表 key → index
for (i = 0; i < oldList.length; i++) {
var ok = getKey(oldList[i]);
if (ok !== void 0) {
oldKeyIndex[ok] = i;
}
}
// 建立新列表 key → index
for (i = 0; i < newList.length; i++) {
var nk = getKey(newList[i]);
if (nk !== void 0) {
newKeyIndex[nk] = i;
}
}
var added = [];
var changed = [];
var removed = [];
// 1⃣ 找 remove
for (i = oldList.length - 1; i >= 0; i--) {
var oldItem = oldList[i];
var oldKey = getKey(oldItem);
if (oldKey === void 0 || newKeyIndex[oldKey] === void 0) {
removed.push({
item: oldItem,
index: i,
key: oldKey
});
}
}
// 2⃣ 找 add / change
for (i = 0; i < newList.length; i++) {
var newItem = newList[i];
var newKey = getKey(newItem);
if (newKey === void 0 || oldKeyIndex[newKey] === void 0) {
added.push({
item: newItem,
index: i,
key: newKey
});
} else {
var oldIndex = oldKeyIndex[newKey];
var oldItem2 = oldList[oldIndex];
if (oldItem2 !== newItem) {
changed.push({
item: newItem,
index: oldIndex,
key: newKey
});
}
}
}
// 3⃣ 执行 remove从后往前
if (removed.length > 0) {
for (i = 0; i < removed.length; i++) {
_list.splice(removed[i].index, 1);
}
emit(new PMChangeEvent(
DataView.ChangeType.remove,
removed
));
}
// 4⃣ 执行 add / change重建顺序
_list = newList.slice(0);
if (added.length > 0) {
emit(new PMChangeEvent(
DataView.ChangeType.add,
added
));
}
if (changed.length > 0) {
emit(new PMChangeEvent(
DataView.ChangeType.change,
changed
));
}
};
}
function PMDataListView(container, templateFn) {
this.container = container;
this.templateFn = templateFn;
this.listViewControl = this;
}
PMDataListView.prototype.bind = function(ds) {
var self = this;
var items = ds.get();
self.container.innerHTML = "";
// 动画队列,保证异步操作不会乱序
var queue = Promise.resolve();
function renderItem(data, index) {
var el = self.templateFn(data, index);
el.addEventListener("click", function() {
self._toggleSelect(el);
});
return el;
}
// 初始化渲染
for (var i = 0; i < items.length; i++) {
self.container.appendChild(renderItem(items[i], i));
}
ds.subscribe(function(evt) {
// 把每次事件放进队列,保证顺序执行
queue = queue.then(function() {
switch (evt.type) {
case DataView.ChangeType.add:
{
// evt.datas = [{item, index}, ...]
var datas = evt.datas;
// 先批量 append 到 DOM顺序必须保持
var nodes = [];
for (var i = 0; i < datas.length; i++) {
var n = renderItem(datas[i].item, datas[i].index);
nodes.push(n);
self.container.appendChild(n);
}
// 如果数量>=20动画并行否则串行
if (datas.length >= 20) {
var promises = [];
for (var j = 0; j < nodes.length; j++) {
promises.push(showItemAmine(nodes[j]));
}
return Promise.all(promises);
} else {
// 串行
var p = Promise.resolve();
for (var k = 0; k < nodes.length; k++) {
(function(node) {
p = p.then(function() {
return showItemAmine(node);
});
})(nodes[k]);
}
return p;
}
}
case DataView.ChangeType.remove:
{
var node = self.container.children[evt.detail.index];
if (!node) return;
// 隐藏动画完成后再移除
return hideItemAmine(node).then(function() {
self.container.removeChild(node);
});
}
case DataView.ChangeType.change:
{
var oldNode = self.container.children[evt.detail.index];
if (!oldNode) return;
// 先淡出旧节点
return hideItemAmine(oldNode).then(function() {
// 替换节点
var newNode = renderItem(evt.datas[0], evt.detail.index);
self.container.replaceChild(newNode, oldNode);
// 再淡入新节点
return showItemAmine(newNode);
});
}
case DataView.ChangeType.clear:
self.container.innerHTML = "";
return Promise.resolve();
case DataView.ChangeType.move:
{
var node = self.container.children[evt.detail.from];
var ref = self.container.children[evt.detail.to] || null;
if (node) self.container.insertBefore(node, ref);
return Promise.resolve();
}
case DataView.ChangeType.sort:
{
self.container.innerHTML = "";
for (var i = 0; i < evt.datas.length; i++) {
self.container.appendChild(renderItem(evt.datas[i], i));
}
return Promise.resolve();
}
}
});
});
};
PMDataListView.prototype._toggleSelect = function(ele) {
// 如果选择模式为 none则不处理
if (this.selectionMode === "none") return;
var isSelected = ele.classList.contains("selected");
if (this.selectionMode === "single") {
// 单选:先取消所有选中
this._clearSelected();
if (!isSelected) {
ele.classList.add("selected");
}
} else if (this.selectionMode === "multiple") {
// 多选:点一次切换状态
if (isSelected) {
ele.classList.remove("selected");
} else {
ele.classList.add("selected");
}
}
};
PMDataListView.prototype._clearSelected = function() {
var selected = this.container.querySelectorAll(".selected");
for (var i = 0; i < selected.length; i++) {
selected[i].classList.remove("selected");
}
};
Object.defineProperty(PMDataListView.prototype, "selectionMode", {
get: function() {
return this._selectionMode || "none";
},
set: function(value) {
var mode = String(value).toLowerCase();
if (mode !== "none" && mode !== "single" && mode !== "multiple") {
mode = "none";
}
this._selectionMode = mode;
// 切换模式时,清空选中状态(可选)
if (mode === "none") {
this._clearSelected();
}
if (mode === "single") {
// 单选模式:如果多选了多个,保留第一个
var selected = this.container.querySelectorAll(".selected");
if (selected.length > 1) {
for (var i = 1; i < selected.length; i++) {
selected[i].classList.remove("selected");
}
}
}
}
});
Object.defineProperty(PMDataListView.prototype, "selectedItems", {
get: function() {
return Array.prototype.slice.call(this.container.querySelectorAll(".selected"));
}
});
global.DataView.ChangeEvent = PMChangeEvent;
global.DataView.DataSource = PMDataSource;
global.DataView.ListView = PMDataListView;
})(this);

View File

@@ -0,0 +1,50 @@
(function(global) {
"use strict";
var pkg_ns = external.Package;
function archsToStr(archs) {
var arr = [];
for (var i = 0; i < archs.length; i++) {
switch (archs[i]) {
case 0:
arr.push("x86");
break;
case 5:
arr.push("ARM");
break;
case 9:
arr.push("x64");
break;
case 11:
arr.push("Neutral");
break;
case 12:
arr.push("ARM64");
break;
case 65535:
arr.push("Unknown");
break;
}
}
return arr.join(", ");
}
function setAppInfoPageContent(info) {
var page = document.getElementById("page-appinfo");
page.querySelector(".display-name").textContent = info.Properties.DisplayName;
page.querySelector(".publisher-display-name").textContent = info.Properties.Publisher;
page.querySelector(".version").textContent = info.Identity.Version.Expression;
page.querySelector(".description").textContent = info.Properties.Description;
page.querySelector(".identity .name").textContent = info.Identity.Name;
page.querySelector(".identity .publisher").textContent = info.Identity.Publisher;
page.querySelector(".identity .publisher-id").textContent = info.Identity.PublisherId;
page.querySelector(".identity .family-name").textContent = info.Identity.FamilyName;
page.querySelector(".identity .full-name").textContent = info.Identity.FullName;
page.querySelector(".identity .architecture").textContent = archsToStr(info.Identity.ProcessArchitecture);
var il = info.InstallLocation;
var pkg = pkg_ns.fromInstallLocation(il);
var json = pkg.jsonText;
console.log(JSON.parse(json));
}
global.setAppInfoPageContent = setAppInfoPageContent;
})(this);

524
shared/html/js/mgrinit.js Normal file
View File

@@ -0,0 +1,524 @@
(function(global) {
function _createImage(src, onload, onerror) {
var img = new Image();
img.onload = function() {
onload(img);
};
img.onerror = function() {
onerror && onerror();
};
img.src = src;
}
function getSolidOpaqueBackgroundColor(source, callback) {
function processImage(img) {
if (!img || !img.complete) {
callback(null);
return;
}
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = img.naturalWidth || img.width;
canvas.height = img.naturalHeight || img.height;
ctx.drawImage(img, 0, 0);
try {
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
} catch (e) {
// 跨域导致的安全异常
callback(null);
return;
}
var data = imageData.data;
var w = canvas.width;
var h = canvas.height;
var colors = {};
var total = 0;
function pushColor(r, g, b, a) {
if (a !== 255) return;
var key = r + "," + g + "," + b;
colors[key] = (colors[key] || 0) + 1;
total++;
}
// top + bottom
for (var x = 0; x < w; x++) {
var topIndex = (0 * w + x) * 4;
var botIndex = ((h - 1) * w + x) * 4;
pushColor(data[topIndex], data[topIndex + 1], data[topIndex + 2], data[topIndex + 3]);
pushColor(data[botIndex], data[botIndex + 1], data[botIndex + 2], data[botIndex + 3]);
}
// left + right
for (var y = 1; y < h - 1; y++) {
var leftIndex = (y * w + 0) * 4;
var rightIndex = (y * w + (w - 1)) * 4;
pushColor(data[leftIndex], data[leftIndex + 1], data[leftIndex + 2], data[leftIndex + 3]);
pushColor(data[rightIndex], data[rightIndex + 1], data[rightIndex + 2], data[rightIndex + 3]);
}
if (total === 0) {
callback(null);
return;
}
var bestKey = null;
var bestCount = 0;
for (var key in colors) {
if (colors.hasOwnProperty(key)) {
if (colors[key] > bestCount) {
bestCount = colors[key];
bestKey = key;
}
}
}
// 95% 纯色阈值
if (bestCount / total < 0.95) {
callback(null);
return;
}
callback(bestKey);
}
// 如果传入的是 img 元素
if (source && source.tagName && source.tagName.toLowerCase() === "img") {
processImage(source);
return;
}
// 如果传入的是 data url 或普通 url
if (typeof source === "string") {
_createImage(source, processImage, function() {
callback(null);
});
return;
}
callback(null);
}
function getHamonyColor(source, callback) {
function _createImage(src, onload, onerror) {
var img = new Image();
img.onload = function() { onload(img); };
img.onerror = function() { onerror && onerror(); };
img.src = src;
}
function _toKey(r, g, b) {
return r + "," + g + "," + b;
}
function _rgbToHsl(r, g, b) {
r /= 255;
g /= 255;
b /= 255;
var max = Math.max(r, g, b);
var min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0;
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return { h: h, s: s, l: l };
}
function _hslToRgb(h, s, l) {
var r, g, b;
function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
if (s === 0) {
r = g = b = l;
} else {
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255)
};
}
function _lum(r, g, b) {
function f(x) {
x = x / 255;
return x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
}
return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
}
function _contrast(a, b) {
var L1 = _lum(a.r, a.g, a.b);
var L2 = _lum(b.r, b.g, b.b);
var lighter = Math.max(L1, L2);
var darker = Math.min(L1, L2);
return (lighter + 0.05) / (darker + 0.05);
}
function _tryPureBackground(data, w, h) {
var edgeColors = {};
var edgeTotal = 0;
function push(r, g, b, a) {
if (a !== 255) return;
var k = _toKey(r, g, b);
edgeColors[k] = (edgeColors[k] || 0) + 1;
edgeTotal++;
}
for (var x = 0; x < w; x++) {
var top = (0 * w + x) * 4;
var bot = ((h - 1) * w + x) * 4;
push(data[top], data[top + 1], data[top + 2], data[top + 3]);
push(data[bot], data[bot + 1], data[bot + 2], data[bot + 3]);
}
for (var y = 1; y < h - 1; y++) {
var left = (y * w + 0) * 4;
var right = (y * w + (w - 1)) * 4;
push(data[left], data[left + 1], data[left + 2], data[left + 3]);
push(data[right], data[right + 1], data[right + 2], data[right + 3]);
}
if (edgeTotal === 0) return null;
var best = null,
bestCount = 0;
for (var k in edgeColors) {
if (edgeColors.hasOwnProperty(k) && edgeColors[k] > bestCount) {
bestCount = edgeColors[k];
best = k;
}
}
if (best && bestCount / edgeTotal >= 0.95) return best;
return null;
}
function _process(img) {
if (!img || !img.complete) { callback(null); return; }
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = img.naturalWidth || img.width;
canvas.height = img.naturalHeight || img.height;
ctx.drawImage(img, 0, 0);
var imageData;
try {
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
} catch (e) {
callback(null);
return;
}
var data = imageData.data;
var w = canvas.width,
h = canvas.height;
// 1) 尝试纯色背景
var pure = _tryPureBackground(data, w, h);
if (pure) { callback(pure); return; }
// 2) 统计不透明像素(抽样)
var sumR = 0,
sumG = 0,
sumB = 0,
count = 0;
var samples = 0;
var step = 4; // 4x抽样减少性能消耗
for (var y = 0; y < h; y += step) {
for (var x = 0; x < w; x += step) {
var i = (y * w + x) * 4;
var a = data[i + 3];
if (a === 255) {
sumR += data[i];
sumG += data[i + 1];
sumB += data[i + 2];
count++;
}
samples++;
}
}
if (count === 0) { callback(null); return; }
var avgR = sumR / count,
avgG = sumG / count,
avgB = sumB / count;
// 3) 生成候选色(借鉴流行配色)
var base = _rgbToHsl(avgR, avgG, avgB);
function clamp(v, min, max) { return Math.max(min, Math.min(max, v)); }
var candidates = [];
// 中性色(低饱和)
candidates.push(_hslToRgb(base.h, 0.05, 0.5));
candidates.push(_hslToRgb(base.h, 0.1, 0.6));
candidates.push(_hslToRgb(base.h, 0.1, 0.4));
// 平均色去饱和
candidates.push(_hslToRgb(base.h, clamp(base.s * 0.4, 0.05, 0.2), clamp(base.l, 0.2, 0.8)));
// 互补色(活泼)
candidates.push(_hslToRgb((base.h + 0.5) % 1, clamp(base.s * 0.6, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
// 类似色
candidates.push(_hslToRgb((base.h + 0.083) % 1, clamp(base.s * 0.5, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
candidates.push(_hslToRgb((base.h - 0.083 + 1) % 1, clamp(base.s * 0.5, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
// 三分色
candidates.push(_hslToRgb((base.h + 0.333) % 1, clamp(base.s * 0.6, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
candidates.push(_hslToRgb((base.h - 0.333 + 1) % 1, clamp(base.s * 0.6, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
// 4) 计算最小对比度(与所有不透明像素)
function minContrastWithImage(bg) {
var bgObj = { r: bg.r, g: bg.g, b: bg.b };
var minC = Infinity;
for (var y = 0; y < h; y += step) {
for (var x = 0; x < w; x += step) {
var i = (y * w + x) * 4;
if (data[i + 3] !== 255) continue;
var px = { r: data[i], g: data[i + 1], b: data[i + 2] };
var c = _contrast(bgObj, px);
if (c < minC) minC = c;
}
}
return minC;
}
var best = null;
for (var i = 0; i < candidates.length; i++) {
var c = candidates[i];
var minC = minContrastWithImage(c);
if (minC >= 4.5) {
best = c;
break;
}
}
if (best) {
callback(_toKey(best.r, best.g, best.b));
} else {
callback(null);
}
}
if (source && source.tagName && source.tagName.toLowerCase() === "img") {
_process(source);
} else if (typeof source === "string") {
_createImage(source, _process, function() { callback(null); });
} else {
callback(null);
}
}
function getSuitableBackgroundColor(source, callback) {
getSolidOpaqueBackgroundColor(source, function(color) {
if (color) {
callback(color);
} else {
getHamonyColor(source, callback);
}
});
}
function createLocalizedCompare(locale) {
return function(a, b) {
a = a || "";
b = b || "";
return a.localeCompare(b, locale, {
numeric: true, // 2 < 10
sensitivity: "base" // 不区分大小写 / 重音
});
};
}
var pagemgr = new PageManager();
OnLoad.add(function() {
var listContainer = document.getElementById("applist");
var appItemTemplate = document.getElementById("appitem-template");
var mgr = Package.manager;
var nstr = Bridge.NString;
var datasrc = new DataView.DataSource();
var themeColor = Bridge.UI.themeColor;
var loadingDisplay = document.getElementById("applist-loading");
var loadingStatus = loadingDisplay.querySelector(".title");
var listView = new DataView.ListView(listContainer, function(item) {
var appItem = appItemTemplate.cloneNode(true);
appItem.id = "";
appItem.style.display = "";
var logoimg = appItem.querySelector("img");
logoimg.src = item.Properties.LogoBase64 || logoimg.src;
logoimg.parentElement.style.backgroundColor = themeColor;
var appName = appItem.querySelector(".displayName");
appName.textContent = item.Properties.DisplayName || item.Identity.Name;
var appPub = appItem.querySelector(".publisher");
appPub.textContent = item.Properties.Publisher;
appItem.data = item;
appItem.setAttribute("data-install-location", item.InstallLocation);
appItem.setAttribute("data-development-mode", item.DevelopmentMode);
appItem.setAttribute("data-is-bundle", item.IsBundle);
appItem.setAttribute("data-is-framework", item.Properties.Framework);
appItem.setAttribute("data-family-name", item.Identity.FamilyName);
appItem.setAttribute("data-full-name", item.Identity.FullName);
appItem.setAttribute("data-version", item.Identity.Version.Expression);
appItem.setAttribute("data-users", item.Users);
appItem.setAttribute("data-publisher-id", item.Identity.PublisherId);
setTimeout(function(a, b) {
getSolidOpaqueBackgroundColor(a, function(color) {
try {
var pipes = color.split(",");
var colorobj = new Color(parseInt(pipes[0]), parseInt(pipes[1]), parseInt(pipes[2]));
if (colorobj.hex == "#ffffff" || colorobj.hex == "#000000") throw "too white or black";
var rgbstr = colorobj.RGB.toString();
b.style.backgroundColor = rgbstr;
} catch (e) {}
});
}, 0, item.Properties.LogoBase64, logoimg.parentElement);
Windows.UI.Event.Util.addEvent(appItem.querySelector("div[role=advance] a"), "click", function(e) {
e.stopPropagation();
try {
pagemgr.go("appinfo", this.parentNode.parentNode.parentNode.data);
} catch (ex) {}
});
return appItem;
});
listView.selectionMode = "single";
listView.bind(datasrc);
var timer = null;
function refreshAppList() {
function update(datas) {
var newDatas = [];
for (var i = 0; i < datas.length; i++) {
var data = datas[i];
if (data.Properties.Framework) continue; // 过滤依赖项
var isfind = false; // 过滤系统应用
for (var j = 0; data && data.Users && j < data.Users.length; j++) {
if (Bridge.NString.equals(data.Users[j], "NT AUTHORITY\\SYSTEM")) {
isfind = true;
break;
}
}
if (isfind) continue;
newDatas.push(data);
}
datasrc.updateList(newDatas, function(item) {
return item.Identity.FullName || "";
});
var compare = function(a, b) { return a - b; };
try {
compare = createLocalizedCompare(external.System.Locale.currentLocale);
} catch (e) {
try {
compare = createLocalizedCompare(navigator.language);
} catch (e) {
compare = function(a, b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
};
}
}
datasrc.sort(function(a, b) {
return compare(a.Properties.DisplayName, b.Properties.DisplayName);
});
}
if (timer) clearTimeout(timer);
timer = null;
loadingDisplay.style.display = "";
loadingDisplay.classList.remove("noloading");
function waitAndHide() {
if (timer) clearTimeout(timer);
timer = null;
timer = setTimeout(function() {
loadingDisplay.style.display = "none";
}, 10000);
}
loadingStatus.textContent = "正在加载数据...";
return mgr.get().then(function(result) {
loadingDisplay.classList.add("noloading");
loadingStatus.textContent = "已经加载了所有数据";
update(result.list);
waitAndHide();
}, function(error) {
loadingDisplay.classList.add("noloading");
loadingStatus.textContent = "更新时出错: " + (error.result ? (error.result.message || error.result.ErrorCode || "获取失败") : (error.message || error.error || error));
try { update(error.list); } catch (e) {}
waitAndHide();
})
}
var appbar = document.getElementById("appBar");
var appbarControl = new AppBar.AppBar(appbar);
var refreshButton = new AppBar.Command();
refreshButton.icon = "&#57623;";
refreshButton.label = "刷新";
global.refreshAppList2 = function refreshAppList2() {
appbarControl.hide();
refreshButton.disabled = true;
refreshAppList().done(function() {
refreshButton.disabled = false;
}, function(error) {
refreshButton.disabled = false;
});
}
refreshButton.addEventListener("click", refreshAppList2);
appbarControl.add(refreshButton);
refreshAppList2();
pagemgr.register("manager", document.getElementById("tag-manager"), document.getElementById("page-manager"));
pagemgr.register("appinfo", document.getElementById("tag-appinfo"), document.getElementById("page-appinfo"), setAppInfoPageContent);
var appinfoBackPage = document.getElementById("page-appinfo").querySelector(".win-backbutton");
Windows.UI.Event.Util.addEvent(appinfoBackPage, "click", function(e) {
pagemgr.back();
});
pagemgr.addEventListener("load", function(e) {
appbarControl.enabled = e == "manager";
refreshButton.style.display = e == "manager" ? "" : "none";
});
pagemgr.go("manager");
});
})(this);

359
shared/html/js/pagemgr.js Normal file
View File

@@ -0,0 +1,359 @@
(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(
anime.runAsync(p.page, [
anime.Keyframes.Opacity.hidden
]).then((function(page, key) {
return function() {
page.style.display = "none";
page.style.opacity = 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) {
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);

128
shared/html/js/pkginfo.js Normal file
View File

@@ -0,0 +1,128 @@
(function(global) {
"use strict";
var mgr = external.Package.manager;
function parseJsonCallback(swJson, callback) {
var ret = swJson;
try {
if (swJson) ret = JSON.parse(swJson);
} catch (e) {}
if (callback) callback(ret);
}
global.Package = {
reader: function(pkgPath) { external.Package.reader(pkgPath); },
manager: {
add: function(swPkgPath, uOptions) {
return new Promise(function(resolve, reject, progress) {
mgr.addPackage(swPkgPath, uOptions, function(result) {
parseJsonCallback(result, resolve);
}, function(result) {
parseJsonCallback(result, reject);
}, progress);
})
},
get: function() {
return new Promise(function(resolve, reject) {
mgr.getPackages(function(result) {
parseJsonCallback(result, resolve);
}, function(result) {
parseJsonCallback(result, reject);
});
});
},
remove: function(swPkgFullName) {
return new Promise(function(resolve, reject, progress) {
mgr.removePackage(swPkgFullName, function(result) {
parseJsonCallback(result, resolve);
}, function(result) {
parseJsonCallback(result, reject);
}, progress);
});
},
clearup: function(swPkgName, swUserSID) {
return new Promise(function(resolve, reject, progress) {
mgr.clearupPackage(swPkgName, swUserSID, function(result) {
parseJsonCallback(result, resolve);
}, function(result) {
parseJsonCallback(result, reject);
}, progress);
});
},
register: function(swPkgPath, uOptions) {
return new Promise(function(resolve, reject, progress) {
mgr.registerPackage(swPkgPath, uOptions, function(result) {
parseJsonCallback(result, resolve);
}, function(result) {
parseJsonCallback(result, reject);
}, progress);
});
},
registerByFullName: function(swPkgFullName, uOptions) {
return new Promise(function(resolve, reject, progress) {
mgr.registerPackageByFullName(swPkgFullName, uOptions, function(result) {
parseJsonCallback(result, resolve);
}, function(result) {
parseJsonCallback(result, reject);
}, progress);
});
},
setStatus: function(swPkgFullName, uStatus) {
mgr.setPackageStatus(swPkgFullName, uStatus);
},
stage: function(swPkgPath, uOptions) {
return new Promise(function(resolve, reject, progress) {
mgr.stagePackage(swPkgPath, uOptions, function(result) {
parseJsonCallback(result, resolve);
}, function(result) {
parseJsonCallback(result, reject);
}, progress);
});
},
stageUserData: function(swPkgFullName) {
return new Promise(function(resolve, reject, progress) {
mgr.stagePackageUserData(swPkgFullName, function(result) {
parseJsonCallback(result, resolve);
}, function(result) {
parseJsonCallback(result, reject);
}, progress);
});
},
update: function(swPkgPath, uOptions) {
return new Promise(function(resolve, reject, progress) {
mgr.updatePackage(swPkgPath, uOptions, function(result) {
parseJsonCallback(result, resolve);
}, function(result) {
parseJsonCallback(result, reject);
}, progress);
});
},
findByIdentity: function(swIdName, swIdPublisher) {
return new Promise(function(resolve, reject) {
mgr.findPackageByIdentity(swIdName, swIdPublisher, function(result) {
parseJsonCallback(result, resolve);
}, function(result) {
parseJsonCallback(result, reject);
});
});
},
findByFamilyName: function(swFamilyName) {
return new Promise(function(resolve, reject) {
mgr.findPackageByFamilyName(swFamilyName, function(result) {
parseJsonCallback(result, resolve);
}, function(result) {
parseJsonCallback(result, reject);
});
});
},
findByFullName: function(swPkgFullName) {
return new Promise(function(resolve, reject) {
mgr.findPackageByFullName(swPkgFullName, function(result) {
parseJsonCallback(result, resolve);
}, function(result) {
parseJsonCallback(result, reject);
});
});
},
},
};
})(this);

View File

@@ -380,4 +380,153 @@ function messageBoxAsync(swText, swTitle, uType, swColor, pfCallback) {
if (reject) reject(ex);
}
});
}
function MessageBoxButton(swDisplayName, nValueReturn) {
this.displayName = swDisplayName;
this.value = nValueReturn;
}
function messageBoxAdvance(swText, swCaption, aCommands, swColor, pfCallback) {
var _lpText = swText;
var _lpCaption = swCaption;
var msgbox = document.createElement("div");
msgbox.classList.add("notice-back");
msgbox.classList.add("win-ui-dark");
var uniqueId = "msgbox_" + new Date().getTime();
msgbox.id = uniqueId;
var msgbody = document.createElement("div");
msgbody.classList.add("notice-body");
if (!IsBlackLabel(swColor)) {
msgbody.style.backgroundColor = swColor;
}
msgbox.appendChild(msgbody);
var msgcontainter = document.createElement("div");
msgcontainter.style.height = "100%";
msgcontainter.style.width = "100%";
msgcontainter.style.maxHeight = "100%";
msgcontainter.style.minHeight = "0px";
msgcontainter.style.boxSizing = "border-box";
msgbody.appendChild(msgcontainter);
var msgcaption = document.createElement("div");
msgcontainter.appendChild(msgcaption);
msgcontainter.style.display = "flex";
msgcontainter.style.flexDirection = "column";
var msgcontent = document.createElement("div");
msgcontent.style.flex = "1 1 auto";
msgcontent.style.marginRight = "3px";
msgcontent.style.overflowX = "hidden";
msgcontent.style.overflowY = "auto";
msgcontent.style.minHeight = "0px";
msgcontainter.appendChild(msgcontent);
if (_lpCaption instanceof HTMLElement) {
msgcaption.appendChild(_lpCaption);
msgcaption.classList.add("notice-title");
} else {
if (!IsBlackLabel(_lpCaption)) {
var msgtitle = document.createElement("h2");
msgtitle.textContent = _lpCaption;
msgtitle.classList.add("notice-title");
msgcaption.appendChild(msgtitle);
} else {
var msgtitle = document.createElement("h2");
msgtitle.textContent = "";
msgtitle.classList.add("notice-title");
msgcaption.appendChild(msgtitle);
}
}
if (_lpText instanceof HTMLElement || _lpText instanceof HTMLDivElement || typeof _lpText !== "string") {
try {
_lpText.classList.add("notice-text");
msgcontent.appendChild(_lpText);
} catch (e) {
if (!IsBlackLabel(_lpText)) {
var msgtext = document.createElement("p");
msgtext.textContent = _lpText;
msgtext.classList.add("notice-text");
if (IsBlackLabel(_lpCaption)) {
msgtext.style.marginTop = "0";
}
msgcontent.appendChild(msgtext);
} else {
var msgtext = document.createElement("p");
msgtext.innerText = "";
msgtext.classList.add("notice-text");
if (IsBlackLabel(_lpCaption)) {
msgtext.style.marginTop = "0";
}
msgcontent.appendChild(msgtext);
}
}
} else {
if (!IsBlackLabel(_lpText)) {
var msgtext = document.createElement("p");
msgtext.textContent = _lpText;
msgtext.classList.add("notice-text");
if (IsBlackLabel(_lpCaption)) {
msgtext.style.marginTop = "0";
}
msgcontent.appendChild(msgtext);
} else {
var msgtext = document.createElement("p");
msgtext.innerText = "";
msgtext.classList.add("notice-text");
if (IsBlackLabel(_lpCaption)) {
msgtext.style.marginTop = "0";
}
msgcontent.appendChild(msgtext);
}
}
var msgctrls = document.createElement("div");
msgctrls.classList.add("notice-controls");
msgcontainter.appendChild(msgctrls);
if (aCommands.length <= 0) {
aCommands.push(new MessageBoxButton(GetLocaleStringFromResId(800) || "OK", MBRET.IDOK));
}
for (var i = 0; i < aCommands.length; i++) {
var cmd = aCommands[i];
var btn = document.createElement("button");
btn.textContent = cmd.displayName;
btn.setAttribute("data-msgbox-value", cmd.value);
Windows.UI.Event.Util.addEvent(btn, "click", function(event) {
var btns = this.parentNode.querySelectorAll("button");
var lastbtnstatus = [];
for (var j = 0; j < btns.length; j++) {
lastbtnstatus.push(btns[j].disabled);
btns[j].disabled = true;
}
try {
pfCallback(this.getAttribute("data-msgbox-value"));
} catch (e) {}
msgbox.style.opacity = 0;
setTimeout(function(nodes, laststatus) {
for (var k = 0; k < nodes.length; k++) {
nodes[k].disabled = laststatus[k];
}
document.body.removeChild(msgbox);
}, 500, btns, lastbtnstatus);
});
msgctrls.appendChild(btn);
}
document.body.appendChild(msgbox);
setTimeout(function() {
msgbox.style.opacity = 1;
}, 1);
return msgbox.id;
}
function messageBoxAdvanceAsync(swText, swCaption, aCommands, swColor) {
if (typeof Promise === "undefined") {
console.error("Promise is not supported in this environment.");
messageBoxAdvance(swText, swCaption, aCommands, swColor);
}
return new Promise(function(resolve, reject) {
try {
messageBoxAdvance(swText, swCaption, aCommands, swColor, function(valueReturn) {
if (resolve) resolve(valueReturn);
});
} catch (ex) {
if (reject) reject(ex);
}
});
}

View File

@@ -8,6 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="js/module.js"></script>
<script type="text/javascript" src="js/polyfill-ie.js"></script>
<link rel="stylesheet" href="libs/winjs/1.0/css/ui-light.css" id="winjs-style-1">
<link rel="stylesheet" href="libs/winjs/2.0/css/ui-light.css" id="winjs-style">
<script type="text/javascript" src="libs/winjs/1.0/js/base.js"></script>
<script type="text/javascript" src="libs/winjs/1.0/js/ui.js"></script>
@@ -21,38 +22,77 @@
<link rel="stylesheet" href="fonts/segx.css">
<link rel="stylesheet" href="manager/page.css">
<link rel="stylesheet" href="manager/appitem.css">
<link rel="stylesheet" href="manager/appbar.css">
<script type="text/javascript" src="js/event.js"></script>
<script type="text/javascript" src="js/tileback.js"></script>
<script type="text/javascript" src="js/load.js"></script>
<link rel="stylesheet" type="text/css" href="libs/msgbox/msgbox.css">
<script type="text/javascript" src="libs/msgbox/msgbox.js"></script>
<script type="text/javascript" src="js/init.js"></script>
<script type="text/javascript" src="js/pkginfo.js"></script>
<script type="text/javascript" src="js/datasrc.js"></script>
<script type="text/javascript" src="js/appbar.js"></script>
<script type="text/javascript" src="js/pagemgr.js"></script>
<script type="text/javascript" src="js/manager/pages.js"></script>
<script type="text/javascript" src="js/mgrinit.js"></script>
</head>
<body>
<div id="settingpage" class="pagecontainer full">
<div id="managerpage" class="pagecontainer full">
<div class="page full guide fold">
<main class="main padding">
<div id="page-manager">
<div id="page-manager" style="display: none;" class="ispage">
<h2>应用</h2>
<p>在这里,可以对安装的 Windows 商店应用进行管理。</p>
<h3>安装的应用</h3>
<template id="appitem-template">
</template>
<div class="appitem selected">
<div role="img">
<img width="24" height="24" src="images/applogo.default.png" />
<br>
<div class="app-loading" id="applist-loading" style="display: none;">
<progress class="win-ring"></progress>
<span class="win-label title">正在加载应用...</span>
<br>
</div>
<div class="appitem" id="appitem-template" style="display: none;">
<div role="img" style="pointer-events: none;">
<img width="" height="" src="images/applogo.default.png" />
</div>
<div role="divide"></div>
<div role="divide" style="pointer-events: none;"></div>
<div role="excepticon">
<div role="title" class="win-type-x-small"><span>App Name</span></div>
<div role="control"><button>卸载</button></div>
<div role="title" class="win-type-x-small" style="pointer-events: none;">
<span class="displayName">App Name</span><br>
<span class="publisher">Publisher</span>
</div>
<div role="advance">
<a>高级选项</a>
</div>
<div role="control">
<button name="uninstall">卸载</button>
</div>
</div>
</div>
<ul>
<li></li>
</ul>
<div id="applist" class="appitem-list" style="width: 100%; height: auto;">
</div>
<div class="bottom-compensate"></div>
</div>
<div id="page-appinfo" class="ispage app-detailpage">
<header>
<button class="win-backbutton"></button>
<h2 class="display-name">App DisplayName</h2>
</header>
<span class="publisher-display-name">App PublisherDisplayName</span><br>
<span class="version">App Version</span><br>
<span class="description">App Description</span>
<p><strong>应用身份</strong></p>
<div class="identity win-type-body" style="width: 100%; max-width: 100%; box-sizing: border-box; -ms-user-select: element;">
<span style="font-weight: bold;">名称</span><span>: </span><span class="name"></span><br>
<span style="font-weight: bold;">发布者</span><span>: </span><span class="publisher"></span><br>
<span style="font-weight: bold;">发布者 ID</span><span>: </span><span class="publisher-id"></span><br>
<span style="font-weight: bold;">系列名</span><span>: </span><span class="family-name"></span><br>
<span style="font-weight: bold;">全名</span><span>: </span><span class="full-name"></span><br>
<span style="font-weight: bold;">支持的处理器架构</span><span>: </span><span class="architecture"></span><br>
</div>
<p><strong>卸载</strong></p>
<p>卸载此应用及其设置。</p>
<button id="detail-uninstall-btn" data-app-fullname="">卸载</button>
</div>
</main>
<aside class="win-ui-dark">
@@ -75,10 +115,14 @@
</ul>
<hr>
<ul class="list">
<li>
<li id="tag-manager">
<div role="img">&#57587;</div>
<span class="win-type-base">管理</span>
</li>
<li id="tag-appinfo" class="subitem">
<div role="img">&#57650;</div>
<span class="win-type-base">应用信息</span>
</li>
<li>
<div role="img">&#57587;</div>
<span class="win-type-base">Manager</span>
@@ -88,6 +132,8 @@
</aside>
</div>
</div>
<div class="win-overlay win-commandlayout win-appbar win-bottom appbar win-ui-dark" id="appBar" role="menubar">
</div>
</body>
</html>

View File

@@ -0,0 +1,49 @@
.win-bottom {
position: absolute;
bottom: 0;
top: auto;
left: 0;
right: 0;
}
.appbar {
-ms-transform: translateY(100%);
transform: translateY(100%);
transition: all 0.5s cubic-bezier(0.1, 0.9, 0.2, 1);
}
.appbar.show {
-ms-transform: translateY(0);
transform: translateY(0);
}
.appbar.win-ui-dark .win-label {
color: white;
}
.appbar-touchhide {
background-color: transparent;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 88px;
}
.appbar button.win-command,
.win-appbar .win-commandlayout button.win-command {
box-sizing: border-box;
/* 含 padding/border 计算宽度 */
min-width: 100px;
/* 强制最小宽度 100px */
}
/* 同时覆盖在窄屏 media query 中的行为(确保在 @media (max-width:1023px) 之后或在文件末尾定义) */
@media (max-width: 1023px) {
.appbar button.win-command,
.win-appbar .win-commandlayout button.win-command {
min-width: 100px;
}
}

View File

@@ -2,7 +2,7 @@
padding: 10px;
box-sizing: border-box;
height: 60px;
width: 450px;
width: 460px;
max-width: 100%;
display: -ms-flexbox;
/* IE10 */
@@ -53,6 +53,14 @@
-ms-flex-line-pack: center;
/* IE10 -> align-content */
align-content: center;
overflow-x: hidden;
overflow-y: hidden;
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);
}
.appitem div[role=img] img {
width: 30px;
height: 30px;
}
.appitem div[role=divide] {
@@ -65,6 +73,23 @@
font-weight: normal;
flex: 1;
-ms-flex: 1;
width: 100%;
overflow-x: hidden;
overflow-y: hidden;
text-overflow: ellipsis;
}
.appitem div[role=excepticon] div[role=advance] {
display: none;
opacity: 0;
height: 0;
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);
}
.appitem.selected div[role=excepticon] div[role=advance] {
display: block;
opacity: 1;
height: auto;
}
.appitem div[role=excepticon] {
@@ -85,12 +110,12 @@
-ms-flex-pack: start;
/* IE10 -> justify-content */
justify-content: flex-start;
width: calc(100% - 40px - 10px);
}
.appitem div[role=excepticon] div[role=control] {
display: none;
/* IE10 */
display: flex;
-ms-flex-direction: row-reverse;
/* IE10 */
flex-direction: row-reverse;
@@ -106,13 +131,95 @@
-ms-flex-align: center;
/* IE10 -> align-items */
align-items: center;
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);
opacity: 0;
height: 0;
}
.appitem.selected {
height: 119px;
background-color: rgba(232, 232, 232, 1);
}
.appitem.selected div[role=excepticon] div[role=control] {
display: flex;
display: -ms-flexbox;
opacity: 1;
height: auto;
}
ul.appitem-list,
ul.appitem-list li {
margin: 0;
padding: 0;
list-style: none;
}
.appitem .displayName,
.appitem .publisher {
text-overflow: ellipsis;
overflow-x: hidden;
overflow-y: hidden;
white-space: nowrap;
max-width: 100%;
}
.appitem .publisher {
color: rgb(102, 102, 102);
}
.app-loading {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-content: center;
justify-content: flex-start;
align-items: center;
width: 100%;
height: auto;
}
.app-loading.noloading progress {
display: none;
}
.app-loading .title {
margin-left: 10px;
}
.app-loading.noloading .title {
margin-left: 0;
}
.app-detailpage header {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: flex-start;
justify-content: flex-start;
overflow-x: hidden;
overflow-y: hidden;
text-overflow: ellipsis;
width: 100%;
height: 67px;
box-sizing: border-box;
max-width: 100%;
}
.app-detailpage header .win-backbutton {
width: 35px;
height: 35px;
font-size: 11.9pt;
line-height: 32px;
min-width: 35px;
min-height: 35px;
}
.app-detailpage header .display-name {
padding-left: 10px;
box-sizing: border-box;
width: calc(100% - 35px - 10px);
overflow-y: hidden;
overflow-x: hidden;
text-overflow: ellipsis;
}

View File

@@ -168,6 +168,7 @@ aside>nav ul li {
.page.fold>aside>nav ul li {
padding: 0;
cursor: pointer;
}
aside>nav ul li div[role=img] {
@@ -189,6 +190,33 @@ aside>nav ul li div[role=img] {
text-align: center;
}
.page>aside>nav ul li.selected {
background-color: #159d9d;
}
.page>aside>nav ul li.selected:hover {
background-color: rgb(23, 187, 187);
}
.page>aside>nav ul li.selected:active {
background-color: rgb(29, 224, 224);
}
.page>aside>nav ul li.subitem {
opacity: 0;
height: 0;
min-height: 0;
}
.page>aside>nav ul li.subitem.selected {
opacity: 1;
height: 50px;
}
.page.fold>aside>nav ul li * {
pointer-events: none;
}
.page.fold>aside>nav ul li div[role=img] {
min-width: 90px;
width: 90px;
@@ -213,7 +241,8 @@ aside>nav ul li div[role=img] {
.page>aside>nav ul li div[role=img] {
font-size: 15pt;
margin-right: 5px;
margin-right: 10px;
width: 1em;
}
.page>aside>nav ul li.title div[role=img] {
@@ -256,7 +285,7 @@ aside>nav ul li div[role=img] {
.page.fold>aside>nav ul li:hover div[role=img] {
min-width: 0;
width: auto;
width: 1em;
}
.page.fold>aside>nav ul li:hover span {
@@ -292,6 +321,10 @@ aside>nav ul li div[role=img] {
overflow-y: visible;
}
.main {
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);
}
.main.padding {
padding: 44px 60px;
}
@@ -307,12 +340,18 @@ aside>nav ul li div[role=img] {
top: 0px;
left: 0px;
background-color: white;
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);
}
.section.padding {
padding: 44px 60px;
}
.section.padding .bottom-compensate {
.bottom-compensate {
padding-bottom: 44px;
}
.ispage {
opacity: 1;
transition: all 0.4s cubic-bezier(0.1, 0.9, 0.2, 1);
}