mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
403 lines
13 KiB
JavaScript
403 lines
13 KiB
JavaScript
(function(global) {
|
||
"use strict";
|
||
|
||
if (!global.Windows) global.Windows = {};
|
||
if (!global.Windows.UI) global.Windows.UI = {};
|
||
if (!global.Windows.UI.Event) global.Windows.UI.Event = {};
|
||
|
||
var Monitor = (function() {
|
||
var _sIdAttr = "data-monitor-id";
|
||
var _idCounter = 1;
|
||
var _aRegistry = {};
|
||
var _typeRegistry = {}; // 按事件类型分类缓存
|
||
var _polling = false;
|
||
var _loopHandle = null;
|
||
var _cleanupThreshold = 30000; // 30秒清理一次
|
||
var _lastCleanup = Date.now();
|
||
var _checkInterval = 200; // 节流时间
|
||
var _eventTypes = [
|
||
"resize",
|
||
"position",
|
||
"attribute",
|
||
"child"
|
||
];
|
||
|
||
// 缓存 DOM 元素引用
|
||
var _elementCache = {};
|
||
|
||
function _ensureId(el) {
|
||
if (!el.getAttribute(_sIdAttr)) {
|
||
el.setAttribute(_sIdAttr, "monitor_" + (_idCounter++));
|
||
}
|
||
return el.getAttribute(_sIdAttr);
|
||
}
|
||
|
||
function _getElementById(id) {
|
||
if (_elementCache[id] && _elementCache[id].parentNode) {
|
||
return _elementCache[id];
|
||
}
|
||
var el = document.querySelector("[" + _sIdAttr + "=\"" + id + "\"]");
|
||
if (el) _elementCache[id] = el;
|
||
return el;
|
||
}
|
||
|
||
function _getAttrSnapshot(el) {
|
||
var attrs = {};
|
||
for (var i = 0; i < el.attributes.length; i++) {
|
||
var attr = el.attributes[i];
|
||
attrs[attr.name] = attr.value;
|
||
}
|
||
attrs["_rect"] = el.getBoundingClientRect();
|
||
return attrs;
|
||
}
|
||
|
||
function _hasChanged(snapshotA, snapshotB) {
|
||
for (var key in snapshotA) {
|
||
if (snapshotA.hasOwnProperty(key)) {
|
||
if (key === "_rect") {
|
||
var a = snapshotA[key],
|
||
b = snapshotB[key];
|
||
if (!b || a.top !== b.top || a.left !== b.left || a.width !== b.width || a.height !== b.height) {
|
||
return true;
|
||
}
|
||
} else {
|
||
if (snapshotA[key] !== snapshotB[key]) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function _pollOnce() {
|
||
var now = Date.now();
|
||
|
||
// 按事件类型遍历,减少不必要检查
|
||
for (var type in _typeRegistry) {
|
||
if (!_typeRegistry.hasOwnProperty(type)) continue;
|
||
|
||
var list = _typeRegistry[type];
|
||
for (var i = 0; i < list.length; i++) {
|
||
var item = list[i];
|
||
var el = _getElementById(item.id);
|
||
if (!el) {
|
||
list.splice(i--, 1);
|
||
delete _elementCache[item.id];
|
||
continue;
|
||
}
|
||
|
||
var newSnapshot = _getAttrSnapshot(el);
|
||
if (_hasChanged(item.snapshot, newSnapshot)) {
|
||
item.snapshot = newSnapshot;
|
||
try {
|
||
item.callback.call(el, { type: type });
|
||
} catch (ex) {
|
||
console.error("Monitor callback error:", ex);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 清理过期节点
|
||
if (now - _lastCleanup > _cleanupThreshold) {
|
||
_cleanup();
|
||
_lastCleanup = now;
|
||
}
|
||
}
|
||
|
||
function _startLoop() {
|
||
if (_polling) return;
|
||
_polling = true;
|
||
|
||
function loop() {
|
||
_pollOnce();
|
||
_loopHandle = global.requestAnimationFrame ? requestAnimationFrame(loop) : setTimeout(loop, _checkInterval);
|
||
}
|
||
loop();
|
||
}
|
||
|
||
function _stopLoop() {
|
||
_polling = false;
|
||
if (_loopHandle) {
|
||
if (global.cancelAnimationFrame) cancelAnimationFrame(_loopHandle);
|
||
else clearTimeout(_loopHandle);
|
||
_loopHandle = null;
|
||
}
|
||
}
|
||
|
||
function _cleanup() {
|
||
for (var type in _typeRegistry) {
|
||
if (!_typeRegistry.hasOwnProperty(type)) continue;
|
||
var list = _typeRegistry[type];
|
||
for (var i = 0; i < list.length; i++) {
|
||
if (!_getElementById(list[i].id)) {
|
||
list.splice(i--, 1);
|
||
delete _elementCache[list[i].id];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
function observe(el, type, callback) {
|
||
if (_eventTypes.indexOf(type) < 0) throw new Error("Unsupported event type: " + type);
|
||
var id = _ensureId(el);
|
||
if (!_typeRegistry[type]) _typeRegistry[type] = [];
|
||
_typeRegistry[type].push({
|
||
id: id,
|
||
callback: callback,
|
||
snapshot: _getAttrSnapshot(el)
|
||
});
|
||
_startLoop();
|
||
}
|
||
|
||
function detach(el, type, callback) {
|
||
if (!_typeRegistry[type]) return;
|
||
var id = el.getAttribute(_sIdAttr);
|
||
if (!id) return;
|
||
var list = _typeRegistry[type];
|
||
for (var i = 0; i < list.length; i++) {
|
||
if (list[i].id === id && (!callback || list[i].callback === callback)) {
|
||
list.splice(i--, 1);
|
||
delete _elementCache[id];
|
||
}
|
||
}
|
||
}
|
||
|
||
function clearAll() {
|
||
_typeRegistry = {};
|
||
_elementCache = {};
|
||
_stopLoop();
|
||
}
|
||
|
||
return {
|
||
/**
|
||
* 监听元素变化,并触发回调函数。
|
||
* @param {Element} el 目标元素
|
||
* @param {string} type 事件类型,如 "resize", "position", "attribute", "child"
|
||
* @param {function} callback 回调函数,参数为事件对象
|
||
*/
|
||
observe: observe,
|
||
/**
|
||
* 取消监听元素变化。
|
||
* @param {Element} el 目标元素
|
||
* @param {string} type 事件类型,如 "resize", "position", "attribute", "child"
|
||
* @param {function} [callback] 回调函数,如果指定,则只移除指定的回调函数,否则移除所有回调函数。
|
||
*/
|
||
detach: detach,
|
||
/**
|
||
* 清除所有监听。
|
||
*/
|
||
clearAll: clearAll,
|
||
/**
|
||
* 事件类型枚举。
|
||
*/
|
||
EventType: {
|
||
/** 元素尺寸变化 */
|
||
resize: "resize",
|
||
/** 元素位置变化 */
|
||
position: "position",
|
||
/** 元素属性变化 */
|
||
attribute: "attribute",
|
||
/** 子元素变化 */
|
||
child: "child"
|
||
}
|
||
};
|
||
})();
|
||
|
||
global.Windows.UI.Event.Monitor = Monitor;
|
||
|
||
})(window);
|
||
|
||
/*
|
||
|
||
// 1) 监听元素尺寸变化
|
||
var el = document.getElementById("box");
|
||
Windows.UI.Event.Monitor.observe(el, "resize", function (e) {
|
||
console.log("resized", e.oldValue, e.newValue, e.rect);
|
||
});
|
||
|
||
// 2) 监听属性变化
|
||
Windows.UI.Event.Monitor.observe(el, "attributeChange", function (e) {
|
||
console.log("attrs changed", e.detail); // detail.added / removed / changed
|
||
});
|
||
|
||
// 3) 监听附着/分离
|
||
Windows.UI.Event.Monitor.observe(el, "attach", function (e) {
|
||
console.log("attached to doc");
|
||
});
|
||
Windows.UI.Event.Monitor.observe(el, "detach", function (e) {
|
||
console.log("detached from doc");
|
||
});
|
||
|
||
// 4) 取消监听
|
||
Windows.UI.Event.Monitor.unobserve(el, "resize", handler);
|
||
|
||
*/
|
||
|
||
(function(global) {
|
||
"use strict";
|
||
|
||
var EventUtil = {};
|
||
|
||
/**
|
||
* 添加事件,兼容 IE10/IE11
|
||
* @param {Element|Window|Document} el 目标元素
|
||
* @param {string} sType 事件类型,如 "click", "resize", "scroll"
|
||
* @param {function} pfHandler 回调函数
|
||
* @param {boolean} [bUseCapture] 是否捕获阶段,默认 false
|
||
*/
|
||
EventUtil.addEvent = function(el, sType, pfHandler, bUseCapture) {
|
||
if (!el || typeof sType !== "string" || typeof pfHandler !== "function") return;
|
||
|
||
bUseCapture = !!bUseCapture;
|
||
|
||
if (el.addEventListener) {
|
||
// 标准方式
|
||
el.addEventListener(sType, pfHandler, bUseCapture);
|
||
} else if (el.attachEvent) {
|
||
// IE8-9 fallback
|
||
el.attachEvent("on" + sType, pfHandler);
|
||
} else {
|
||
// 最原始方式
|
||
var oldHandler = el["on" + sType];
|
||
el["on" + sType] = function(e) {
|
||
if (oldHandler) oldHandler(e || window.event);
|
||
pfHandler(e || window.event);
|
||
};
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 移除事件,兼容 IE10/IE11
|
||
* @param {Element|Window|Document} el 目标元素
|
||
* @param {string} sType 事件类型,如 "click", "resize", "scroll"
|
||
* @param {function} pfHandler 回调函数
|
||
* @param {boolean} [bUseCapture] 是否捕获阶段,默认 false
|
||
*/
|
||
EventUtil.removeEvent = function(el, sType, pfHandler, bUseCapture) {
|
||
if (!el || typeof sType !== "string" || typeof pfHandler !== "function") return;
|
||
|
||
bUseCapture = !!bUseCapture;
|
||
|
||
if (el.removeEventListener) {
|
||
el.removeEventListener(sType, pfHandler, bUseCapture);
|
||
} else if (el.detachEvent) {
|
||
el.detachEvent("on" + sType, pfHandler);
|
||
} else {
|
||
var oldHandler = el["on" + sType];
|
||
if (oldHandler === pfHandler) {
|
||
el["on" + sType] = null;
|
||
}
|
||
}
|
||
};
|
||
|
||
// 暴露到全局命名空间
|
||
if (typeof module !== "undefined" && module.exports) {
|
||
module.exports = {
|
||
Windows: {
|
||
UI: {
|
||
Event: {
|
||
Util: EventUtil
|
||
}
|
||
}
|
||
}
|
||
};
|
||
} else {
|
||
global.Windows = global.Windows || {};
|
||
global.Windows.UI = global.Windows.UI || {};
|
||
global.Windows.UI.Event = global.Windows.UI.Event || {};
|
||
global.Windows.UI.Event.Util = EventUtil;
|
||
}
|
||
|
||
})(this);
|
||
/*
|
||
使用示例:
|
||
var handler = function (e) {
|
||
console.log("事件触发", e.type);
|
||
};
|
||
|
||
// 添加事件
|
||
Windows.UI.Event.Util.addEvent(window, "resize", handler);
|
||
|
||
// 删除事件
|
||
Windows.UI.Event.Util.removeEvent(window, "resize", handler);
|
||
|
||
*/
|
||
(function(global) {
|
||
"use strict";
|
||
/**
|
||
*
|
||
* @param {function} fn
|
||
* @param {number} delay
|
||
* @param {boolean} immediate 是否在第一次立即执行(可选,默认 false)
|
||
* @returns {function} 返回一个新的函数,该函数在 delay 时间后执行 fn 函数,如果在 delay 时间内再次调用该函数,则会重新计时。
|
||
*/
|
||
function debounce(fn, delay, immediate) {
|
||
var timer = null;
|
||
var lastCall = 0;
|
||
return function() {
|
||
var context = this;
|
||
var args = arguments;
|
||
var now = +new Date();
|
||
var callNow = immediate && !timer;
|
||
if (now - lastCall >= delay) {
|
||
lastCall = now;
|
||
if (callNow) {
|
||
fn.apply(context, args);
|
||
}
|
||
}
|
||
clearTimeout(timer);
|
||
timer = setTimeout(function() {
|
||
lastCall = +new Date();
|
||
if (!immediate) {
|
||
fn.apply(context, args);
|
||
}
|
||
}, delay);
|
||
};
|
||
}
|
||
module.exports = { debounce: debounce };
|
||
})(this);
|
||
|
||
(function(global) {
|
||
"use strict";
|
||
|
||
var eToEvent = {}; // 存储元素和回调
|
||
var lastContent = {}; // 存储上一次的 textContent
|
||
|
||
// 注册文本变化事件
|
||
global.setTextChangeEvent = function(el, fn) {
|
||
if (!el || typeof fn !== "function") return;
|
||
|
||
var id = el.__textChangeId;
|
||
if (!id) {
|
||
id = Math.random().toString(36).substr(2, 9);
|
||
el.__textChangeId = id;
|
||
lastContent[id] = el.textContent;
|
||
}
|
||
|
||
eToEvent[id] = { el: el, callback: fn };
|
||
};
|
||
|
||
// 定时轮询
|
||
setInterval(function() {
|
||
var keys = Object.keys(eToEvent);
|
||
for (var i = 0; i < keys.length; i++) {
|
||
var key = keys[i];
|
||
var obj = eToEvent[key];
|
||
var el = obj.el;
|
||
var currentText = el.textContent;
|
||
|
||
if (currentText !== lastContent[key]) {
|
||
lastContent[key] = currentText;
|
||
try {
|
||
obj.callback.call(el, currentText);
|
||
} catch (e) {
|
||
// 忽略回调错误
|
||
if (typeof console !== "undefined") console.error(e);
|
||
}
|
||
}
|
||
}
|
||
}, 20);
|
||
|
||
})(this); |