mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-06-14 03:16:38 +10:00
Update manager and add features for App Installer.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
.statusbar {
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.statusbar.x {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.statusbar.y {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.statusbar.both {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.statusbar.fast {
|
||||
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);
|
||||
}
|
||||
|
||||
.statusbar.medium {
|
||||
transition: all 0.5s cubic-bezier(0.1, 0.9, 0.2, 1);
|
||||
}
|
||||
|
||||
.statusbar.slow {
|
||||
transition: all 0.7s cubic-bezier(0.1, 0.9, 0.2, 1);
|
||||
}
|
||||
@@ -312,9 +312,15 @@
|
||||
function hideTouchHide() {
|
||||
touchHide.style.display = "none";
|
||||
}
|
||||
var timerHide = null;
|
||||
this.show = function() {
|
||||
try {
|
||||
if (!_enable) return;
|
||||
if (timerHide) {
|
||||
clearTimeout(timerHide);
|
||||
timerHide = null;
|
||||
}
|
||||
this.element.style.display = "";
|
||||
if (!this.element.classList.contains("show"))
|
||||
this.element.classList.add("show");
|
||||
waitTimer(500);
|
||||
@@ -323,8 +329,16 @@
|
||||
};
|
||||
this.hide = function() {
|
||||
try {
|
||||
if (timerHide) {
|
||||
clearTimeout(timerHide);
|
||||
timerHide = null;
|
||||
}
|
||||
if (this.element.classList.contains("show"))
|
||||
this.element.classList.remove("show");
|
||||
timerHide = setTimeout(function() {
|
||||
timerHide = null;
|
||||
self.element.style.display = "none";
|
||||
}, 500);
|
||||
waitTimer(500);
|
||||
hideTouchHide();
|
||||
} catch (e) {}
|
||||
|
||||
@@ -102,4 +102,20 @@
|
||||
get: function() { return ext.System.UI.SplashImage; },
|
||||
});
|
||||
} catch (e) {}
|
||||
// 下面是有关 String 方法的补充
|
||||
if (typeof String.prototype.trim !== "function") {
|
||||
String.prototype.trim = function() {
|
||||
return Bridge.String.trim(this);
|
||||
};
|
||||
}
|
||||
if (typeof String.prototype.toLowerCase !== "function") {
|
||||
String.prototype.toLowerCase = function() {
|
||||
return Bridge.String.tolower(this);
|
||||
};
|
||||
}
|
||||
if (typeof String.prototype.toUpperCase !== "function") {
|
||||
String.prototype.toUpperCase = function() {
|
||||
return Bridge.String.toupper(this);
|
||||
};
|
||||
}
|
||||
})(this);
|
||||
+357
-27
@@ -13,6 +13,7 @@
|
||||
var childAnimeDuration = 120;
|
||||
var parentAnimeDuration = 400;
|
||||
|
||||
|
||||
function showItemAmine(node) {
|
||||
return Windows.UI.Animation.runAsync(node, [
|
||||
Windows.UI.Animation.Keyframes.Scale.up,
|
||||
@@ -27,6 +28,23 @@
|
||||
], childAnimeDuration);
|
||||
}
|
||||
|
||||
function noAnime(node) {
|
||||
return Promise.resolve(node);
|
||||
}
|
||||
|
||||
function runShowAnime(node, enable) {
|
||||
if (enable === void 0) enable = true;
|
||||
if (!enable) return noAnime(node);
|
||||
return showItemAmine(node);
|
||||
}
|
||||
|
||||
function runHideAnime(node, enable) {
|
||||
if (enable === void 0) enable = true;
|
||||
if (!enable) return noAnime(node);
|
||||
return hideItemAmine(node);
|
||||
}
|
||||
|
||||
|
||||
function updateItemAmine(node, updateCallback) {
|
||||
return Windows.UI.Animation.runAsync(node, [
|
||||
Windows.UI.Animation.Keyframes.Opacity.hidden,
|
||||
@@ -53,6 +71,43 @@
|
||||
function PMDataSource() {
|
||||
var _list = [];
|
||||
var _listeners = [];
|
||||
|
||||
var _keySelector = null;
|
||||
var _autoKeySeed = 1;
|
||||
this.setKeySelector = function(fn) {
|
||||
_keySelector = (typeof fn === "function") ? fn : null;
|
||||
};
|
||||
|
||||
function getKey(item) {
|
||||
if (!item) return null;
|
||||
|
||||
// 用户提供
|
||||
if (_keySelector) {
|
||||
return _keySelector(item);
|
||||
}
|
||||
|
||||
// 自动注入(对象)
|
||||
if (typeof item === "object") {
|
||||
if (item.__pm_key !== void 0) {
|
||||
return item.__pm_key;
|
||||
}
|
||||
|
||||
try {
|
||||
Object.defineProperty(item, "__pm_key", {
|
||||
value: "pm_" + (_autoKeySeed++),
|
||||
enumerable: false
|
||||
});
|
||||
} catch (e) {
|
||||
// IE10 兜底
|
||||
item.__pm_key = "pm_" + (_autoKeySeed++);
|
||||
}
|
||||
return item.__pm_key;
|
||||
}
|
||||
|
||||
// 原始类型兜底
|
||||
return typeof item + ":" + item;
|
||||
}
|
||||
|
||||
this.subscribe = function(fn) {
|
||||
if (typeof fn === "function") {
|
||||
_listeners.push(fn);
|
||||
@@ -64,26 +119,47 @@
|
||||
_listeners[i](evt);
|
||||
}
|
||||
}
|
||||
this.indexOf = function(item) {
|
||||
var key = getKey(item);
|
||||
for (var i = 0; i < _list.length; i++) {
|
||||
if (getKey(_list[i]) === key) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
this.add = function(item) {
|
||||
_list.push(item);
|
||||
emit(new PMChangeEvent(
|
||||
DataView.ChangeType.add, [item], { index: _list.length - 1 }
|
||||
DataView.ChangeType.add, [{ item: item, index: _list.length - 1, key: getKey(item) }]
|
||||
));
|
||||
};
|
||||
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 }
|
||||
DataView.ChangeType.remove, [{ item: item, index: index, key: getKey(item) }]
|
||||
));
|
||||
};
|
||||
this.remove = function(item) {
|
||||
var index = this.indexOf(item);
|
||||
if (index >= 0) {
|
||||
this.removeAt(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 }
|
||||
DataView.ChangeType.change, [{ item: newItem, index: index, key: getKey(newItem) }]
|
||||
));
|
||||
};
|
||||
this.change = function(oldItem, newItem) {
|
||||
var index = this.indexOf(oldItem);
|
||||
if (index >= 0) {
|
||||
this.changeAt(index, newItem);
|
||||
}
|
||||
};
|
||||
this.clear = function() {
|
||||
_list.length = 0;
|
||||
emit(new PMChangeEvent(
|
||||
@@ -224,7 +300,6 @@
|
||||
var changed = [];
|
||||
var removed = [];
|
||||
|
||||
// 1️⃣ 找 remove
|
||||
for (i = oldList.length - 1; i >= 0; i--) {
|
||||
var oldItem = oldList[i];
|
||||
var oldKey = getKey(oldItem);
|
||||
@@ -238,7 +313,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 2️⃣ 找 add / change
|
||||
for (i = 0; i < newList.length; i++) {
|
||||
var newItem = newList[i];
|
||||
var newKey = getKey(newItem);
|
||||
@@ -263,7 +337,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 3️⃣ 执行 remove(从后往前)
|
||||
if (removed.length > 0) {
|
||||
for (i = 0; i < removed.length; i++) {
|
||||
_list.splice(removed[i].index, 1);
|
||||
@@ -274,7 +347,6 @@
|
||||
));
|
||||
}
|
||||
|
||||
// 4️⃣ 执行 add / change(重建顺序)
|
||||
_list = newList.slice(0);
|
||||
|
||||
if (added.length > 0) {
|
||||
@@ -291,25 +363,50 @@
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
this._getKey = getKey;
|
||||
}
|
||||
var MAX_ANIMATE_COUNT = 100;
|
||||
|
||||
function PMDataListView(container, templateFn) {
|
||||
this.container = container;
|
||||
this.templateFn = templateFn;
|
||||
this.listViewControl = this;
|
||||
this._emptyView = null;
|
||||
// === 新增 ===
|
||||
this._filter = null;
|
||||
|
||||
this._searchHandler = null;
|
||||
this._searchText = null;
|
||||
this._searchSuggestProvider = null;
|
||||
|
||||
this.onSearchSuggest = null; // function(text, list)
|
||||
this._isSearching = false;
|
||||
this.onsearchstart = null;
|
||||
this.onsearchend = null;
|
||||
}
|
||||
PMDataListView.prototype.bind = function(ds) {
|
||||
var self = this;
|
||||
var items = ds.get();
|
||||
this._ds = ds;
|
||||
|
||||
self.container.innerHTML = "";
|
||||
|
||||
var items = ds.get();
|
||||
|
||||
// 动画队列,保证异步操作不会乱序
|
||||
var queue = Promise.resolve();
|
||||
|
||||
function renderItem(data, index) {
|
||||
var el = self.templateFn(data, index);
|
||||
|
||||
var key = ds && ds._getKey ? ds._getKey(data) : null;
|
||||
|
||||
el.__pm_item = data;
|
||||
el.__pm_key = key;
|
||||
|
||||
if (key != null) {
|
||||
el.setAttribute("data-pm-key", key);
|
||||
}
|
||||
|
||||
el.addEventListener("click", function() {
|
||||
self._toggleSelect(el);
|
||||
});
|
||||
@@ -317,10 +414,13 @@
|
||||
return el;
|
||||
}
|
||||
|
||||
|
||||
// 初始化渲染
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
self.container.appendChild(renderItem(items[i], i));
|
||||
}
|
||||
// 初始化 emptyView 状态
|
||||
self._updateEmptyView();
|
||||
|
||||
ds.subscribe(function(evt) {
|
||||
|
||||
@@ -337,37 +437,58 @@
|
||||
var nodes = [];
|
||||
for (var i = 0; i < datas.length; i++) {
|
||||
var n = renderItem(datas[i].item, datas[i].index);
|
||||
n.style.display = "none";
|
||||
nodes.push(n);
|
||||
self.container.appendChild(n);
|
||||
}
|
||||
|
||||
// 如果数量>=20,动画并行,否则串行
|
||||
if (datas.length >= 20) {
|
||||
var enableAnime = datas.length <= MAX_ANIMATE_COUNT;
|
||||
if (!enableAnime) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
// 如果数量>=20,动画串行,否则并行
|
||||
if (datas.length <= 20) {
|
||||
var promises = [];
|
||||
for (var j = 0; j < nodes.length; j++) {
|
||||
promises.push(showItemAmine(nodes[j]));
|
||||
promises.push((function(node) {
|
||||
node.style.display = "";
|
||||
return showItemAmine(node);
|
||||
})(nodes[j]));
|
||||
}
|
||||
return Promise.all(promises);
|
||||
} else {
|
||||
// 串行
|
||||
var p = Promise.resolve();
|
||||
var group = [];
|
||||
for (var k = 0; k < nodes.length; k++) {
|
||||
(function(node) {
|
||||
p = p.then(function() {
|
||||
group.push((function(node) {
|
||||
node.style.display = "";
|
||||
return showItemAmine(node);
|
||||
});
|
||||
})(nodes[k]);
|
||||
})
|
||||
(nodes[k]));
|
||||
if (group.length === 20 || k === nodes.length - 1) {
|
||||
(function(g) {
|
||||
p = p.then(function() {
|
||||
return Promise.join(g);
|
||||
});
|
||||
})(group);
|
||||
group = [];
|
||||
}
|
||||
}
|
||||
(function(g) {
|
||||
p = p.then(function() {
|
||||
return Promise.join(g);
|
||||
});
|
||||
})(group);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
case DataView.ChangeType.remove:
|
||||
{
|
||||
var node = self.container.children[evt.detail.index];
|
||||
var info = evt.datas[0];
|
||||
var node = self._findNodeByKey(info.key);
|
||||
if (!node) return;
|
||||
|
||||
// 隐藏动画完成后再移除
|
||||
return hideItemAmine(node).then(function() {
|
||||
self.container.removeChild(node);
|
||||
});
|
||||
@@ -375,29 +496,30 @@
|
||||
|
||||
case DataView.ChangeType.change:
|
||||
{
|
||||
var oldNode = self.container.children[evt.detail.index];
|
||||
var info = evt.datas[0];
|
||||
var oldNode = self._findNodeByKey(info.key);
|
||||
if (!oldNode) return;
|
||||
|
||||
// 先淡出旧节点
|
||||
return hideItemAmine(oldNode).then(function() {
|
||||
// 替换节点
|
||||
var newNode = renderItem(evt.datas[0], evt.detail.index);
|
||||
var newNode = renderItem(info.item);
|
||||
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 info = evt.datas[0];
|
||||
var node = self._findNodeByKey(info.key);
|
||||
if (!node) return;
|
||||
|
||||
var ref = self.container.children[evt.detail.to] || null;
|
||||
if (node) self.container.insertBefore(node, ref);
|
||||
self.container.insertBefore(node, ref);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@@ -410,9 +532,22 @@
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
promises.push(self._refreshVisibility());
|
||||
return Promise.join(promises);
|
||||
});
|
||||
});
|
||||
};
|
||||
PMDataListView.prototype._findNodeByKey = function(key) {
|
||||
if (key == null) return null;
|
||||
|
||||
var children = this.container.children;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
if (children[i].__pm_key === key) {
|
||||
return children[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
PMDataListView.prototype._toggleSelect = function(ele) {
|
||||
// 如果选择模式为 none,则不处理
|
||||
@@ -472,7 +607,202 @@
|
||||
return Array.prototype.slice.call(this.container.querySelectorAll(".selected"));
|
||||
}
|
||||
});
|
||||
PMDataListView.prototype._updateEmptyView = function() {
|
||||
if (!this._emptyView) return;
|
||||
|
||||
// container 中是否还有 item
|
||||
var hasItem = this.container.children.length > 0;
|
||||
|
||||
if (hasItem) {
|
||||
if (this._emptyView.parentNode) {
|
||||
this._emptyView.style.display = "none";
|
||||
}
|
||||
} else {
|
||||
if (!this._emptyView.parentNode) {
|
||||
this.container.appendChild(this._emptyView);
|
||||
}
|
||||
this._emptyView.style.display = "";
|
||||
}
|
||||
};
|
||||
Object.defineProperty(PMDataListView.prototype, "emptyView", {
|
||||
get: function() {
|
||||
return this._emptyView;
|
||||
},
|
||||
set: function(value) {
|
||||
// 只接受 HTMLElement 或 null / undefined
|
||||
if (value !== null && value !== void 0 && !(value instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 移除旧的
|
||||
if (this._emptyView && this._emptyView.parentNode) {
|
||||
this._emptyView.parentNode.removeChild(this._emptyView);
|
||||
}
|
||||
|
||||
this._emptyView = value || null;
|
||||
|
||||
// 设置后立刻刷新一次
|
||||
this._updateEmptyView();
|
||||
}
|
||||
});
|
||||
PMDataListView.prototype._isItemVisible = function(item) {
|
||||
// 1️⃣ filter
|
||||
if (this._filter) {
|
||||
if (!this._filter(item)) return false;
|
||||
}
|
||||
|
||||
// 2️⃣ search(自动启用 / 禁用)
|
||||
var handler = this._searchHandler;
|
||||
var text = this._searchText;
|
||||
|
||||
if (typeof handler === "function") {
|
||||
if (text != null) {
|
||||
text = ("" + text).replace(/^\s+|\s+$/g, "");
|
||||
}
|
||||
|
||||
if (text && text.length > 0) {
|
||||
if (!handler(text, item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
PMDataListView.prototype._refreshVisibility = function() {
|
||||
var self = this;
|
||||
var children = self.container.children;
|
||||
var animes = [];
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
(function(node) {
|
||||
var item = node.__pm_item;
|
||||
if (!item) return;
|
||||
|
||||
var visible = self._isItemVisible(item);
|
||||
|
||||
var enableAnime = animes.length < MAX_ANIMATE_COUNT;
|
||||
if (visible) {
|
||||
if (node.style.display === "none") {
|
||||
node.style.display = "";
|
||||
animes.push(runShowAnime(node, enableAnime));
|
||||
}
|
||||
} else {
|
||||
if (node.style.display !== "none") {
|
||||
// 移除选择状态
|
||||
node.classList.remove("selected");
|
||||
animes.push(runHideAnime(node, enableAnime).then(function() {
|
||||
node.style.display = "none";
|
||||
}));
|
||||
}
|
||||
}
|
||||
})(children[i]);
|
||||
}
|
||||
return Promise.join(animes);
|
||||
};
|
||||
Object.defineProperty(PMDataListView.prototype, "filter", {
|
||||
get: function() {
|
||||
return this._filter;
|
||||
},
|
||||
set: function(fn) {
|
||||
this._filter = (typeof fn === "function") ? fn : null;
|
||||
this._refreshVisibility();
|
||||
}
|
||||
});
|
||||
Object.defineProperty(PMDataListView.prototype, "searchHandler", {
|
||||
get: function() {
|
||||
return this._searchHandler;
|
||||
},
|
||||
set: function(fn) {
|
||||
this._searchHandler = (typeof fn === "function") ? fn : null;
|
||||
this._refreshVisibility();
|
||||
}
|
||||
});
|
||||
Object.defineProperty(PMDataListView.prototype, "searchText", {
|
||||
get: function() {
|
||||
return this._searchText;
|
||||
},
|
||||
set: function(text) {
|
||||
var oldText = this._searchText;
|
||||
|
||||
this._searchText = text;
|
||||
|
||||
var oldActive = !!(oldText && oldText.trim());
|
||||
var newActive = !!(text && ("" + text).trim());
|
||||
|
||||
//if (!oldActive && newActive) {
|
||||
this._isSearching = true;
|
||||
this._emitSearchEvent("searchstart");
|
||||
//}
|
||||
|
||||
var handler = this._searchHandler;
|
||||
var provider = this._searchSuggestProvider;
|
||||
var cb = this.onSearchSuggest;
|
||||
|
||||
var t = text;
|
||||
if (t != null) {
|
||||
t = ("" + t).replace(/^\s+|\s+$/g, "");
|
||||
}
|
||||
|
||||
// 搜索建议
|
||||
if (
|
||||
typeof handler === "function" &&
|
||||
t &&
|
||||
t.length > 0 &&
|
||||
typeof provider === "function" &&
|
||||
typeof cb === "function"
|
||||
) {
|
||||
var list = provider(t);
|
||||
if (list && list.length) {
|
||||
cb(t, list.slice(0, 10));
|
||||
}
|
||||
}
|
||||
var self = this;
|
||||
var func = function() {
|
||||
//if (oldActive && !newActive) {
|
||||
self._isSearching = false;
|
||||
self._emitSearchEvent("searchend");
|
||||
//}
|
||||
};
|
||||
this._refreshVisibility().done(func, func);
|
||||
}
|
||||
});
|
||||
Object.defineProperty(PMDataListView.prototype, "searchSuggestProvider", {
|
||||
get: function() {
|
||||
return this._searchSuggestProvider;
|
||||
},
|
||||
set: function(fn) {
|
||||
this._searchSuggestProvider = (typeof fn === "function") ? fn : null;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(PMDataListView.prototype, "findItemLength", {
|
||||
get: function() {
|
||||
var count = 0;
|
||||
var children = this.container.children;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var item = children[i].__pm_item;
|
||||
if (this._isItemVisible(item)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
});
|
||||
PMDataListView.prototype._emitSearchEvent = function(type) {
|
||||
if (typeof this["on" + type] === "function") {
|
||||
try {
|
||||
this["on" + type].call(this);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
try {
|
||||
var ev = document.createEvent("Event");
|
||||
ev.initEvent(type, true, true);
|
||||
this.container.dispatchEvent(ev);
|
||||
} catch (e) {}
|
||||
};
|
||||
PMDataListView.prototype.refresh = function() {
|
||||
this._refreshVisibility();
|
||||
};
|
||||
global.DataView.ChangeEvent = PMChangeEvent;
|
||||
global.DataView.DataSource = PMDataSource;
|
||||
global.DataView.ListView = PMDataListView;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(function(global) {
|
||||
"use strict";
|
||||
var pkg_ns = external.Package;
|
||||
var strres = external.StringResources;
|
||||
|
||||
function archsToStr(archs) {
|
||||
var arr = [];
|
||||
@@ -28,9 +29,23 @@
|
||||
}
|
||||
return arr.join(", ");
|
||||
}
|
||||
var showAppDetailTimer = null;
|
||||
|
||||
function updateAppDataSource(page, result, bar) {
|
||||
try {
|
||||
var json = result.json;
|
||||
console.log(json);
|
||||
page.appDataSource.updateList(json.applications);
|
||||
} catch (e) {}
|
||||
showAppDetailTimer = setTimeout(function() {
|
||||
showAppDetailTimer = null;
|
||||
bar.hide();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
function setAppInfoPageContent(info) {
|
||||
var page = document.getElementById("page-appinfo");
|
||||
page.data = info;
|
||||
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;
|
||||
@@ -42,9 +57,72 @@
|
||||
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));
|
||||
try { page.appDataSource.clear(); } catch (e) {}
|
||||
var appLoading = page.querySelector("#appinfo-loading");
|
||||
appLoading.classList.remove("noloading");
|
||||
if (showAppDetailTimer) clearTimeout(showAppDetailTimer);
|
||||
if (typeof appLoading.bar === "undefined") {
|
||||
appLoading.bar = new TransitionPanel(appLoading, {
|
||||
axis: 'y',
|
||||
duration: 500,
|
||||
});
|
||||
}
|
||||
appLoading.bar.show();
|
||||
var appLoadingStatus = page.querySelector(".title");
|
||||
appLoadingStatus.textContent = strres.get("MANAGER_APP_INSTALLEDAPPS_LOADING");
|
||||
return Package.reader.readFromInstallLocation(il, true).then(
|
||||
function(result) {
|
||||
try {
|
||||
var displayNameNode = page.querySelector(".display-name");
|
||||
displayNameNode.textContent = displayNameNode.textContent || result.json.properties.display_name;
|
||||
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
|
||||
displayNameNode.textContent = "";
|
||||
}
|
||||
if (result.json.applications.length === 1) {
|
||||
displayNameNode.textContent = displayNameNode.textContent || result.json.applications[0].DisplayName || result.json.applications[0].ShortName;
|
||||
}
|
||||
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
|
||||
displayNameNode.textContent = "";
|
||||
}
|
||||
if (result.json.applications.length === 1) {
|
||||
displayNameNode.textContent = displayNameNode.textContent || result.json.applications[0].ShortName;
|
||||
}
|
||||
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
|
||||
displayNameNode.textContent = "";
|
||||
}
|
||||
displayNameNode.textContent = displayNameNode.textContent || info.Identity.FamilyName;
|
||||
} catch (e) {}
|
||||
appLoadingStatus.textContent = strres.get("MANAGER_APP_INSTALLEDAPPS_SUCCEED");
|
||||
appLoading.classList.add("noloading");
|
||||
updateAppDataSource(page, result, appLoading.bar);
|
||||
},
|
||||
function(result) {
|
||||
try {
|
||||
var displayNameNode = page.querySelector(".display-name");
|
||||
displayNameNode.textContent = displayNameNode.textContent || result.json.properties.display_name;
|
||||
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
|
||||
displayNameNode.textContent = "";
|
||||
}
|
||||
if (result.json.applications.length === 1) {
|
||||
displayNameNode.textContent = displayNameNode.textContent || result.json.applications[0].DisplayName || result.json.applications[0].ShortName;
|
||||
}
|
||||
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
|
||||
displayNameNode.textContent = "";
|
||||
}
|
||||
if (result.json.applications.length === 1) {
|
||||
displayNameNode.textContent = displayNameNode.textContent || result.json.applications[0].ShortName;
|
||||
}
|
||||
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
|
||||
displayNameNode.textContent = "";
|
||||
}
|
||||
displayNameNode.textContent = displayNameNode.textContent || info.Identity.FamilyName;
|
||||
} catch (e) {}
|
||||
var msg = result.message;
|
||||
appLoadingStatus.textContent = external.String.format(strres.get("MANAGER_APP_INSTALLEDAPPS_FAILED"), msg);
|
||||
appLoading.classList.add("noloading");
|
||||
updateAppDataSource(page, result, appLoading.bar);
|
||||
}
|
||||
);
|
||||
}
|
||||
global.setAppInfoPageContent = setAppInfoPageContent;
|
||||
})(this);
|
||||
+441
-420
@@ -1,369 +1,5 @@
|
||||
(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);
|
||||
}
|
||||
});
|
||||
}
|
||||
var strres = external.StringResources;
|
||||
|
||||
function createLocalizedCompare(locale) {
|
||||
return function(a, b) {
|
||||
@@ -383,9 +19,17 @@
|
||||
var mgr = Package.manager;
|
||||
var nstr = Bridge.NString;
|
||||
var datasrc = new DataView.DataSource();
|
||||
datasrc.setKeySelector(function(item) {
|
||||
if (item === null || item === void 0) return null;
|
||||
return Bridge.String.tolower(Bridge.String.trim(item.Identity.FullName));
|
||||
});
|
||||
var themeColor = Bridge.UI.themeColor;
|
||||
var loadingDisplay = document.getElementById("applist-loading");
|
||||
var loadingStatus = loadingDisplay.querySelector(".title");
|
||||
var emptyDisplay = document.createElement("div");
|
||||
var dataLengthDisplay = document.getElementById("applist-datalen");
|
||||
var appSearchList = document.getElementById("applist-search");
|
||||
emptyDisplay.textContent = strres.get("MANAGER_MANAGE_LISTEMPTY");
|
||||
var listView = new DataView.ListView(listContainer, function(item) {
|
||||
var appItem = appItemTemplate.cloneNode(true);
|
||||
appItem.id = "";
|
||||
@@ -407,17 +51,102 @@
|
||||
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);
|
||||
logoimg.parentElement.style.backgroundColor = item.BackgroundColor;
|
||||
if (item.BackgroundColor === "transparent") {
|
||||
logoimg.parentElement.style.backgroundColor = themeColor;
|
||||
}
|
||||
var uninstallButton = appItem.querySelector("div[role=control] .uninstall");
|
||||
Windows.UI.Event.Util.addEvent(uninstallButton, "click", function(e) {
|
||||
e.stopPropagation();
|
||||
this.disabled = true;
|
||||
var itemNode = this.parentNode.parentNode.parentNode;
|
||||
var flyout = document.getElementById("app-uninstall-flyout");
|
||||
if (typeof flyout.appDataSource !== "undefined") flyout.appDataSource.clear();
|
||||
if (typeof flyout.appDataSource !== "undefined") {
|
||||
Package.reader.readFromInstallLocation(this.parentNode.parentNode.parentNode.data.InstallLocation, true).then(function(result) {
|
||||
try {
|
||||
if (typeof result.json.applications === "undefined" || result.json.applications.length === 0) {
|
||||
result.json.applications = [{
|
||||
DisplayName: item.Properties.DisplayName || item.Identity.Name,
|
||||
SmallLogo_Base64: item.Properties.LogoBase64,
|
||||
}];
|
||||
}
|
||||
flyout.appDataSource.updateList(result.json.applications);
|
||||
|
||||
} catch (e) {}
|
||||
}, function(result) {
|
||||
try { flyout.appDataSource.updateList(result.json.applications); } catch (e) {}
|
||||
});
|
||||
}
|
||||
var self = this;
|
||||
var confirm = flyout.querySelector(".confirm");
|
||||
confirm.onclick = null;
|
||||
confirm.onclick = function() {
|
||||
self.disabled = true;
|
||||
flyout.winControl.hide();
|
||||
var fullName = itemNode.getAttribute("data-full-name");
|
||||
itemNode.classList.add("uninstalling");
|
||||
var progressPart = itemNode.querySelector("div[role=progress]");
|
||||
var statusDisplay = progressPart.querySelector(".status");
|
||||
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_ING");
|
||||
var progressDisplay = progressPart.querySelector(".progress");
|
||||
progressDisplay.removeAttribute("value");
|
||||
self.disabled = true;
|
||||
(function(itemNode, statusDisplay, progressDisplay, self) {
|
||||
mgr.remove(fullName).then(function(_s) {
|
||||
itemNode.classList.remove("uninstalling");
|
||||
itemNode.classList.add("uninstalled");
|
||||
if (_s.succeeded) {
|
||||
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_SUCCEED");
|
||||
datasrc.remove(itemNode.data);
|
||||
} else {
|
||||
statusDisplay.textContent = _s.message;
|
||||
setTimeout(function(iNode, uButton) {
|
||||
iNode.classList.remove("uninstalled");
|
||||
uButton.disabled = false;
|
||||
}, 5000, itemNode, self);
|
||||
}
|
||||
}, function(_f) {
|
||||
itemNode.classList.remove("uninstalling");
|
||||
itemNode.classList.add("uninstalled");
|
||||
try {
|
||||
if (_f.succeeded) {
|
||||
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_SUCCEED");
|
||||
datasrc.remove(itemNode.data);
|
||||
} else {
|
||||
statusDisplay.textContent = _f.message;
|
||||
setTimeout(function(iNode, uButton) {
|
||||
iNode.classList.remove("uninstalled");
|
||||
uButton.disabled = false;
|
||||
}, 5000, itemNode, self);
|
||||
}
|
||||
} catch (e) {
|
||||
statusDisplay.textContent = e.message;
|
||||
setTimeout(function(iNode, uButton) {
|
||||
iNode.classList.remove("uninstalled");
|
||||
uButton.disabled = false;
|
||||
}, 5000, itemNode, self);
|
||||
}
|
||||
self.disabled = false;
|
||||
}, function(_p) {
|
||||
statusDisplay.textContent = Bridge.String.format(
|
||||
strres.get("MANAGER_APP_UNINSTALL_PROGRESSING"),
|
||||
_p
|
||||
);
|
||||
progressDisplay.value = _p;
|
||||
});
|
||||
})(itemNode, statusDisplay, progressDisplay, self);
|
||||
};
|
||||
var winFlyout = flyout.winControl;
|
||||
if (winFlyout._beforehideHandler) {
|
||||
winFlyout.removeEventListener("beforehide", winFlyout._beforehideHandler);
|
||||
}
|
||||
winFlyout._beforehideHandler = function() {
|
||||
self.disabled = false;
|
||||
};
|
||||
winFlyout.addEventListener("beforehide", winFlyout._beforehideHandler);
|
||||
flyout.winControl.show(this);
|
||||
});
|
||||
Windows.UI.Event.Util.addEvent(appItem.querySelector("div[role=advance] a"), "click", function(e) {
|
||||
e.stopPropagation();
|
||||
try {
|
||||
@@ -428,93 +157,385 @@
|
||||
});
|
||||
listView.selectionMode = "single";
|
||||
listView.bind(datasrc);
|
||||
listView.emptyView = emptyDisplay;
|
||||
listView.searchHandler = function(text, item) {
|
||||
return ((item.Properties.DisplayName || item.Identity.Name || "") + (item.Properties.Publisher || "")).indexOf(text) >= 0;
|
||||
};
|
||||
appSearchList.control = new Search.Box(appSearchList, {
|
||||
placeholderText: strres.get("MANAGER_MANAGE_SEARCHPLACEHOLDER"),
|
||||
chooseSuggestionOnEnter: false
|
||||
});
|
||||
appSearchList.control.ontextchanged = function(ev) {
|
||||
console.log(ev.text);
|
||||
listView.searchText = ev.detail.text;
|
||||
};
|
||||
listView.onsearchend = function() {
|
||||
dataLengthDisplay.textContent = external.String.format(strres.get("MANAGER_MANAGE_FINDAPPS"), listView.findItemLength);
|
||||
};
|
||||
var timer = null;
|
||||
|
||||
function refreshAppList() {
|
||||
dataLengthDisplay.textContent = "";
|
||||
|
||||
function processData(manifest, dataitem) {
|
||||
//if (dataitem.Identity.FamilyName = "Microsoft.MicrosoftEdge.Stable_8wekyb3d8bbwe") debugger;
|
||||
dataitem.Properties.DisplayName = dataitem.Properties.DisplayName || manifest.properties.display_name || dataitem.Properties.DisplayName;
|
||||
if ((dataitem.Properties.DisplayName || "").indexOf("ms-resource:") === 0) {
|
||||
dataitem.Properties.DisplayName = "";
|
||||
}
|
||||
if (manifest.applications.length === 1) {
|
||||
dataitem.Properties.DisplayName = dataitem.Properties.DisplayName || manifest.applications[0].DisplayName || "";
|
||||
}
|
||||
if ((dataitem.Properties.DisplayName || "").indexOf("ms-resource:") === 0) {
|
||||
dataitem.Properties.DisplayName = "";
|
||||
}
|
||||
if (manifest.applications.length === 1) {
|
||||
dataitem.Properties.DisplayName = dataitem.Properties.DisplayName || manifest.applications[0].ShortName || "";
|
||||
}
|
||||
if ((dataitem.Properties.DisplayName || "").indexOf("ms-resource:") === 0) {
|
||||
dataitem.Properties.DisplayName = "";
|
||||
}
|
||||
dataitem.Properties.DisplayName = dataitem.Properties.DisplayName || dataitem.Identity.FamilyName;
|
||||
dataitem.Properties.Puvlisher = dataitem.Properties.Publisher || manifest.properties.publisher_display_name || dataitem.Properties.Publisher;
|
||||
dataitem.Properties.Framework = dataitem.Properties.Framework || manifest.properties.framework;
|
||||
dataitem.Properties.Logo = dataitem.Properties.Logo || manifest.properties.logo;
|
||||
dataitem.Properties.LogoBase64 = dataitem.Properties.LogoBase64 || manifest.properties.logo_base64;
|
||||
if (manifest.applications.length === 1) {
|
||||
dataitem.Properties.LogoBase64 = dataitem.Properties.LogoBase64 || manifest.applications[0].Square44x44Logo_Base64 || manifest.applications[0].SmallLogo_Base64;
|
||||
}
|
||||
dataitem.Properties.ResourcePackage = dataitem.Properties.ResourcePackage || manifest.properties.resource_package;
|
||||
dataitem.Properties.Description = dataitem.Properties.Description || manifest.properties.description;
|
||||
try {
|
||||
dataitem.BackgroundColor = manifest.applications[0].BackgroundColor || "transparent";
|
||||
} catch (e) {
|
||||
dataitem.BackgroundColor = "transparent";
|
||||
}
|
||||
return dataitem;
|
||||
}
|
||||
|
||||
function update(datas) {
|
||||
var newDatas = [];
|
||||
var promises = [];
|
||||
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 (external.System.isWindows10) {
|
||||
if (data.Properties.DisplayName === null || data.Properties.DisplayName === "" || data.Properties.DisplayName === void 0 ||
|
||||
data.Properties.LogoBase64 === null || data.Properties.LogoBase64 === "" || data.Properties.LogoBase64 === void 0
|
||||
) {
|
||||
promises.push(function(item, arr) {
|
||||
return Package.reader.readFromInstallLocation(item.InstallLocation, true).then(function(result) {
|
||||
try {
|
||||
arr.push(processData(result.json, item));
|
||||
} catch (e) {
|
||||
item.BackgroundColor = "transparent";
|
||||
arr.push(item);
|
||||
}
|
||||
}, function(result) {
|
||||
try {
|
||||
arr.push(processData(result.json, item));
|
||||
} catch (e) {
|
||||
item.BackgroundColor = "transparent";
|
||||
arr.push(item);
|
||||
}
|
||||
});
|
||||
}(data, newDatas));
|
||||
} else {
|
||||
promises.push(function(item, arr) {
|
||||
return Package.reader.readFromInstallLocation(item.InstallLocation, false).then(function(result) {
|
||||
try {
|
||||
item.BackgroundColor = result.json.applications[0].BackgroundColor;
|
||||
arr.push(item);
|
||||
} catch (e) {
|
||||
item.BackgroundColor = "transparent";
|
||||
arr.push(item);
|
||||
}
|
||||
}, function(result) {
|
||||
try {
|
||||
item.BackgroundColor = result.json.applications[0].BackgroundColor;
|
||||
arr.push(item);
|
||||
} catch (e) {
|
||||
item.BackgroundColor = "transparent";
|
||||
arr.push(item);
|
||||
}
|
||||
});
|
||||
}(data, newDatas));
|
||||
}
|
||||
} else {
|
||||
promises.push(function(item, arr) {
|
||||
return Package.reader.readFromInstallLocation(item.InstallLocation, true).then(function(result) {
|
||||
try {
|
||||
arr.push(processData(result.json, item));
|
||||
} catch (e) {
|
||||
item.BackgroundColor = "transparent";
|
||||
arr.push(item);
|
||||
}
|
||||
}, function(result) {
|
||||
try {
|
||||
arr.push(processData(result.json, item));
|
||||
} catch (e) {
|
||||
item.BackgroundColor = "transparent";
|
||||
arr.push(item);
|
||||
}
|
||||
});
|
||||
}(data, newDatas));
|
||||
}
|
||||
}
|
||||
|
||||
function updateDatas() {
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
if (isfind) continue;
|
||||
newDatas.push(data);
|
||||
datasrc.sort(function(a, b) {
|
||||
return compare(a.Properties.DisplayName, b.Properties.DisplayName);
|
||||
});
|
||||
dataLengthDisplay.textContent = external.String.format(strres.get("MANAGER_MANAGE_FINDAPPS"), listView.findItemLength);
|
||||
}
|
||||
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);
|
||||
});
|
||||
return Promise.join(promises).then(updateDatas, updateDatas);
|
||||
}
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = null;
|
||||
loadingDisplay.style.display = "";
|
||||
loadingDisplay.classList.remove("noloading");
|
||||
loadingDisplay.bar.show();
|
||||
|
||||
function waitAndHide() {
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = null;
|
||||
timer = setTimeout(function() {
|
||||
loadingDisplay.style.display = "none";
|
||||
}, 10000);
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = null;
|
||||
timer = setTimeout(function(rs, rj) {
|
||||
//loadingDisplay.style.display = "none";
|
||||
loadingDisplay.bar.hide();
|
||||
rs();
|
||||
}, 5000, resolve, reject);
|
||||
});
|
||||
}
|
||||
loadingStatus.textContent = "正在加载数据...";
|
||||
loadingStatus.textContent = strres.get("MANAGER_APP_INSTALLEDAPPS_LOADING");
|
||||
return mgr.get().then(function(result) {
|
||||
loadingDisplay.classList.add("noloading");
|
||||
loadingStatus.textContent = "已经加载了所有数据";
|
||||
update(result.list);
|
||||
waitAndHide();
|
||||
return update(result.list).then(function() {
|
||||
loadingDisplay.classList.add("noloading");
|
||||
loadingStatus.textContent = strres.get("MANAGER_APP_INSTALLEDAPPS_SUCCEED");
|
||||
setTimeout(function(lv) {
|
||||
lv.refresh();
|
||||
}, 500, listView);
|
||||
}).then(waitAndHide);
|
||||
}, function(error) {
|
||||
loadingDisplay.classList.add("noloading");
|
||||
loadingStatus.textContent = "更新时出错: " + (error.result ? (error.result.message || error.result.ErrorCode || "获取失败") : (error.message || error.error || error));
|
||||
var errmsg = (error.result ? (error.result.message || error.result.ErrorCode || "获取失败") : (error.message || error.error || error));
|
||||
loadingStatus.textContent = external.String.format(strres.get("MANAGER_APP_INSTALLEDAPPS_FAILED"), errmsg);
|
||||
try { update(error.list); } catch (e) {}
|
||||
waitAndHide();
|
||||
})
|
||||
setTimeout(function(lv) {
|
||||
lv.refresh();
|
||||
}, 500, listView);
|
||||
return waitAndHide();
|
||||
});
|
||||
}
|
||||
var appbar = document.getElementById("appBar");
|
||||
var appbarControl = new AppBar.AppBar(appbar);
|
||||
var refreshButton = new AppBar.Command();
|
||||
refreshButton.icon = "";
|
||||
refreshButton.label = "刷新";
|
||||
refreshButton.label = strres.get("MANAGER_APP_REFRESH");
|
||||
global.refreshAppList2 = function refreshAppList2() {
|
||||
appbarControl.hide();
|
||||
refreshButton.disabled = true;
|
||||
refreshAppList().done(function() {
|
||||
return refreshAppList().then(function() {
|
||||
refreshButton.disabled = false;
|
||||
}, function(error) {
|
||||
refreshButton.disabled = false;
|
||||
});
|
||||
}
|
||||
var showSystemApps = document.getElementById("applist-showsystemapp");
|
||||
var showFrameworks = document.getElementById("applist-showframework");
|
||||
listView.filter = function(item) {
|
||||
try {
|
||||
if (!showFrameworks.checked && item.Properties.Framework) return false;
|
||||
if (!showSystemApps.checked && item.Users.indexOf("NT AUTHORITY\\SYSTEM") !== -1) return false;
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Windows.UI.Event.Util.addEvent(showSystemApps, "change", function() {
|
||||
listView.refresh();
|
||||
dataLengthDisplay.textContent = external.String.format(strres.get("MANAGER_MANAGE_FINDAPPS"), listView.findItemLength);
|
||||
});
|
||||
Windows.UI.Event.Util.addEvent(showFrameworks, "change", function() {
|
||||
listView.refresh();
|
||||
dataLengthDisplay.textContent = external.String.format(strres.get("MANAGER_MANAGE_FINDAPPS"), listView.findItemLength);
|
||||
});
|
||||
refreshButton.addEventListener("click", refreshAppList2);
|
||||
appbarControl.add(refreshButton);
|
||||
refreshAppList2();
|
||||
var appDetailPage = document.getElementById("page-appinfo");
|
||||
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");
|
||||
var appinfoBackPage = appDetailPage.querySelector(".win-backbutton");
|
||||
Windows.UI.Event.Util.addEvent(appinfoBackPage, "click", function(e) {
|
||||
pagemgr.back();
|
||||
});
|
||||
appDetailPage.appDataSource = new DataView.DataSource();
|
||||
var appListView = new DataView.ListView(appDetailPage.querySelector(".apps"), function(item) {
|
||||
var appItem = appItemTemplate.cloneNode(true);
|
||||
appItem.id = "";
|
||||
appItem.style.display = "";
|
||||
var logoimg = appItem.querySelector("img");
|
||||
logoimg.src = item.Square44x44Logo_Base64 || item.SmallLogo_Base64;
|
||||
if (logoimg.src == "" || logoimg.src == null || logoimg.src == void 0) logoimg.removeAttribute("src");
|
||||
logoimg.parentElement.style.backgroundColor = item.BackgroundColor;
|
||||
if (Bridge.NString.equals(item.BackgroundColor, "transparent")) logoimg.parentElement.style.backgroundColor = themeColor;
|
||||
var appName = appItem.querySelector(".displayName");
|
||||
appName.textContent = item.DisplayName || item.ShortName;
|
||||
var appPub = appItem.querySelector(".publisher");
|
||||
appPub.style.display = "none";
|
||||
appItem.querySelector("div[role=advance]").style.display = "none";
|
||||
var ctrls = appItem.querySelector("div[role=control]");
|
||||
ctrls.innerHTML = "";
|
||||
appItem.data = item;
|
||||
var launchButton = document.createElement("button");
|
||||
launchButton.textContent = strres.get("MANAGER_APP_LAUNCH");
|
||||
launchButton.setAttribute("data-app-user-model-id", item.AppUserModelID);
|
||||
var createShortcutButton = document.createElement("button");
|
||||
createShortcutButton.textContent = strres.get("MANAGER_APP_CREATESHORTCUT");
|
||||
createShortcutButton.style.marginRight = "10px";
|
||||
Windows.UI.Event.Util.addEvent(launchButton, "click", function(e) {
|
||||
e.stopPropagation();
|
||||
Package.manager.active(this.getAttribute("data-app-user-model-id"));
|
||||
});
|
||||
ctrls.appendChild(launchButton);
|
||||
ctrls.appendChild(createShortcutButton);
|
||||
return appItem;
|
||||
});
|
||||
appListView.selectionMode = "single";
|
||||
appListView.bind(appDetailPage.appDataSource);
|
||||
appListView.emptyView = emptyDisplay.cloneNode(true);
|
||||
var appDetailUninstall = appDetailPage.querySelector("#detail-uninstall-btn");
|
||||
var appDetailUninstallStatusBlock = appDetailPage.querySelector("#appinfo-uninstallstatus");
|
||||
var appDetailUninstallProgress = appDetailUninstallStatusBlock.querySelector(".progress");
|
||||
var appDetailUninstallProgressStatus = appDetailUninstallStatusBlock.querySelector(".status");
|
||||
appDetailUninstallStatusBlock.bar = new TransitionPanel(appDetailUninstallStatusBlock, {
|
||||
axis: 'y',
|
||||
duration: 500,
|
||||
});
|
||||
Windows.UI.Event.Util.addEvent(appDetailUninstall, "click", function(e) {
|
||||
e.stopPropagation();
|
||||
appinfoBackPage.disabled = true;
|
||||
appDetailUninstallProgress.removeAttribute("value");
|
||||
var item = appDetailPage.data;
|
||||
var flyout = document.getElementById("app-uninstall-flyout");
|
||||
if (typeof flyout.appDataSource !== "undefined") flyout.appDataSource.clear();
|
||||
if (typeof flyout.appDataSource !== "undefined") {
|
||||
flyout.appDataSource.updateList(appDetailPage.appDataSource.get());
|
||||
}
|
||||
var self = this;
|
||||
var confirm = flyout.querySelector(".confirm");
|
||||
confirm.onclick = null;
|
||||
confirm.onclick = function() {
|
||||
self.disabled = true;
|
||||
flyout.winControl.hide();
|
||||
var fullName = item.Identity.FullName;
|
||||
var progressPart = appDetailUninstallStatusBlock;
|
||||
var statusDisplay = appDetailUninstallProgressStatus;
|
||||
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_ING");
|
||||
var progressDisplay = appDetailUninstallProgress;
|
||||
progressDisplay.style.display = "";
|
||||
self.disabled = true;
|
||||
progressPart.bar.show();
|
||||
(function(statusDisplay, progressDisplay, self, item) {
|
||||
mgr.remove(fullName).then(function(_s) {
|
||||
if (_s.succeeded) {
|
||||
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_SUCCEED");
|
||||
datasrc.remove(item);
|
||||
appinfoBackPage.disabled = false;
|
||||
} else {
|
||||
statusDisplay.textContent = _s.message;
|
||||
}
|
||||
setTimeout(function(uButton, isSuccess) {
|
||||
appinfoBackPage.disabled = false;
|
||||
uButton.disabled = isSuccess;
|
||||
progressPart.bar.hide();
|
||||
}, 5000, self, _s.succeeded);
|
||||
progressDisplay.style.display = "none";
|
||||
}, function(_f) {
|
||||
try {
|
||||
if (_f.succeeded) {
|
||||
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_SUCCEED");
|
||||
datasrc.remove(item);
|
||||
appinfoBackPage.disabled = false;
|
||||
} else {
|
||||
statusDisplay.textContent = _f.message;
|
||||
}
|
||||
setTimeout(function(uButton, isSuccess) {
|
||||
appinfoBackPage.disabled = false;
|
||||
uButton.disabled = isSuccess;
|
||||
progressPart.bar.hide();
|
||||
}, 5000, self, _f.succeeded);
|
||||
} catch (e) {
|
||||
statusDisplay.textContent = e.message;
|
||||
appinfoBackPage.disabled = false;
|
||||
setTimeout(function(uButton, isSuccess) {
|
||||
appinfoBackPage.disabled = false;
|
||||
uButton.disabled = isSuccess;
|
||||
progressPart.bar.hide();
|
||||
}, 5000, self, _f.succeeded);
|
||||
}
|
||||
self.disabled = false;
|
||||
progressDisplay.style.display = "none";
|
||||
}, function(_p) {
|
||||
statusDisplay.textContent = Bridge.String.format(
|
||||
strres.get("MANAGER_APP_UNINSTALL_PROGRESSING"),
|
||||
_p
|
||||
);
|
||||
progressDisplay.value = _p;
|
||||
});
|
||||
})(statusDisplay, progressDisplay, self, item);
|
||||
};
|
||||
var winFlyout = flyout.winControl;
|
||||
if (winFlyout._beforehideHandler) {
|
||||
winFlyout.removeEventListener("beforehide", winFlyout._beforehideHandler);
|
||||
}
|
||||
winFlyout._beforehideHandler = function() {
|
||||
self.disabled = false;
|
||||
};
|
||||
winFlyout.addEventListener("beforehide", winFlyout._beforehideHandler);
|
||||
flyout.winControl.show(this);
|
||||
});
|
||||
var uninstallFlyout = document.getElementById("app-uninstall-flyout");
|
||||
uninstallFlyout.appListView = new DataView.ListView(uninstallFlyout.querySelector(".applist"), function(item) {
|
||||
var appItem = appItemTemplate.cloneNode(true);
|
||||
appItem.id = "";
|
||||
appItem.style.display = "";
|
||||
var logoimg = appItem.querySelector("img");
|
||||
logoimg.src = item.Square44x44Logo_Base64 || item.SmallLogo_Base64;
|
||||
if (logoimg.src == "" || logoimg.src == null || logoimg.src == void 0) logoimg.removeAttribute("src");
|
||||
logoimg.parentElement.style.backgroundColor = item.BackgroundColor;
|
||||
if (Bridge.NString.equals(item.BackgroundColor, "transparent")) logoimg.parentElement.style.backgroundColor = themeColor;
|
||||
var appName = appItem.querySelector(".displayName");
|
||||
appName.style.wordBreak = "normal";
|
||||
appName.style.wordWrap = "normal";
|
||||
appName.textContent = item.DisplayName || item.ShortName;
|
||||
var appPub = appItem.querySelector(".publisher");
|
||||
appPub.style.display = "none";
|
||||
appItem.querySelector("div[role=advance]").style.display = "none";
|
||||
var ctrls = appItem.querySelector("div[role=control]");
|
||||
ctrls.innerHTML = "";
|
||||
appItem.data = item;
|
||||
return appItem;
|
||||
});
|
||||
uninstallFlyout.appDataSource = new DataView.DataSource();
|
||||
uninstallFlyout.appListView.bind(uninstallFlyout.appDataSource);
|
||||
pagemgr.addEventListener("load", function(e) {
|
||||
appbarControl.enabled = e == "manager";
|
||||
refreshButton.style.display = e == "manager" ? "" : "none";
|
||||
|
||||
+40
-33
@@ -16,7 +16,44 @@
|
||||
if (callback) callback(ret);
|
||||
}
|
||||
global.Package = {
|
||||
reader: function(pkgPath) { return external.Package.reader(pkgPath); },
|
||||
reader: {
|
||||
package: function(pkgPath) { return external.Package.Reader.package(pkgPath); },
|
||||
manifest: function(swManifestPath) { return external.Package.Reader.manifest(swManifestPath); },
|
||||
manifestFromInstallLocation: function(swInstallLocation) { return external.Package.Reader.fromInstallLocation(swInstallLocation); },
|
||||
readFromPackage: function(swPkgPath, bUsePri) {
|
||||
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
|
||||
return new Promise(function(resolve, reject) {
|
||||
external.Package.Reader.readFromPackageAsync(swPkgPath, bUsePri, function(result) {
|
||||
parseJsonCallback(result, resolve);
|
||||
}, function(error) {
|
||||
parseJsonCallback(error, reject);
|
||||
});
|
||||
});
|
||||
},
|
||||
readFromManifest: function(swManifestPath, bUsePri) {
|
||||
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
|
||||
return new Promise(function(resolve, reject) {
|
||||
external.Package.Reader.readFromManifestAsync(swManifestPath, bUsePri, function(result) {
|
||||
parseJsonCallback(result, resolve);
|
||||
}, function(error) {
|
||||
parseJsonCallback(error, reject);
|
||||
});
|
||||
});
|
||||
},
|
||||
readFromInstallLocation: function(swInstallLocation, bUsePri) {
|
||||
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
|
||||
return new Promise(function(resolve, reject) {
|
||||
external.Package.Reader.readFromInstallLocationAsync(swInstallLocation, bUsePri, function(result) {
|
||||
parseJsonCallback(result, resolve);
|
||||
}, function(error) {
|
||||
parseJsonCallback(error, reject);
|
||||
});
|
||||
});
|
||||
},
|
||||
cancelAll: function() { external.Package.Reader.cancelAll(); },
|
||||
addApplicationReadItem: function(swItemName) { return external.Package.Reader.addApplicationItem(swItemName); },
|
||||
removeApplicationReadItem: function(swItemName) { return external.Package.Reader.removeApplicationItem(swItemName); }
|
||||
},
|
||||
manager: {
|
||||
add: function(swPkgPath, uOptions) {
|
||||
return new Promise(function(resolve, reject, progress) {
|
||||
@@ -129,38 +166,8 @@
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
manifest: function(swManifestPath) { return external.Package.manifest(swManifestPath); },
|
||||
manifestFromInstallLocation: function(swInstallLocation) { return external.Package.fromInstallLocation(swInstallLocation); },
|
||||
readFromPackage: function(swPkgPath, bUsePri) {
|
||||
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
|
||||
return new Promise(function(resolve, reject) {
|
||||
external.Package.readFromPackageAsync(swPkgPath, bUsePri, function(result) {
|
||||
parseJsonCallback(result, resolve);
|
||||
}, function(error) {
|
||||
parseJsonCallback(error, reject);
|
||||
});
|
||||
});
|
||||
},
|
||||
readFromManifest: function(swPkgPath, bUsePri) {
|
||||
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
|
||||
return new Promise(function(resolve, reject) {
|
||||
external.Package.readFromManifestAsync(swPkgPath, bUsePri, function(result) {
|
||||
parseJsonCallback(result, resolve);
|
||||
}, function(error) {
|
||||
parseJsonCallback(error, reject);
|
||||
});
|
||||
});
|
||||
},
|
||||
readFromInstallLocation: function(swPkgPath, bUsePri) {
|
||||
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
|
||||
return new Promise(function(resolve, reject) {
|
||||
external.Package.readFromInstallLocationAsync(swPkgPath, bUsePri, function(result) {
|
||||
parseJsonCallback(result, resolve);
|
||||
}, function(error) {
|
||||
parseJsonCallback(error, reject);
|
||||
});
|
||||
});
|
||||
cancelAll: function() { mgr.cancelAll(); },
|
||||
active: function(swAppUserModelID, swArgs) { return mgr.activeApp(swAppUserModelID, swArgs || null); }
|
||||
},
|
||||
};
|
||||
})(this);
|
||||
@@ -13,7 +13,11 @@
|
||||
var byName = el.getAttribute('data-res-byname');
|
||||
var byId = el.getAttribute('data-res-byid');
|
||||
var fromFile = el.getAttribute('data-res-fromfile');
|
||||
if ((byName && !Bridge.NString.empty(byName)) || (byId && parseInt(byId, 10) > 0) || (fromFile && !Bridge.NString.empty(fromFile))) {
|
||||
var byXml = el.getAttribute('data-res-resxml');
|
||||
if ((byName && !Bridge.NString.empty(byName)) ||
|
||||
(byId && parseInt(byId, 10) > 0) ||
|
||||
(fromFile && !Bridge.NString.empty(fromFile)) ||
|
||||
(byXml && !Bridge.NString.empty(byXml))) {
|
||||
result.push(el);
|
||||
}
|
||||
}
|
||||
@@ -47,6 +51,16 @@
|
||||
} catch (e) {
|
||||
nodes[i].textContent = "";
|
||||
}
|
||||
} else if (nodes[i].hasAttribute('data-res-resxml')) {
|
||||
try {
|
||||
var obj = nodes[i].getAttribute('data-res-resxml');
|
||||
var strres = external.StringResources;
|
||||
if (strres && strres.isValid) {
|
||||
nodes[i].textContent = strres.get(obj);
|
||||
}
|
||||
} catch (e) {
|
||||
nodes[i].textContent = "";
|
||||
}
|
||||
} else {
|
||||
nodes[i].textContent = "";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,720 @@
|
||||
/*!
|
||||
* Search.Box - standalone SearchBox control (ES5, IE10 compatible)
|
||||
* Exposes constructor as global.Search.Box
|
||||
*
|
||||
* Features:
|
||||
* - API compatible-ish with WinJS.UI.SearchBox: properties (placeholderText, queryText, chooseSuggestionOnEnter, disabled)
|
||||
* - Events: querychanged, querysubmitted, resultsuggestionchosen, suggestionsrequested
|
||||
* - supports both `element.addEventListener("querychanged", handler)` and `instance.onquerychanged = handler`
|
||||
* - Methods: setSuggestions(array), clearSuggestions(), dispose(), setLocalContentSuggestionSettings(settings) (noop)
|
||||
* - Suggestions kinds: Query (0), Result (1), Separator (2) OR string names 'query'/'result'/'separator'
|
||||
* - Hit highlighting: uses item.hits if provided, otherwise simple substring match of current input
|
||||
* - No WinRT / WinJS dependency
|
||||
*
|
||||
* Usage:
|
||||
* var box = new Search.Box(hostElement, options);
|
||||
* box.setSuggestions([{ kind: 0, text: "hello" }, ...]);
|
||||
*/
|
||||
|
||||
(function(global) {
|
||||
"use strict";
|
||||
|
||||
// Ensure namespace
|
||||
if (!global.Search) {
|
||||
global.Search = {};
|
||||
}
|
||||
|
||||
// Suggestion kinds
|
||||
var SuggestionKind = {
|
||||
Query: 0,
|
||||
Result: 1,
|
||||
Separator: 2
|
||||
};
|
||||
|
||||
// Utility: create id
|
||||
function uniqueId(prefix) {
|
||||
return prefix + Math.random().toString(36).slice(2);
|
||||
}
|
||||
|
||||
// Simple CustomEvent fallback for IE10
|
||||
function createCustomEvent(type, detail) {
|
||||
var ev;
|
||||
try {
|
||||
ev = document.createEvent("CustomEvent");
|
||||
ev.initCustomEvent(type, true, true, detail || {});
|
||||
} catch (e) {
|
||||
ev = document.createEvent("Event");
|
||||
ev.initEvent(type, true, true);
|
||||
ev.detail = detail || {};
|
||||
}
|
||||
return ev;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
function SearchBox(element, options) {
|
||||
element = element || document.createElement("div");
|
||||
|
||||
if (element.__searchBoxInstance) {
|
||||
throw new Error("Search.Box: duplicate construction on same element");
|
||||
}
|
||||
element.__searchBoxInstance = this;
|
||||
|
||||
// DOM elements
|
||||
this._root = element;
|
||||
this._input = document.createElement("input");
|
||||
this._input.type = "search";
|
||||
this._button = document.createElement("div");
|
||||
this._button.tabIndex = -1;
|
||||
this._flyout = document.createElement("div");
|
||||
this._repeater = document.createElement("div"); // container for suggestion items
|
||||
this._flyout.style.display = "none";
|
||||
// state
|
||||
this._suggestions = [];
|
||||
this._currentSelectedIndex = -1; // fake focus/selection index
|
||||
this._currentFocusedIndex = -1; // navigation focus index
|
||||
this._prevQueryText = "";
|
||||
this._chooseSuggestionOnEnter = false;
|
||||
this._disposed = false;
|
||||
this._lastKeyPressLanguage = "";
|
||||
|
||||
// classes follow WinJS naming where convenient (so your existing CSS can still be used)
|
||||
this._root.className = (this._root.className ? this._root.className + " " : "") + "win-searchbox";
|
||||
this._input.className = "win-searchbox-input";
|
||||
this._button.className = "win-searchbox-button";
|
||||
this._flyout.className = "win-searchbox-flyout";
|
||||
this._repeater.className = "win-searchbox-repeater";
|
||||
|
||||
// assemble
|
||||
this._flyout.appendChild(this._repeater);
|
||||
this._root.appendChild(this._input);
|
||||
this._root.appendChild(this._button);
|
||||
this._root.appendChild(this._flyout);
|
||||
|
||||
// accessibility basics
|
||||
this._root.setAttribute("role", "group");
|
||||
this._input.setAttribute("role", "textbox");
|
||||
this._button.setAttribute("role", "button");
|
||||
this._repeater.setAttribute("role", "listbox");
|
||||
if (!this._repeater.id) {
|
||||
this._repeater.id = uniqueId("search_repeater_");
|
||||
}
|
||||
this._input.setAttribute("aria-controls", this._repeater.id);
|
||||
this._repeater.setAttribute("aria-live", "polite");
|
||||
|
||||
// user-assignable event handlers (older style)
|
||||
this.onquerychanged = null;
|
||||
this.onquerysubmitted = null;
|
||||
this.onresultsuggestionchosen = null;
|
||||
this.onsuggestionsrequested = null;
|
||||
|
||||
// wire events
|
||||
this._wireEvents();
|
||||
|
||||
// options
|
||||
options = options || {};
|
||||
if (options.placeholderText) this.placeholderText = options.placeholderText;
|
||||
if (options.queryText) this.queryText = options.queryText;
|
||||
if (options.chooseSuggestionOnEnter) this.chooseSuggestionOnEnter = !!options.chooseSuggestionOnEnter;
|
||||
if (options.disabled) this.disabled = !!options.disabled;
|
||||
|
||||
// new events
|
||||
this.ontextchanged = null;
|
||||
}
|
||||
|
||||
// Prototype
|
||||
SearchBox.prototype = {
|
||||
// Properties
|
||||
get element() {
|
||||
return this._root;
|
||||
},
|
||||
|
||||
get placeholderText() {
|
||||
return this._input.placeholder;
|
||||
},
|
||||
set placeholderText(value) {
|
||||
this._input.placeholder = value || "";
|
||||
},
|
||||
|
||||
get queryText() {
|
||||
return this._input.value;
|
||||
},
|
||||
set queryText(value) {
|
||||
this._input.value = value == null ? "" : value;
|
||||
},
|
||||
|
||||
get chooseSuggestionOnEnter() {
|
||||
return this._chooseSuggestionOnEnter;
|
||||
},
|
||||
set chooseSuggestionOnEnter(v) {
|
||||
this._chooseSuggestionOnEnter = !!v;
|
||||
this._updateButtonClass();
|
||||
},
|
||||
|
||||
get disabled() {
|
||||
return !!this._input.disabled;
|
||||
},
|
||||
set disabled(v) {
|
||||
var val = !!v;
|
||||
if (val === this.disabled) return;
|
||||
this._input.disabled = val;
|
||||
try { this._button.disabled = val; } catch (e) {}
|
||||
if (val) {
|
||||
this._root.className = (this._root.className + " win-searchbox-disabled").trim();
|
||||
this.hideFlyout();
|
||||
} else {
|
||||
this._root.className = this._root.className.replace(/\bwin-searchbox-disabled\b/g, "").trim();
|
||||
}
|
||||
},
|
||||
|
||||
// Public methods
|
||||
setSuggestions: function(arr) {
|
||||
// Expect array of objects with keys: kind (0/1/2 or 'query'/'result'/'separator'), text, detailText, tag, imageUrl, hits
|
||||
this._suggestions = (arr && arr.slice(0)) || [];
|
||||
this._currentSelectedIndex = -1;
|
||||
this._currentFocusedIndex = -1;
|
||||
this._renderSuggestions();
|
||||
if (this._suggestions.length) this.showFlyout();
|
||||
else this.hideFlyout();
|
||||
},
|
||||
|
||||
clearSuggestions: function() {
|
||||
this.setSuggestions([]);
|
||||
},
|
||||
|
||||
showFlyout: function() {
|
||||
if (!this._suggestions || this._suggestions.length === 0) return;
|
||||
this._flyout.style.display = "block";
|
||||
this._updateButtonClass();
|
||||
},
|
||||
|
||||
hideFlyout: function() {
|
||||
this._flyout.style.display = "none";
|
||||
this._updateButtonClass();
|
||||
},
|
||||
|
||||
dispose: function() {
|
||||
if (this._disposed) return;
|
||||
// detach event listeners by cloning elements (simple way)
|
||||
var newRoot = this._root.cloneNode(true);
|
||||
if (this._root.parentNode) {
|
||||
this._root.parentNode.replaceChild(newRoot, this._root);
|
||||
}
|
||||
try {
|
||||
delete this._root.__searchBoxInstance;
|
||||
} catch (e) {}
|
||||
this._disposed = true;
|
||||
},
|
||||
|
||||
setLocalContentSuggestionSettings: function(settings) {
|
||||
// No-op in non-WinRT environment; kept for API compatibility.
|
||||
},
|
||||
|
||||
// Internal / rendering
|
||||
_wireEvents: function() {
|
||||
var that = this;
|
||||
|
||||
this._input.addEventListener("input", function(ev) {
|
||||
that._onInputChange(ev);
|
||||
}, false);
|
||||
|
||||
this._input.addEventListener("keydown", function(ev) {
|
||||
that._onKeyDown(ev);
|
||||
}, false);
|
||||
|
||||
this._input.addEventListener("keypress", function(ev) {
|
||||
// capture locale if available
|
||||
try { that._lastKeyPressLanguage = ev.locale || that._lastKeyPressLanguage; } catch (e) {}
|
||||
}, false);
|
||||
|
||||
this._input.addEventListener("focus", function() {
|
||||
if (that._suggestions.length) {
|
||||
that.showFlyout();
|
||||
that._updateFakeFocus();
|
||||
}
|
||||
that._root.className = (that._root.className + " win-searchbox-input-focus").trim();
|
||||
that._updateButtonClass();
|
||||
}, false);
|
||||
|
||||
this._input.addEventListener("blur", function() {
|
||||
// small timeout to allow suggestion click to process
|
||||
setTimeout(function() {
|
||||
if (!that._root.contains(document.activeElement)) {
|
||||
that.hideFlyout();
|
||||
that._root.className = that._root.className.replace(/\bwin-searchbox-input-focus\b/g, "").trim();
|
||||
that._currentFocusedIndex = -1;
|
||||
that._currentSelectedIndex = -1;
|
||||
}
|
||||
}, 0);
|
||||
}, false);
|
||||
|
||||
this._button.addEventListener("click", function(ev) {
|
||||
that._input.focus();
|
||||
that._submitQuery(that._input.value, ev);
|
||||
that.hideFlyout();
|
||||
}, false);
|
||||
|
||||
// delegate click for suggestions: attach on repeater container (works in IE10)
|
||||
this._repeater.addEventListener("click", function(ev) {
|
||||
var el = ev.target;
|
||||
// climb until we find child with data-index
|
||||
while (el && el !== that._repeater) {
|
||||
if (el.hasAttribute && el.hasAttribute("data-index")) break;
|
||||
el = el.parentNode;
|
||||
}
|
||||
if (el && el !== that._repeater) {
|
||||
var idx = parseInt(el.getAttribute("data-index"), 10);
|
||||
var item = that._suggestions[idx];
|
||||
if (item) {
|
||||
that._input.focus();
|
||||
that._processSuggestionChosen(item, ev);
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
},
|
||||
|
||||
_onInputChange: function(ev) {
|
||||
if (this.disabled) return;
|
||||
var v = this._input.value;
|
||||
|
||||
this._emit("textchanged", {
|
||||
text: v
|
||||
}, this.ontextchanged);
|
||||
|
||||
var changed = (v !== this._prevQueryText);
|
||||
this._prevQueryText = v;
|
||||
|
||||
// fire querychanged
|
||||
var evDetail = {
|
||||
language: this._getBrowserLanguage(),
|
||||
queryText: v,
|
||||
linguisticDetails: { queryTextAlternatives: [], queryTextCompositionStart: 0, queryTextCompositionLength: 0 }
|
||||
};
|
||||
this._emit("querychanged", evDetail, this.onquerychanged);
|
||||
|
||||
// fire suggestionsrequested - allow client to call setSuggestions
|
||||
var suggestionsDetail = {
|
||||
queryText: v,
|
||||
language: this._getBrowserLanguage(),
|
||||
setSuggestions: (function(thatRef) {
|
||||
return function(arr) {
|
||||
thatRef.setSuggestions(arr || []);
|
||||
};
|
||||
})(this)
|
||||
};
|
||||
this._emit("suggestionsrequested", suggestionsDetail, this.onsuggestionsrequested);
|
||||
},
|
||||
|
||||
_submitQuery: function(queryText, ev) {
|
||||
var detail = {
|
||||
language: this._getBrowserLanguage(),
|
||||
queryText: queryText,
|
||||
keyModifiers: this._getKeyModifiers(ev)
|
||||
};
|
||||
this._emit("querysubmitted", detail, this.onquerysubmitted);
|
||||
},
|
||||
|
||||
_processSuggestionChosen: function(item, ev) {
|
||||
// normalize kind
|
||||
var kind = item.kind;
|
||||
if (typeof kind === "string") {
|
||||
if (kind.toLowerCase() === "query") kind = SuggestionKind.Query;
|
||||
else if (kind.toLowerCase() === "result") kind = SuggestionKind.Result;
|
||||
else if (kind.toLowerCase() === "separator") kind = SuggestionKind.Separator;
|
||||
}
|
||||
|
||||
this.queryText = item.text || "";
|
||||
if (kind === SuggestionKind.Query || kind === undefined) {
|
||||
// choose query -> submit
|
||||
this._submitQuery(item.text || "", ev);
|
||||
} else if (kind === SuggestionKind.Result) {
|
||||
this._emit("resultsuggestionchosen", {
|
||||
tag: item.tag,
|
||||
keyModifiers: this._getKeyModifiers(ev),
|
||||
storageFile: null
|
||||
}, this.onresultsuggestionchosen);
|
||||
}
|
||||
this.hideFlyout();
|
||||
},
|
||||
|
||||
_renderSuggestions: function() {
|
||||
// clear repeater
|
||||
while (this._repeater.firstChild) this._repeater.removeChild(this._repeater.firstChild);
|
||||
|
||||
var frag = document.createDocumentFragment();
|
||||
for (var i = 0; i < this._suggestions.length; i++) {
|
||||
var s = this._suggestions[i];
|
||||
var itemEl = this._renderSuggestion(s, i);
|
||||
frag.appendChild(itemEl);
|
||||
}
|
||||
this._repeater.appendChild(frag);
|
||||
this._updateFakeFocus();
|
||||
},
|
||||
|
||||
_renderSuggestion: function(item, index) {
|
||||
var that = this;
|
||||
var kind = item.kind;
|
||||
if (typeof kind === "string") {
|
||||
kind = kind.toLowerCase() === "query" ? SuggestionKind.Query :
|
||||
kind.toLowerCase() === "result" ? SuggestionKind.Result :
|
||||
kind.toLowerCase() === "separator" ? SuggestionKind.Separator : kind;
|
||||
}
|
||||
|
||||
var root = document.createElement("div");
|
||||
root.setAttribute("data-index", index);
|
||||
root.id = this._repeater.id + "_" + index;
|
||||
|
||||
if (kind === SuggestionKind.Separator) {
|
||||
root.className = "win-searchbox-suggestion-separator";
|
||||
if (item.text) {
|
||||
var textEl = document.createElement("div");
|
||||
textEl.innerText = item.text;
|
||||
textEl.setAttribute("aria-hidden", "true");
|
||||
root.appendChild(textEl);
|
||||
}
|
||||
root.insertAdjacentHTML("beforeend", "<hr/>");
|
||||
root.setAttribute("role", "separator");
|
||||
root.setAttribute("aria-label", item.text || "");
|
||||
return root;
|
||||
}
|
||||
|
||||
if (kind === SuggestionKind.Result) {
|
||||
root.className = "win-searchbox-suggestion-result";
|
||||
// image
|
||||
var img = document.createElement("img");
|
||||
img.setAttribute("aria-hidden", "true");
|
||||
if (item.imageUrl) {
|
||||
img.onload = function() {
|
||||
img.style.opacity = "1";
|
||||
};
|
||||
img.style.opacity = "0";
|
||||
img.src = item.imageUrl;
|
||||
} else {
|
||||
img.style.display = "none";
|
||||
}
|
||||
root.appendChild(img);
|
||||
|
||||
var textDiv = document.createElement("div");
|
||||
textDiv.className = "win-searchbox-suggestion-result-text";
|
||||
textDiv.setAttribute("aria-hidden", "true");
|
||||
this._addHitHighlightedText(textDiv, item, item.text || "");
|
||||
textDiv.title = item.text || "";
|
||||
root.appendChild(textDiv);
|
||||
|
||||
var detail = document.createElement("span");
|
||||
detail.className = "win-searchbox-suggestion-result-detailed-text";
|
||||
detail.setAttribute("aria-hidden", "true");
|
||||
this._addHitHighlightedText(detail, item, item.detailText || "");
|
||||
textDiv.appendChild(document.createElement("br"));
|
||||
textDiv.appendChild(detail);
|
||||
|
||||
root.setAttribute("role", "option");
|
||||
root.setAttribute("aria-label", (item.text || "") + " " + (item.detailText || ""));
|
||||
return root;
|
||||
}
|
||||
|
||||
// default / query
|
||||
root.className = "win-searchbox-suggestion-query";
|
||||
this._addHitHighlightedText(root, item, item.text || "");
|
||||
root.title = item.text || "";
|
||||
root.setAttribute("role", "option");
|
||||
root.setAttribute("aria-label", item.text || "");
|
||||
return root;
|
||||
},
|
||||
|
||||
_addHitHighlightedText: function(container, item, text) {
|
||||
// Remove existing children
|
||||
while (container.firstChild) container.removeChild(container.firstChild);
|
||||
if (!text) return;
|
||||
|
||||
// Build hits from item.hits if present (array of {startPosition, length}), otherwise simple substring matches of current input
|
||||
var hits = [];
|
||||
if (item && item.hits && item.hits.length) {
|
||||
for (var i = 0; i < item.hits.length; i++) {
|
||||
hits.push({ startPosition: item.hits[i].startPosition, length: item.hits[i].length });
|
||||
}
|
||||
} else {
|
||||
var q = this._input.value || "";
|
||||
if (q) {
|
||||
var low = text.toLowerCase();
|
||||
var lq = q.toLowerCase();
|
||||
var pos = 0;
|
||||
while (true) {
|
||||
var idx = low.indexOf(lq, pos);
|
||||
if (idx === -1) break;
|
||||
hits.push({ startPosition: idx, length: q.length });
|
||||
pos = idx + q.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge overlapping hits & sort
|
||||
hits.sort(function(a, b) { return a.startPosition - b.startPosition; });
|
||||
var merged = [];
|
||||
for (var j = 0; j < hits.length; j++) {
|
||||
if (merged.length === 0) {
|
||||
merged.push({ startPosition: hits[j].startPosition, length: hits[j].length });
|
||||
} else {
|
||||
var cur = merged[merged.length - 1];
|
||||
var curEnd = cur.startPosition + cur.length;
|
||||
if (hits[j].startPosition <= curEnd) {
|
||||
var nextEnd = hits[j].startPosition + hits[j].length;
|
||||
if (nextEnd > curEnd) {
|
||||
cur.length = nextEnd - cur.startPosition;
|
||||
}
|
||||
} else {
|
||||
merged.push({ startPosition: hits[j].startPosition, length: hits[j].length });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var last = 0;
|
||||
for (var k = 0; k < merged.length; k++) {
|
||||
var h = merged[k];
|
||||
if (h.startPosition > last) {
|
||||
var pre = document.createElement("span");
|
||||
pre.innerText = text.substring(last, h.startPosition);
|
||||
pre.setAttribute("aria-hidden", "true");
|
||||
container.appendChild(pre);
|
||||
}
|
||||
var hitSpan = document.createElement("span");
|
||||
hitSpan.innerText = text.substring(h.startPosition, h.startPosition + h.length);
|
||||
hitSpan.className = "win-searchbox-flyout-highlighttext";
|
||||
hitSpan.setAttribute("aria-hidden", "true");
|
||||
container.appendChild(hitSpan);
|
||||
last = h.startPosition + h.length;
|
||||
}
|
||||
if (last < text.length) {
|
||||
var post = document.createElement("span");
|
||||
post.innerText = text.substring(last);
|
||||
post.setAttribute("aria-hidden", "true");
|
||||
container.appendChild(post);
|
||||
}
|
||||
|
||||
if (merged.length === 0) {
|
||||
// no hits - append plain text
|
||||
var whole = document.createElement("span");
|
||||
whole.innerText = text;
|
||||
whole.setAttribute("aria-hidden", "true");
|
||||
container.appendChild(whole);
|
||||
}
|
||||
},
|
||||
|
||||
_updateFakeFocus: function() {
|
||||
var firstIndex = -1;
|
||||
if ((this._flyout.style.display !== "none") && this._chooseSuggestionOnEnter) {
|
||||
for (var i = 0; i < this._suggestions.length; i++) {
|
||||
var s = this._suggestions[i];
|
||||
var kind = s.kind;
|
||||
if (typeof kind === "string") {
|
||||
kind = kind.toLowerCase() === "query" ? SuggestionKind.Query :
|
||||
kind.toLowerCase() === "result" ? SuggestionKind.Result :
|
||||
kind.toLowerCase() === "separator" ? SuggestionKind.Separator : kind;
|
||||
}
|
||||
if (kind === SuggestionKind.Query || kind === SuggestionKind.Result) {
|
||||
firstIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._selectSuggestionAtIndex(firstIndex);
|
||||
},
|
||||
|
||||
_selectSuggestionAtIndex: function(index) {
|
||||
for (var i = 0; i < this._repeater.children.length; i++) {
|
||||
var el = this._repeater.children[i];
|
||||
if (!el) continue;
|
||||
if (i === index) {
|
||||
if (el.className.indexOf("win-searchbox-suggestion-selected") === -1) {
|
||||
el.className = (el.className + " win-searchbox-suggestion-selected").trim();
|
||||
}
|
||||
el.setAttribute("aria-selected", "true");
|
||||
try {
|
||||
this._input.setAttribute("aria-activedescendant", el.id);
|
||||
} catch (e) {}
|
||||
// ensure visible
|
||||
try {
|
||||
var top = el.offsetTop;
|
||||
var bottom = top + el.offsetHeight;
|
||||
var scrollTop = this._flyout.scrollTop;
|
||||
var height = this._flyout.clientHeight;
|
||||
if (bottom > scrollTop + height) this._flyout.scrollTop = bottom - height;
|
||||
else if (top < scrollTop) this._flyout.scrollTop = top;
|
||||
} catch (e) {}
|
||||
} else {
|
||||
el.className = el.className.replace(/\bwin-searchbox-suggestion-selected\b/g, "").trim();
|
||||
el.setAttribute("aria-selected", "false");
|
||||
}
|
||||
}
|
||||
if (index === -1) {
|
||||
try { this._input.removeAttribute("aria-activedescendant"); } catch (e) {}
|
||||
}
|
||||
this._currentSelectedIndex = index;
|
||||
this._updateButtonClass();
|
||||
},
|
||||
|
||||
_updateButtonClass: function() {
|
||||
if ((this._currentSelectedIndex !== -1) || (document.activeElement !== this._input)) {
|
||||
this._button.className = this._button.className.replace(/\bwin-searchbox-button-input-focus\b/g, "").trim();
|
||||
} else if (document.activeElement === this._input) {
|
||||
if (this._button.className.indexOf("win-searchbox-button-input-focus") === -1) {
|
||||
this._button.className = (this._button.className + " win-searchbox-button-input-focus").trim();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onKeyDown: function(ev) {
|
||||
// Normalize key
|
||||
var key = ev.key || "";
|
||||
if (!key && ev.keyCode) {
|
||||
if (ev.keyCode === 13) key = "Enter";
|
||||
else if (ev.keyCode === 27) key = "Esc";
|
||||
else if (ev.keyCode === 38) key = "Up";
|
||||
else if (ev.keyCode === 40) key = "Down";
|
||||
else if (ev.keyCode === 9) key = "Tab";
|
||||
}
|
||||
|
||||
if (key === "Tab") {
|
||||
// handle tab navigation into suggestions
|
||||
if (ev.shiftKey) {
|
||||
// shift+tab: allow default behavior
|
||||
} else {
|
||||
if (this._currentFocusedIndex === -1) {
|
||||
this._currentFocusedIndex = this._findNextSuggestionElementIndex(-1);
|
||||
}
|
||||
if (this._currentFocusedIndex !== -1) {
|
||||
this._selectSuggestionAtIndex(this._currentFocusedIndex);
|
||||
this._updateQueryTextWithSuggestionText(this._currentFocusedIndex);
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
}
|
||||
}
|
||||
} else if (key === "Esc") {
|
||||
if (this._currentFocusedIndex !== -1) {
|
||||
this.queryText = this._prevQueryText;
|
||||
this._currentFocusedIndex = -1;
|
||||
this._selectSuggestionAtIndex(-1);
|
||||
this._updateButtonClass();
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
} else if (this.queryText !== "") {
|
||||
this.queryText = "";
|
||||
// trigger querychanged handlers
|
||||
this._onInputChange(null);
|
||||
this._updateButtonClass();
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
}
|
||||
} else if (key === "Up") {
|
||||
var prev;
|
||||
if (this._currentSelectedIndex !== -1) {
|
||||
prev = this._findPreviousSuggestionElementIndex(this._currentSelectedIndex);
|
||||
if (prev === -1) this.queryText = this._prevQueryText;
|
||||
} else {
|
||||
prev = this._findPreviousSuggestionElementIndex(this._suggestions.length);
|
||||
}
|
||||
this._currentFocusedIndex = prev;
|
||||
this._selectSuggestionAtIndex(prev);
|
||||
this._updateQueryTextWithSuggestionText(this._currentFocusedIndex);
|
||||
this._updateButtonClass();
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
} else if (key === "Down") {
|
||||
var next = this._findNextSuggestionElementIndex(this._currentSelectedIndex);
|
||||
if ((this._currentSelectedIndex !== -1) && (next === -1)) this.queryText = this._prevQueryText;
|
||||
this._currentFocusedIndex = next;
|
||||
this._selectSuggestionAtIndex(next);
|
||||
this._updateQueryTextWithSuggestionText(this._currentFocusedIndex);
|
||||
this._updateButtonClass();
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
} else if (key === "Enter") {
|
||||
if (this._currentSelectedIndex === -1) {
|
||||
this._submitQuery(this._input.value, ev);
|
||||
} else {
|
||||
var chosen = this._suggestions[this._currentSelectedIndex];
|
||||
if (chosen) this._processSuggestionChosen(chosen, ev);
|
||||
else this._submitQuery(this._input.value, ev);
|
||||
}
|
||||
this.hideFlyout();
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
} else {
|
||||
// typing -> clear selection
|
||||
if (this._currentFocusedIndex !== -1) {
|
||||
this._currentFocusedIndex = -1;
|
||||
this._selectSuggestionAtIndex(-1);
|
||||
this._updateFakeFocus();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_findNextSuggestionElementIndex: function(curIndex) {
|
||||
var start = curIndex + 1;
|
||||
if (start < 0) start = 0;
|
||||
for (var i = start; i < this._suggestions.length; i++) {
|
||||
var s = this._suggestions[i];
|
||||
var k = s.kind;
|
||||
if (typeof k === "string") {
|
||||
k = k.toLowerCase() === "query" ? SuggestionKind.Query :
|
||||
k.toLowerCase() === "result" ? SuggestionKind.Result :
|
||||
k.toLowerCase() === "separator" ? SuggestionKind.Separator : k;
|
||||
}
|
||||
if (k === SuggestionKind.Query || k === SuggestionKind.Result) return i;
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
|
||||
_findPreviousSuggestionElementIndex: function(curIndex) {
|
||||
var start = curIndex - 1;
|
||||
if (start >= this._suggestions.length) start = this._suggestions.length - 1;
|
||||
for (var i = start; i >= 0; i--) {
|
||||
var s = this._suggestions[i];
|
||||
var k = s.kind;
|
||||
if (typeof k === "string") {
|
||||
k = k.toLowerCase() === "query" ? SuggestionKind.Query :
|
||||
k.toLowerCase() === "result" ? SuggestionKind.Result :
|
||||
k.toLowerCase() === "separator" ? SuggestionKind.Separator : k;
|
||||
}
|
||||
if (k === SuggestionKind.Query || k === SuggestionKind.Result) return i;
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
|
||||
_updateQueryTextWithSuggestionText: function(idx) {
|
||||
if ((idx >= 0) && (idx < this._suggestions.length)) {
|
||||
this.queryText = this._suggestions[idx].text || "";
|
||||
}
|
||||
},
|
||||
|
||||
_emit: function(type, detail, handler) {
|
||||
var ev = createCustomEvent(type, detail);
|
||||
// call handler property first
|
||||
if (typeof handler === "function") {
|
||||
try { handler.call(this, ev); } catch (e) { /* swallow */ }
|
||||
}
|
||||
try { this._root.dispatchEvent(ev); } catch (e) { /* swallow */ }
|
||||
return ev;
|
||||
},
|
||||
|
||||
_getBrowserLanguage: function() {
|
||||
try {
|
||||
return (navigator && (navigator.language || navigator.userLanguage)) || "";
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
|
||||
_getKeyModifiers: function(ev) {
|
||||
var m = 0;
|
||||
if (!ev) return m;
|
||||
if (ev.ctrlKey) m |= 1;
|
||||
if (ev.altKey) m |= 2;
|
||||
if (ev.shiftKey) m |= 4;
|
||||
return m;
|
||||
}
|
||||
};
|
||||
|
||||
// export
|
||||
global.Search.Box = SearchBox;
|
||||
|
||||
})(this);
|
||||
@@ -0,0 +1,184 @@
|
||||
(function(global) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* TransitionPanel
|
||||
* axis: 'x' | 'y' | 'both'
|
||||
* speed: 'fast' | 'medium' | 'slow'
|
||||
* el: DOM 元素
|
||||
*/
|
||||
function TransitionPanel(el, options) {
|
||||
if (!el) throw new Error("TransitionPanel requires a DOM element.");
|
||||
|
||||
this.el = el;
|
||||
this.opts = options || {};
|
||||
this.axis = this.opts.axis || 'y';
|
||||
this.speed = this.opts.speed || 'medium';
|
||||
|
||||
// 初始化状态
|
||||
this._shown = false;
|
||||
this._events = {};
|
||||
|
||||
// 确保基础类 statusbar
|
||||
if (!el.classList.contains('statusbar')) el.classList.add('statusbar');
|
||||
|
||||
// 确保 axis 类存在(x/y/both)
|
||||
if (this.axis === 'x' && !el.classList.contains('x')) el.classList.add('x');
|
||||
else if (this.axis === 'y' && !el.classList.contains('y')) el.classList.add('y');
|
||||
else if (this.axis === 'both' && !el.classList.contains('both')) el.classList.add('both');
|
||||
|
||||
// 添加速度类
|
||||
if (this.speed === 'fast') el.classList.add('fast');
|
||||
else if (this.speed === 'medium') el.classList.add('medium');
|
||||
else el.classList.add('slow');
|
||||
|
||||
// 内容变化自动刷新
|
||||
this._bindContentChange();
|
||||
}
|
||||
|
||||
function maxWidth(el) {
|
||||
var cw = 0;
|
||||
var ow = 0;
|
||||
var rw = 0;
|
||||
var sw = 0;
|
||||
try { cw = el.clientWidth; } catch (e) {}
|
||||
try { ow = el.offsetWidth; } catch (e) {}
|
||||
try { rw = el.getBoundingClientRect().width; } catch (e) {}
|
||||
try { sw = el.scrollWidth; } catch (e) {}
|
||||
return Math.max(cw, ow, rw, sw);
|
||||
}
|
||||
|
||||
function maxHeight(el) {
|
||||
var ch = 0;
|
||||
var oh = 0;
|
||||
var rh = 0;
|
||||
var sh = 0;
|
||||
try { ch = el.clientHeight; } catch (e) {}
|
||||
try { oh = el.offsetHeight; } catch (e) {}
|
||||
try { rh = el.getBoundingClientRect().height; } catch (e) {}
|
||||
try { sh = el.scrollHeight; } catch (e) {}
|
||||
return Math.max(ch, oh, rh, sh);
|
||||
}
|
||||
// 显示
|
||||
TransitionPanel.prototype.show = function() {
|
||||
if (this._shown) return;
|
||||
this._emit('beforeshow');
|
||||
this._shown = true;
|
||||
|
||||
var el = this.el;
|
||||
|
||||
setTimeout(function() {
|
||||
this._emit('show');
|
||||
|
||||
if (this.axis !== 'x') el.style.height = maxHeight(el) + 'px';
|
||||
if (this.axis !== 'y') el.style.width = maxWidth(el) + 'px';
|
||||
if (this.axis === 'both') {
|
||||
el.style.height = maxHeight(el) + 'px';
|
||||
el.style.width = maxWidth(el) + 'px';
|
||||
}
|
||||
this._afterTransition('aftershow');
|
||||
}.bind(this), 16);
|
||||
};
|
||||
|
||||
// 隐藏
|
||||
TransitionPanel.prototype.hide = function() {
|
||||
if (!this._shown) return;
|
||||
this._emit('beforehide');
|
||||
this._shown = false;
|
||||
|
||||
var el = this.el;
|
||||
|
||||
// 锁定当前尺寸
|
||||
if (this.axis !== 'x') el.style.height = maxHeight(el) + 'px';
|
||||
if (this.axis !== 'y') el.style.width = maxWidth(el) + 'px';
|
||||
if (this.axis === 'both') {
|
||||
el.style.height = maxHeight(el) + 'px';
|
||||
el.style.width = maxWidth(el) + 'px';
|
||||
}
|
||||
setTimeout(function() {
|
||||
this._emit('hide');
|
||||
|
||||
// 回到折叠状态尺寸(依赖 x/y/both 类)
|
||||
if (this.axis !== 'x') el.style.height = '';
|
||||
if (this.axis !== 'y') el.style.width = '';
|
||||
if (this.axis === 'both') {
|
||||
el.style.height = '';
|
||||
el.style.width = '';
|
||||
}
|
||||
this._afterTransition('afterhide');
|
||||
}.bind(this), 16);
|
||||
};
|
||||
|
||||
// 刷新尺寸(显示中)
|
||||
TransitionPanel.prototype.refresh = function() {
|
||||
if (!this._shown) return;
|
||||
var el = this.el;
|
||||
if (this.axis !== 'x') el.style.height = el.scrollHeight + 'px';
|
||||
if (this.axis !== 'y') el.style.width = el.scrollWidth + 'px';
|
||||
};
|
||||
|
||||
// 内容变化自动刷新
|
||||
TransitionPanel.prototype._bindContentChange = function() {
|
||||
if (!global.setTextChangeEvent) return;
|
||||
var self = this;
|
||||
global.setTextChangeEvent(this.el, function() {
|
||||
if (self._shown) self.refresh();
|
||||
});
|
||||
};
|
||||
|
||||
// transitionend 回调处理
|
||||
TransitionPanel.prototype._afterTransition = function(evt) {
|
||||
var el = this.el;
|
||||
var called = false;
|
||||
var duration = this.speed === 'fast' ? 300 : (this.speed === 'medium' ? 500 : 700);
|
||||
|
||||
function done() {
|
||||
if (called) return;
|
||||
called = true;
|
||||
el.removeEventListener('transitionend', done);
|
||||
if (evt) this._emit(evt);
|
||||
}
|
||||
el.addEventListener('transitionend', done.bind(this));
|
||||
setTimeout(done.bind(this), duration + 30);
|
||||
};
|
||||
|
||||
// 生命周期事件绑定
|
||||
TransitionPanel.prototype.on = function(name, fn) {
|
||||
(this._events[name] || (this._events[name] = [])).push(fn);
|
||||
};
|
||||
|
||||
// 事件触发
|
||||
TransitionPanel.prototype._emit = function(name) {
|
||||
var list = this._events[name];
|
||||
if (!list) return;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
try { list[i].call(this); } catch (e) { console.error(e); }
|
||||
}
|
||||
};
|
||||
|
||||
// 只读属性 shown
|
||||
Object.defineProperty(TransitionPanel.prototype, 'shown', {
|
||||
get: function() { return this._shown; }
|
||||
});
|
||||
|
||||
// 销毁
|
||||
TransitionPanel.prototype.dispose = function() {
|
||||
// 移除所有事件回调
|
||||
this._events = {};
|
||||
// 清理 el 内联样式
|
||||
if (this.el) {
|
||||
this.el.style.height = '';
|
||||
this.el.style.width = '';
|
||||
}
|
||||
this._shown = false;
|
||||
// 可选:删除内容变化监听(如果使用全局 setTextChangeEvent)
|
||||
if (global.Windows && global.Windows.UI && global.Windows.UI.Event && global.Windows.UI.Event.Monitor) {
|
||||
// 这里可以 detach 所有回调
|
||||
// 视具体实现可扩展
|
||||
}
|
||||
};
|
||||
|
||||
// 全局暴露
|
||||
global.TransitionPanel = TransitionPanel;
|
||||
|
||||
})(this);
|
||||
+108
-25
@@ -33,6 +33,9 @@
|
||||
<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/search.js"></script>
|
||||
<link rel="stylesheet" href="css/statusbar.css">
|
||||
<script type="text/javascript" src="js/statusbar.js"></script>
|
||||
<script type="text/javascript" src="js/manager/pages.js"></script>
|
||||
<script type="text/javascript" src="js/mgrinit.js"></script>
|
||||
</head>
|
||||
@@ -42,15 +45,39 @@
|
||||
<div class="page full guide fold">
|
||||
<main class="main padding">
|
||||
<div id="page-manager" style="display: none;" class="ispage">
|
||||
<h2>应用</h2>
|
||||
<p>在这里,可以对安装的 Windows 商店应用进行管理。</p>
|
||||
<h3>安装的应用</h3>
|
||||
<h2 data-res-resxml="MANAGER_APP_TITLE"></h2>
|
||||
<p data-res-resxml="MANAGER_APP_DESCRIPTION"></p>
|
||||
<h3 data-res-resxml="MANAGER_APP_INSTALLEDAPPS"></h3>
|
||||
<br>
|
||||
<div class="app-loading" id="applist-loading" style="display: none;">
|
||||
<progress class="win-ring"></progress>
|
||||
<span class="win-label title">正在加载应用...</span>
|
||||
<br>
|
||||
<div class="win-searchbox win-disposable" id="applist-search" role="group" aria-label="搜索框"></div>
|
||||
<div class="applist-options">
|
||||
<div class="item">
|
||||
<input type="checkbox" id="applist-showsystemapp">
|
||||
<label for="applist-showsystemapp" data-res-resxml="MANAGER_APP_SHOWSYSTEMAPP"></label>
|
||||
</div>
|
||||
<div class="item">
|
||||
<input type="checkbox" id="applist-showframework">
|
||||
<label for="applist-showframework" data-res-resxml="MANAGER_APP_SHOWFRAMEWORK"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-loading" id="applist-loading" style="display: none;">
|
||||
<br>
|
||||
<div class="container">
|
||||
<progress class="win-ring"></progress>
|
||||
<span class="win-label title" data-res-resxml="MANAGER_APP_INSTALLEDAPPS_LOADING"></span>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
<p id="applist-datalen"></p>
|
||||
<script>
|
||||
(function(global) {
|
||||
var appLoading = document.getElementById("applist-loading");
|
||||
appLoading.bar = new TransitionPanel(appLoading, {
|
||||
axis: 'y',
|
||||
duration: 500,
|
||||
});
|
||||
})(this);
|
||||
</script>
|
||||
<div class="appitem" id="appitem-template" style="display: none;">
|
||||
<div role="img" style="pointer-events: none;">
|
||||
<img width="" height="" src="images/applogo.default.png" />
|
||||
@@ -58,14 +85,18 @@
|
||||
<div role="divide" style="pointer-events: none;"></div>
|
||||
<div role="excepticon">
|
||||
<div role="title" class="win-type-x-small" style="pointer-events: none;">
|
||||
<span class="displayName">App Name</span><br>
|
||||
<span class="publisher">Publisher</span>
|
||||
<span class="displayName"></span><br>
|
||||
<span class="publisher"></span>
|
||||
</div>
|
||||
<div role="advance">
|
||||
<a>高级选项</a>
|
||||
<a data-res-resxml="MANAGER_APP_ADVANCEOPTIONS"></a>
|
||||
</div>
|
||||
<div role="progress">
|
||||
<span class="status" data-res-resxml="MANAGER_APP_UNINSTALL_ING"></span><br>
|
||||
<progress class="win-progress progress" min="0" max="100"></progress>
|
||||
</div>
|
||||
<div role="control">
|
||||
<button name="uninstall">卸载</button>
|
||||
<button class="uninstall" name="uninstall" data-res-resxml="MANAGER_APP_UNINSTALL"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -73,7 +104,7 @@
|
||||
</div>
|
||||
<div class="bottom-compensate"></div>
|
||||
</div>
|
||||
<div id="page-appinfo" class="ispage app-detailpage">
|
||||
<div id="page-appinfo" class="ispage app-detailpage" style="display: none;">
|
||||
<header>
|
||||
<button class="win-backbutton"></button>
|
||||
<h2 class="display-name">App DisplayName</h2>
|
||||
@@ -81,18 +112,37 @@
|
||||
<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>
|
||||
<p><strong data-res-resxml="MANAGER_APP_IDENTITY"></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>
|
||||
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_NAME"></span><span>: </span><span class="name"></span><br>
|
||||
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_PUBLISHER"></span><span>: </span><span class="publisher"></span><br>
|
||||
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_PUBLISHERID"></span><span>: </span><span class="publisher-id"></span><br>
|
||||
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_FAMILYNAME"></span><span>: </span><span class="family-name"></span><br>
|
||||
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_FULLNAME"></span><span>: </span><span class="full-name"></span><br>
|
||||
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_ARCHITECTURE"></span><span>: </span><span class="architecture"></span><br>
|
||||
</div>
|
||||
<p><strong>卸载</strong></p>
|
||||
<p>卸载此应用及其设置。</p>
|
||||
<button id="detail-uninstall-btn" data-app-fullname="">卸载</button>
|
||||
<p><strong data-res-resxml="MANAGER_APP_HASAPPS"></strong></p>
|
||||
<p data-res-resxml="MANAGER_APP_HASAPPS_DESC"></p>
|
||||
<div class="loadingstatus" id="appinfo-loading">
|
||||
<div class="container">
|
||||
<progress class="win-ring"></progress>
|
||||
<span class="win-label title" data-res-resxml="MANAGER_APP_INSTALLEDAPPS_LOADING"></span>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
<div class="apps">
|
||||
</div>
|
||||
<p><strong data-res-resxml="MANAGER_APP_UNINSTALL"></strong></p>
|
||||
<p data-res-resxml="MANAGER_APP_UNINSTALL_DESC"></p>
|
||||
<div class="loadingstatus" id="appinfo-uninstallstatus">
|
||||
<div style="width: 100%;">
|
||||
<span class="status" data-res-resxml="MANAGER_APP_UNINSTALL_ING"></span><br>
|
||||
<progress class="win-progress progress" min="0" max="100"></progress>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
<button id="detail-uninstall-btn" data-res-resxml="MANAGER_APP_UNINSTALL">卸载</button>
|
||||
<div class="bottom-compensate"></div>
|
||||
</div>
|
||||
</main>
|
||||
<aside class="win-ui-dark">
|
||||
@@ -100,8 +150,8 @@
|
||||
<ul class="list top">
|
||||
<li class="title">
|
||||
<div role="img"></div>
|
||||
<div role="placeholder"></div>
|
||||
<span class="win-type-base">应用管理</span>
|
||||
<!--<div role="placeholder"></div>-->
|
||||
<span class="win-type-base" data-res-resxml="MANAGER_APPTITLE"></span>
|
||||
</li>
|
||||
<script>
|
||||
(function($) {
|
||||
@@ -117,7 +167,7 @@
|
||||
<ul class="list">
|
||||
<li id="tag-manager">
|
||||
<div role="img"></div>
|
||||
<span class="win-type-base">管理</span>
|
||||
<span class="win-type-base" data-res-resxml="MANAGER_MANAGE"></span>
|
||||
</li>
|
||||
<li id="tag-appinfo" class="subitem">
|
||||
<div role="img"></div>
|
||||
@@ -134,6 +184,39 @@
|
||||
</div>
|
||||
<div class="win-overlay win-commandlayout win-appbar win-bottom appbar win-ui-dark" id="appBar" role="menubar">
|
||||
</div>
|
||||
<div data-win-control="WinJS.UI.Flyout" id="app-uninstall-flyout" style="position: absolute; width: 336px; padding: 0; max-height: 284px;">
|
||||
<div class="top" style="padding: 20px 20px 0 20px;">
|
||||
<span data-res-resxml="MANAGER_APP_UNINSTALL_DESC"></span>
|
||||
</div>
|
||||
<div class="sapplist applist"></div>
|
||||
<style>
|
||||
#app-uninstall-flyout {
|
||||
/*min-height: 88px;
|
||||
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);*/
|
||||
}
|
||||
|
||||
#app-uninstall-flyout .sapplist {
|
||||
padding: 0 20px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-ms-overflow-style: -ms-autohiding-scrollbar;
|
||||
max-height: 160px;
|
||||
}
|
||||
</style>
|
||||
<div class="bottom" style="padding: 20px 20px 20px 20px; height: 32px;">
|
||||
<button class="confirm" data-res-resxml="MANAGER_APP_UNINSTALL" style="float: right;"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-deskshortcut-create" style="position: absolute;">
|
||||
<p>即将在桌面创建快捷方式,这里做一些调整。快捷方式不建议固定到开始菜单中,因为本快捷方式只是一种启动器。不具有其余磁贴功能。</p>
|
||||
<div>
|
||||
<div>
|
||||
<div class="win-radio"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -32,6 +32,7 @@
|
||||
}
|
||||
|
||||
.appitem div[role=img] {
|
||||
position: relative;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background-color: #464646;
|
||||
@@ -58,6 +59,16 @@
|
||||
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);
|
||||
}
|
||||
|
||||
.appitem div[role=img]::after {
|
||||
border: 1px solid rgba(254, 254, 254, 0.1);
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.appitem div[role=img] img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
@@ -113,6 +124,11 @@
|
||||
width: calc(100% - 40px - 10px);
|
||||
}
|
||||
|
||||
.appitem div[role=excepticon] div[role=progress] {
|
||||
display: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.appitem div[role=excepticon] div[role=control] {
|
||||
display: none;
|
||||
/* IE10 */
|
||||
@@ -136,11 +152,45 @@
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.appitem div[role=excepticon] div[role=progress] {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.appitem.uninstalling,
|
||||
.appitem.selected {
|
||||
height: 119px;
|
||||
background-color: rgba(232, 232, 232, 1);
|
||||
}
|
||||
|
||||
.appitem.uninstalled div[role=excepticon] div[role=progress],
|
||||
.appitem.uninstalling div[role=excepticon] div[role=progress] {
|
||||
display: block;
|
||||
flex: 1 0 auto;
|
||||
-ms-flex: 1 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.appitem.uninstalling div[role=excepticon] div[role=progress] progress {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.appitem.uninstalled div[role=excepticon] div[role=progress] progress {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.appitem.uninstalling div[role=excepticon] div[role=progress],
|
||||
.appitem.uninstalled div[role=excepticon] div[role=progress],
|
||||
.appitem.uninstalling div[role=excepticon] div[role=progress] .status,
|
||||
.appitem.uninstalled div[role=excepticon] div[role=progress] .status {
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.appitem.uninstalled {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.appitem.selected div[role=excepticon] div[role=control] {
|
||||
display: flex;
|
||||
display: -ms-flexbox;
|
||||
@@ -148,6 +198,23 @@
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.appitem.uninstalling div[role=excepticon] div[role=advance],
|
||||
.appitem.uninstalling div[role=excepticon] div[role=control],
|
||||
.appitem.uninstalling.selected div[role=excepticon] div[role=advance],
|
||||
.appitem.uninstalling.selected div[role=excepticon] div[role=control],
|
||||
.appitem.uninstalled div[role=excepticon] div[role=advance],
|
||||
.appitem.uninstalled div[role=excepticon] div[role=control],
|
||||
.appitem.uninstalled.selected div[role=excepticon] div[role=advance],
|
||||
.appitem.uninstalled.selected div[role=excepticon] div[role=control] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.appitem.uninstalling div[role=excepticon] div[role=title],
|
||||
.appitem.uninstalled div[role=excepticon] div[role=title] {
|
||||
-ms-flex: none;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
ul.appitem-list,
|
||||
ul.appitem-list li {
|
||||
margin: 0;
|
||||
@@ -169,6 +236,11 @@ ul.appitem-list li {
|
||||
}
|
||||
|
||||
.app-loading {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.app-loading .container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
@@ -176,7 +248,17 @@ ul.appitem-list li {
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
/*****/
|
||||
display: -ms-flexbox;
|
||||
/* IE10 */
|
||||
-ms-flex-direction: row;
|
||||
/* flex-direction: row */
|
||||
-ms-flex-wrap: wrap;
|
||||
/* flex-wrap: wrap */
|
||||
-ms-flex-pack: start;
|
||||
/* justify-content: flex-start */
|
||||
-ms-flex-align: center;
|
||||
/* align-items: center */
|
||||
}
|
||||
|
||||
.app-loading.noloading progress {
|
||||
@@ -204,6 +286,13 @@ ul.appitem-list li {
|
||||
height: 67px;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
display: -ms-flexbox;
|
||||
-ms-flex-direction: row;
|
||||
/* flex-direction: row */
|
||||
-ms-flex-wrap: nowrap;
|
||||
/* flex-wrap: nowrap */
|
||||
-ms-flex-pack: start;
|
||||
/* justify-content: flex-start */
|
||||
}
|
||||
|
||||
.app-detailpage header .win-backbutton {
|
||||
@@ -222,4 +311,92 @@ ul.appitem-list li {
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.app-detailpage .identity,
|
||||
.app-detailpage .publisher-display-name,
|
||||
.app-detailpage .version,
|
||||
.app-detailpage .description {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.loadingstatus {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.loadingstatus .container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-content: center;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
/* IE10 */
|
||||
display: -ms-flexbox;
|
||||
-ms-flex-direction: row;
|
||||
/* flex-direction: row */
|
||||
-ms-flex-wrap: wrap;
|
||||
/* flex-wrap: wrap */
|
||||
-ms-flex-pack: start;
|
||||
/* justify-content: flex-start */
|
||||
-ms-flex-align: center;
|
||||
/* align-items: center */
|
||||
}
|
||||
|
||||
.loadingstatus.noloading progress {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.loadingstatus .title {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.loadingstatus.noloading .title {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.applist-options {
|
||||
margin: 10px 0 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
/* IE10 */
|
||||
display: -ms-flexbox;
|
||||
-ms-flex-direction: row;
|
||||
/* flex-direction: row */
|
||||
-ms-flex-wrap: wrap;
|
||||
/* flex-wrap: wrap */
|
||||
-ms-flex-pack: start;
|
||||
/* justify-content: flex-start */
|
||||
-ms-flex-align: center;
|
||||
/* align-items: center */
|
||||
}
|
||||
|
||||
.applist-options .item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
align-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin-right: 20px;
|
||||
/* IE10 */
|
||||
display: -ms-flexbox;
|
||||
-ms-flex-direction: row;
|
||||
/* flex-direction: row */
|
||||
-ms-flex-wrap: nowrap;
|
||||
/* flex-wrap: nowrap */
|
||||
-ms-flex-pack: start;
|
||||
/* justify-content: flex-start */
|
||||
-ms-flex-align: center;
|
||||
/* align-items: center */
|
||||
}
|
||||
|
||||
.applist-options .item input[type="checkbox"] {
|
||||
margin-left: 0;
|
||||
}
|
||||
Reference in New Issue
Block a user