mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
Update reader.
This commit is contained in:
@@ -1240,6 +1240,8 @@ namespace AppxPackage
|
||||
};
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class PRPrerequisites: BaseInfoSection, IPrerequisites
|
||||
{
|
||||
public PRPrerequisites (ref IntPtr hReader) : base (ref hReader) { }
|
||||
@@ -1487,7 +1489,7 @@ namespace AppxPackage
|
||||
}
|
||||
public static bool AddApplicationItem (string itemName) => PackageReadHelper.AddPackageApplicationItemGetName (itemName);
|
||||
public static bool RemoveApplicationItem (string itemName) => PackageReadHelper.RemovePackageApplicationItemGetName (itemName);
|
||||
public static string [] GetApplicationItem () => PackageReadHelper.GetApplicationItemNames ();
|
||||
public static string [] GetApplicationItems () => PackageReadHelper.GetApplicationItemNames ();
|
||||
public static void UpdateApplicationItems (IEnumerable<string> items) => PackageReadHelper.SetApplicationItemNames (items);
|
||||
public string BuildJsonForUse ()
|
||||
{
|
||||
|
||||
@@ -11,6 +11,8 @@ using ModernNotice;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bridge
|
||||
{
|
||||
@@ -762,6 +764,44 @@ namespace Bridge
|
||||
}
|
||||
public bool AddApplicationItem (string itemName) => PackageReader.AddApplicationItem (itemName);
|
||||
public bool RemoveApplicationItem (string itemName) => PackageReader.RemoveApplicationItem (itemName);
|
||||
private List<object> JsArrayToList (object jsArray)
|
||||
{
|
||||
var result = new List<object> ();
|
||||
|
||||
if (jsArray == null)
|
||||
return result;
|
||||
|
||||
// JS Array 有 length 属性和数字索引器
|
||||
var type = jsArray.GetType ();
|
||||
|
||||
int length = (int)type.InvokeMember (
|
||||
"length",
|
||||
BindingFlags.GetProperty,
|
||||
null,
|
||||
jsArray,
|
||||
null);
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
object value = type.InvokeMember (
|
||||
i.ToString (),
|
||||
BindingFlags.GetProperty,
|
||||
null,
|
||||
jsArray,
|
||||
null);
|
||||
|
||||
result.Add (value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
public void UpdateApplicationItems (object items)
|
||||
{
|
||||
var stritems = JsArrayToList (items).Select (e => e?.ToString ()).ToList ();
|
||||
PackageReader.UpdateApplicationItems (stritems);
|
||||
}
|
||||
public string [] GetApplicationItems () => PackageReader.GetApplicationItems ();
|
||||
public string GetApplicationItemsToJson () => JsonConvert.SerializeObject (GetApplicationItems ());
|
||||
// Cache about
|
||||
private const int MaxCacheItems = 64; // 最大缓存数量
|
||||
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes (30);
|
||||
@@ -895,6 +935,7 @@ namespace Bridge
|
||||
public _I_System System => system;
|
||||
public _I_Notice Notice => new _I_Notice ();
|
||||
public _I_Process Process => proc;
|
||||
public _I_Web Web => new _I_Web ();
|
||||
public string CmdArgs
|
||||
{
|
||||
get
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Download.cs" />
|
||||
<Compile Include="Enumerable.cs" />
|
||||
<Compile Include="HResult.cs" />
|
||||
<Compile Include="IE.cs" />
|
||||
<Compile Include="Locale.cs" />
|
||||
@@ -61,6 +62,7 @@
|
||||
<Compile Include="Utils.cs" />
|
||||
<Compile Include="Version.cs" />
|
||||
<Compile Include="VisualElements.cs" />
|
||||
<Compile Include="Web.cs" />
|
||||
<Compile Include="WebBrowser.cs" />
|
||||
<Compile Include="Window.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
159
DataUtils/Enumerable.cs
Normal file
159
DataUtils/Enumerable.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace DataUtils
|
||||
{
|
||||
[ComVisible (true)]
|
||||
[InterfaceType (ComInterfaceType.InterfaceIsDual)]
|
||||
public interface _I_Enumerable
|
||||
{
|
||||
int Length { get; set; }
|
||||
object this [int index] { get; set; }
|
||||
void Add (object value); // push
|
||||
void Push (object value);
|
||||
object Pop (); // 删除并返回末尾元素
|
||||
object Shift (); // 删除并返回开头元素
|
||||
void Unshift (object value); // 在开头插入
|
||||
void RemoveAt (int index); // 删除任意索引
|
||||
void Clear (); // 清空数组
|
||||
_I_Enumerable Slice (int start, int end); // 返回子数组
|
||||
void Splice (int start, int deleteCount, object [] items); // 删除并插入
|
||||
int IndexOf (object value); // 查找索引
|
||||
bool Includes (object value); // 是否包含
|
||||
void ForEach (object callback, bool suppressExceptions = false); // 遍历,callback(item, index)
|
||||
_I_Enumerable Concat (_I_Enumerable other); // 拼接
|
||||
string Join (string separator); // 转字符串
|
||||
object GetItem (int index); // 返回 { key, data } 或直接 data
|
||||
void SetAt (int index, object value); // 替换元素
|
||||
int IndexOfKey (int key); // 按内部 key 查找
|
||||
void Move (int index, int newIndex); // 移动元素
|
||||
void PushAll (object [] items); // 一次性 push 多个
|
||||
}
|
||||
public class _I_List: _I_Enumerable, IList
|
||||
{
|
||||
public _I_List (IEnumerable<object> initArr, bool readOnly = false, bool fixedSize = false, bool sync = true)
|
||||
{
|
||||
_list = initArr?.ToList () ?? new List<object> ();
|
||||
IsFixedSize = fixedSize;
|
||||
IsReadOnly = readOnly;
|
||||
IsSynchronized = sync;
|
||||
}
|
||||
protected List<object> _list;
|
||||
protected object _lock = new object ();
|
||||
public object this [int index] { get { return _list [index]; } set { _list [index] = value; } }
|
||||
public int Count => _list.Count;
|
||||
public bool IsFixedSize { get; }
|
||||
public bool IsReadOnly { get; }
|
||||
public bool IsSynchronized { get; }
|
||||
public int Length
|
||||
{
|
||||
get { return _list.Count; }
|
||||
set
|
||||
{
|
||||
if (!IsFixedSize && !IsReadOnly)
|
||||
{
|
||||
_list.Capacity = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
public object SyncRoot => _lock;
|
||||
public void Add (object value) => _list.Add (value);
|
||||
public void Push (object value) => _list.Add (value);
|
||||
public void RemoveAt (int index) => _list.RemoveAt (index);
|
||||
public void Clear () => _list.Clear ();
|
||||
public int IndexOf (object value) => _list.IndexOf (value);
|
||||
int IList.Add (object value)
|
||||
{
|
||||
_list.Add (value);
|
||||
return _list.Count - 1;
|
||||
}
|
||||
public bool Contains (object value) => _list.Contains (value);
|
||||
public void Insert (int index, object value) => _list.Insert (index, value);
|
||||
public void Remove (object value) => _list.Remove (value);
|
||||
public void ForEach (object callback, bool suppressExceptions = false)
|
||||
{
|
||||
for (int i = 0; i < _list.Count; i++)
|
||||
{
|
||||
var item = _list [i];
|
||||
if (suppressExceptions)
|
||||
{
|
||||
try { JsUtils.Call (callback, item, i); } catch { }
|
||||
}
|
||||
else JsUtils.Call (callback, item, i);
|
||||
}
|
||||
}
|
||||
public IEnumerator GetEnumerator () => _list.GetEnumerator ();
|
||||
public _I_Enumerable Slice (int start, int end)
|
||||
{
|
||||
if (end < 0) end = _list.Count + end;
|
||||
start = Math.Max (0, start);
|
||||
end = Math.Min (_list.Count, end);
|
||||
var arr = _list.GetRange (start, Math.Max (0, end - start));
|
||||
return new _I_List (arr);
|
||||
}
|
||||
public void Splice (int start, int deleteCount, object [] items)
|
||||
{
|
||||
if (start < 0) start = Math.Max (0, _list.Count + start);
|
||||
int count = Math.Min (deleteCount, _list.Count - start);
|
||||
_list.RemoveRange (start, count);
|
||||
if (items != null && items.Length > 0)
|
||||
_list.InsertRange (start, items);
|
||||
}
|
||||
public bool Includes (object value) => _list.Contains (value);
|
||||
public _I_Enumerable Concat (_I_Enumerable other)
|
||||
{
|
||||
var newList = new List<object> (_list);
|
||||
if (other is _I_List)
|
||||
newList.AddRange ((other as _I_List)._list);
|
||||
return new _I_List (newList);
|
||||
}
|
||||
public string Join (string separator)
|
||||
{
|
||||
return string.Join (separator ?? ",", _list.Select (x => x?.ToString () ?? ""));
|
||||
}
|
||||
public object GetItem (int index) => _list [index];
|
||||
public void SetAt (int index, object value) => _list [index] = value;
|
||||
public int IndexOfKey (int key)
|
||||
{
|
||||
return key >= 0 && key < _list.Count ? key : -1;
|
||||
}
|
||||
public void Move (int index, int newIndex)
|
||||
{
|
||||
if (index < 0 || index >= _list.Count || newIndex < 0 || newIndex >= _list.Count) return;
|
||||
var item = _list [index];
|
||||
_list.RemoveAt (index);
|
||||
_list.Insert (newIndex, item);
|
||||
}
|
||||
public void PushAll (object [] items)
|
||||
{
|
||||
if (items == null || items.Length == 0) return;
|
||||
_list.AddRange (items);
|
||||
}
|
||||
public void CopyTo (Array array, int index)
|
||||
{
|
||||
if (array == null) throw new ArgumentNullException (nameof (array));
|
||||
for (int i = 0; i < _list.Count && index + i < array.Length; i++)
|
||||
array.SetValue (_list [i], index + i);
|
||||
}
|
||||
public object Pop ()
|
||||
{
|
||||
if (_list.Count == 0) return null;
|
||||
var last = _list [_list.Count - 1];
|
||||
_list.RemoveAt (_list.Count - 1);
|
||||
return last;
|
||||
}
|
||||
public object Shift ()
|
||||
{
|
||||
if (_list.Count == 0) return null;
|
||||
var first = _list [0];
|
||||
_list.RemoveAt (0);
|
||||
return first;
|
||||
}
|
||||
public void Unshift (object value) => _list.Insert (0, value);
|
||||
}
|
||||
}
|
||||
@@ -131,6 +131,8 @@ namespace DataUtils
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_Process
|
||||
{
|
||||
public Process Start (string filename, string args) => Process.Start (filename, args);
|
||||
public Process Open (string url) => Process.Start (url);
|
||||
public int Run (
|
||||
string cmdline,
|
||||
string filepath,
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@@ -186,4 +190,194 @@ namespace DataUtils
|
||||
object BuildJSON ();
|
||||
}
|
||||
}
|
||||
public static class JsUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// 调用 JS 函数。第一个参数作为 this,其余作为 JS 函数参数。
|
||||
/// </summary>
|
||||
/// <param name="callback">JS 函数对象</param>
|
||||
/// <param name="args">JS 函数参数,可选</param>
|
||||
/// <returns>JS 函数返回值</returns>
|
||||
public static void Call (object jsFunc, params object [] args)
|
||||
{
|
||||
if (jsFunc == null) return;
|
||||
object [] invokeArgs = new object [(args?.Length ?? 0) + 1];
|
||||
invokeArgs [0] = jsFunc; // this
|
||||
if (args != null)
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
invokeArgs [i + 1] = args [i];
|
||||
jsFunc.GetType ().InvokeMember (
|
||||
"call",
|
||||
BindingFlags.InvokeMethod,
|
||||
null,
|
||||
jsFunc,
|
||||
invokeArgs);
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[InterfaceType (ComInterfaceType.InterfaceIsDual)]
|
||||
public interface _I_IAsyncAction
|
||||
{
|
||||
_I_IAsyncAction Then (object resolve, object reject = null, object progress = null);
|
||||
void Done (object resolve, object reject = null);
|
||||
void Catch (object reject);
|
||||
bool IsCompleted { get; }
|
||||
bool IsCancelled { get; }
|
||||
bool IsError { get; }
|
||||
void Cancel ();
|
||||
void ReportProgress (object progress);
|
||||
object Error { get; }
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_Task: _I_IAsyncAction
|
||||
{
|
||||
private object _result;
|
||||
private Exception _error;
|
||||
private bool _completed;
|
||||
private bool _cancelled;
|
||||
private List<object> _resolveCallbacks = new List<object> ();
|
||||
private List<object> _rejectCallbacks = new List<object> ();
|
||||
private List<object> _progressCallbacks = new List<object> ();
|
||||
private CancellationTokenSource _cts = new CancellationTokenSource ();
|
||||
public _I_Task (Func<object> func)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem (_ => {
|
||||
try
|
||||
{
|
||||
if (_cts.Token.IsCancellationRequested)
|
||||
{
|
||||
_cancelled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_result = func ();
|
||||
_completed = true;
|
||||
|
||||
foreach (var cb in _resolveCallbacks)
|
||||
JsUtils.Call (cb, _result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_error = ex;
|
||||
foreach (var cb in _rejectCallbacks)
|
||||
JsUtils.Call (cb, ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
public _I_IAsyncAction Then (object resolve, object reject = null, object progress = null)
|
||||
{
|
||||
if (resolve != null) _resolveCallbacks.Add (resolve);
|
||||
if (reject != null) _rejectCallbacks.Add (reject);
|
||||
if (progress != null) _progressCallbacks.Add (progress);
|
||||
return this;
|
||||
}
|
||||
public void Done (object resolve, object reject = null)
|
||||
{
|
||||
if (resolve != null) _resolveCallbacks.Add (resolve);
|
||||
if (reject != null) _rejectCallbacks.Add (reject);
|
||||
}
|
||||
|
||||
public void Catch (object reject)
|
||||
{
|
||||
if (reject != null) _rejectCallbacks.Add (reject);
|
||||
}
|
||||
|
||||
public bool IsCompleted => _completed;
|
||||
public bool IsCancelled => _cancelled;
|
||||
public bool IsError => _error != null;
|
||||
|
||||
public object Error => _error;
|
||||
|
||||
public void Cancel ()
|
||||
{
|
||||
_cts.Cancel ();
|
||||
_cancelled = true;
|
||||
}
|
||||
|
||||
public void ReportProgress (object progress)
|
||||
{
|
||||
foreach (var cb in _progressCallbacks)
|
||||
JsUtils.Call (cb, progress);
|
||||
}
|
||||
|
||||
public object Result => _result;
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_Thread: _I_IAsyncAction
|
||||
{
|
||||
private Thread _thread;
|
||||
private bool _completed;
|
||||
private bool _cancelled;
|
||||
private Exception _error;
|
||||
private List<object> _resolveCallbacks = new List<object> ();
|
||||
private List<object> _rejectCallbacks = new List<object> ();
|
||||
private List<object> _progressCallbacks = new List<object> ();
|
||||
private CancellationTokenSource _cts = new CancellationTokenSource ();
|
||||
|
||||
public _I_Thread (Action action)
|
||||
{
|
||||
_thread = new Thread (() => {
|
||||
try
|
||||
{
|
||||
if (_cts.Token.IsCancellationRequested)
|
||||
{
|
||||
_cancelled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
action ();
|
||||
_completed = true;
|
||||
|
||||
foreach (var cb in _resolveCallbacks)
|
||||
JsUtils.Call (cb);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_error = ex;
|
||||
foreach (var cb in _rejectCallbacks)
|
||||
JsUtils.Call (cb, ex);
|
||||
}
|
||||
});
|
||||
_thread.IsBackground = true;
|
||||
_thread.Start ();
|
||||
}
|
||||
|
||||
public _I_IAsyncAction Then (object resolve, object reject = null, object progress = null)
|
||||
{
|
||||
if (resolve != null) _resolveCallbacks.Add (resolve);
|
||||
if (reject != null) _rejectCallbacks.Add (reject);
|
||||
if (progress != null) _progressCallbacks.Add (progress);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Done (object resolve, object reject = null)
|
||||
{
|
||||
if (resolve != null) _resolveCallbacks.Add (resolve);
|
||||
if (reject != null) _rejectCallbacks.Add (reject);
|
||||
}
|
||||
|
||||
public void Catch (object reject)
|
||||
{
|
||||
if (reject != null) _rejectCallbacks.Add (reject);
|
||||
}
|
||||
|
||||
public bool IsCompleted => _completed;
|
||||
public bool IsCancelled => _cancelled;
|
||||
public bool IsError => _error != null;
|
||||
public object Error => _error;
|
||||
|
||||
public void Cancel ()
|
||||
{
|
||||
_cts.Cancel ();
|
||||
_cancelled = true;
|
||||
}
|
||||
|
||||
public void ReportProgress (object progress)
|
||||
{
|
||||
foreach (var cb in _progressCallbacks)
|
||||
JsUtils.Call (cb, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
321
DataUtils/Web.cs
Normal file
321
DataUtils/Web.cs
Normal file
@@ -0,0 +1,321 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace DataUtils
|
||||
{
|
||||
[ComVisible (true)]
|
||||
[InterfaceType (ComInterfaceType.InterfaceIsDual)]
|
||||
public interface IHttpResponse: IDisposable
|
||||
{
|
||||
int Status { get; } // 兼容旧版,等同于 StatusCode
|
||||
int StatusCode { get; }
|
||||
string StatusText { get; } // 等同于 StatusDescription
|
||||
string StatusDescription { get; }
|
||||
string ResponseUrl { get; }
|
||||
Uri ResponseUri { get; }
|
||||
string ContentType { get; }
|
||||
long ContentLength { get; } // 注意:JS 中 Number 可表示 2^53 以内整数
|
||||
string CharacterSet { get; }
|
||||
string ContentEncoding { get; }
|
||||
DateTime LastModified { get; }
|
||||
string Method { get; } // 原始请求方法 (GET, POST...)
|
||||
Version ProtocolVersion { get; } // 如 1.1,JS 中可能转为字符串
|
||||
bool IsFromCache { get; }
|
||||
bool IsMutuallyAuthenticated { get; }
|
||||
string Text ();
|
||||
_I_Enumerable Bytes ();
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class HttpResponse: IHttpResponse, IDisposable
|
||||
{
|
||||
private readonly byte [] _data;
|
||||
private readonly Dictionary<string, string> _headersDict;
|
||||
private bool _disposed = false;
|
||||
public int Status => StatusCode;
|
||||
public int StatusCode { get; private set; }
|
||||
public string StatusText => StatusDescription;
|
||||
public string StatusDescription { get; private set; }
|
||||
public string ResponseUrl => ResponseUri?.ToString ();
|
||||
public Uri ResponseUri { get; private set; }
|
||||
public string ContentType { get; private set; }
|
||||
public long ContentLength { get; private set; }
|
||||
public string CharacterSet { get; private set; }
|
||||
public string ContentEncoding { get; private set; }
|
||||
public DateTime LastModified { get; private set; }
|
||||
public string Method { get; private set; }
|
||||
public Version ProtocolVersion { get; private set; }
|
||||
public bool IsFromCache { get; private set; }
|
||||
public bool IsMutuallyAuthenticated { get; private set; }
|
||||
public HttpResponse (HttpWebResponse response)
|
||||
{
|
||||
if (response == null) throw new ArgumentNullException (nameof (response));
|
||||
using (var stream = response.GetResponseStream ())
|
||||
using (var ms = new MemoryStream ())
|
||||
{
|
||||
stream.CopyTo (ms);
|
||||
_data = ms.ToArray ();
|
||||
}
|
||||
StatusCode = (int)response.StatusCode;
|
||||
StatusDescription = response.StatusDescription;
|
||||
ResponseUri = response.ResponseUri;
|
||||
Method = response.Method;
|
||||
ProtocolVersion = new Version ((ushort)response.ProtocolVersion.Major, (ushort)response.ProtocolVersion.Minor, (ushort)response.ProtocolVersion.Build, (ushort)response.ProtocolVersion.Revision);
|
||||
IsFromCache = response.IsFromCache;
|
||||
IsMutuallyAuthenticated = response.IsMutuallyAuthenticated;
|
||||
ContentType = response.ContentType ?? "";
|
||||
ContentLength = response.ContentLength;
|
||||
CharacterSet = response.CharacterSet ?? "";
|
||||
ContentEncoding = response.ContentEncoding ?? "";
|
||||
LastModified = response.LastModified;
|
||||
_headersDict = new Dictionary<string, string> (StringComparer.OrdinalIgnoreCase);
|
||||
foreach (string key in response.Headers.AllKeys)
|
||||
{
|
||||
if (!string.IsNullOrEmpty (key))
|
||||
_headersDict [key] = response.Headers [key];
|
||||
}
|
||||
}
|
||||
public HttpResponse (int statusCode, string statusDescription, string responseUrl, byte [] data, Dictionary<string, string> headers)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
StatusDescription = statusDescription ?? "";
|
||||
ResponseUri = string.IsNullOrEmpty (responseUrl) ? null : new Uri (responseUrl);
|
||||
_data = data ?? new byte [0];
|
||||
_headersDict = headers ?? new Dictionary<string, string> ();
|
||||
ContentType = GetHeader ("Content-Type") ?? "";
|
||||
ContentLength = _data.Length;
|
||||
CharacterSet = "";
|
||||
ContentEncoding = "";
|
||||
LastModified = DateTime.MinValue;
|
||||
Method = "";
|
||||
ProtocolVersion = new Version (0, 0);
|
||||
IsFromCache = false;
|
||||
IsMutuallyAuthenticated = false;
|
||||
}
|
||||
public string GetHeader (string sName)
|
||||
{
|
||||
if (string.IsNullOrEmpty (sName)) return null;
|
||||
try
|
||||
{
|
||||
return _headersDict [sName];
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
public string GetHeadersToJson ()
|
||||
{
|
||||
return JsonConvert.SerializeObject (_headersDict);
|
||||
}
|
||||
public string Text ()
|
||||
{
|
||||
string charset = CharacterSet;
|
||||
Encoding enc = Encoding.UTF8;
|
||||
if (!string.IsNullOrEmpty (charset))
|
||||
{
|
||||
try { enc = Encoding.GetEncoding (charset); }
|
||||
catch { /* 保持 UTF-8 */ }
|
||||
}
|
||||
return enc.GetString (_data);
|
||||
}
|
||||
public _I_Enumerable Bytes ()
|
||||
{
|
||||
var list = new List<object> ();
|
||||
foreach (byte b in _data)
|
||||
list.Add (b);
|
||||
return new _I_List (list);
|
||||
}
|
||||
public void Dispose ()
|
||||
{
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class HttpRequest: IDisposable
|
||||
{
|
||||
private string _method;
|
||||
private string _url;
|
||||
private Dictionary<string, string> _headers = new Dictionary<string, string> ();
|
||||
public int Timeout { get; set; } = 100000; // 毫秒,默认 100 秒
|
||||
public int ReadWriteTimeout { get; set; } = 300000; // 读写超时,默认 5 分钟
|
||||
public bool AllowAutoRedirect { get; set; } = true;
|
||||
public bool AllowWriteStreamBuffering { get; set; } = true;
|
||||
public bool KeepAlive { get; set; } = true;
|
||||
public int MaximumAutomaticRedirections { get; set; } = 50;
|
||||
public string UserAgent
|
||||
{
|
||||
get { return GetHeader ("User-Agent"); }
|
||||
set { SetHeader ("User-Agent", value); }
|
||||
}
|
||||
public string Referer
|
||||
{
|
||||
get { return GetHeader ("Referer"); }
|
||||
set { SetHeader ("Referer", value); }
|
||||
}
|
||||
public string ContentType
|
||||
{
|
||||
get { return GetHeader ("Content-Type"); }
|
||||
set { SetHeader ("Content-Type", value); }
|
||||
}
|
||||
public string Accept
|
||||
{
|
||||
get { return GetHeader ("Accept"); }
|
||||
set { SetHeader ("Accept", value); }
|
||||
}
|
||||
public IWebProxy Proxy { get; set; } = null;
|
||||
public CookieContainer CookieContainer { get; set; } = null;
|
||||
private string _httpver = "1.1";
|
||||
public string ProtocolVersion
|
||||
{
|
||||
get { return _httpver; }
|
||||
set { _httpver = value; }
|
||||
}
|
||||
public System.Version ProtVer
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (_httpver)
|
||||
{
|
||||
case "1.0": return HttpVersion.Version10;
|
||||
default:
|
||||
case "1.1": return HttpVersion.Version11;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool PreAuthenticate { get; set; } = false;
|
||||
public ICredentials Credentials { get; set; } = null;
|
||||
public bool AutomaticDecompression { get; set; } = false;
|
||||
public Action<long, long> UploadProgressCallback { get; set; } = null;
|
||||
public void Open (string sMethod, string sUrl)
|
||||
{
|
||||
_method = sMethod;
|
||||
_url = sUrl;
|
||||
}
|
||||
public void SetHeader (string sName, string sValue) => _headers [sName] = sValue;
|
||||
public string GetHeader (string sName) => _headers [sName];
|
||||
public string GetHeadersToJson () => JsonConvert.SerializeObject (_headers);
|
||||
public void RemoveHeader (string sName) => _headers.Remove (sName);
|
||||
public void ClearHeader () => _headers.Clear ();
|
||||
public IHttpResponse Send (string sBody, string encoding)
|
||||
{
|
||||
var req = (HttpWebRequest)WebRequest.Create (_url);
|
||||
req.Method = _method;
|
||||
req.Timeout = Timeout;
|
||||
req.ReadWriteTimeout = ReadWriteTimeout;
|
||||
req.AllowAutoRedirect = AllowAutoRedirect;
|
||||
req.AllowWriteStreamBuffering = AllowWriteStreamBuffering;
|
||||
req.KeepAlive = KeepAlive;
|
||||
req.MaximumAutomaticRedirections = MaximumAutomaticRedirections;
|
||||
if (Proxy != null) req.Proxy = Proxy;
|
||||
if (CookieContainer != null) req.CookieContainer = CookieContainer;
|
||||
req.ProtocolVersion = ProtVer;
|
||||
req.PreAuthenticate = PreAuthenticate;
|
||||
if (Credentials != null) req.Credentials = Credentials;
|
||||
if (AutomaticDecompression)
|
||||
req.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
|
||||
if (_headers.ContainsKey ("User-Agent"))
|
||||
req.UserAgent = _headers ["User-Agent"];
|
||||
foreach (var h in _headers)
|
||||
{
|
||||
if (string.Equals (h.Key, "User-Agent", StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
if (string.Equals (h.Key, "Content-Type", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string ct = h.Value;
|
||||
if (!string.IsNullOrEmpty (sBody) && !ct.Contains ("charset"))
|
||||
{
|
||||
Encoding enc = Encoding.GetEncoding (encoding);
|
||||
ct = ct + "; charset=" + enc.WebName;
|
||||
}
|
||||
req.ContentType = ct;
|
||||
}
|
||||
else if (string.Equals (h.Key, "Accept", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
req.Accept = h.Value;
|
||||
}
|
||||
else if (string.Equals (h.Key, "Referer", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
req.Referer = h.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
req.Headers [h.Key] = h.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有显式设置 Content-Type 且是 POST/PUT 且有请求体,设置默认值
|
||||
bool hasContentType = _headers.Keys.Any (k => string.Equals (k, "Content-Type", StringComparison.OrdinalIgnoreCase));
|
||||
if (!hasContentType && (string.Equals (_method, "POST", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals (_method, "PUT", StringComparison.OrdinalIgnoreCase)) &&
|
||||
!string.IsNullOrEmpty (sBody))
|
||||
{
|
||||
Encoding enc = Encoding.GetEncoding (encoding);
|
||||
req.ContentType = "application/x-www-form-urlencoded; charset=" + enc.WebName;
|
||||
}
|
||||
|
||||
// 写入请求体
|
||||
if (!string.IsNullOrEmpty (sBody))
|
||||
{
|
||||
Encoding enc = Encoding.GetEncoding (encoding);
|
||||
byte [] bytes = enc.GetBytes (sBody);
|
||||
req.ContentLength = bytes.Length;
|
||||
using (var stream = req.GetRequestStream ())
|
||||
{
|
||||
if (UploadProgressCallback != null)
|
||||
{
|
||||
int totalWritten = 0;
|
||||
int bufferSize = 8192;
|
||||
for (int offset = 0; offset < bytes.Length; offset += bufferSize)
|
||||
{
|
||||
int chunkSize = Math.Min (bufferSize, bytes.Length - offset);
|
||||
stream.Write (bytes, offset, chunkSize);
|
||||
totalWritten += chunkSize;
|
||||
UploadProgressCallback (totalWritten, bytes.Length);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.Write (bytes, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
using (var res = (HttpWebResponse)req.GetResponse ())
|
||||
{
|
||||
return new HttpResponse (res);
|
||||
}
|
||||
}
|
||||
public void SendAsync (string sBody, string encoding, object pfResolve)
|
||||
{
|
||||
System.Threading.ThreadPool.QueueUserWorkItem (delegate
|
||||
{
|
||||
JsUtils.Call (pfResolve, Send (sBody, encoding));
|
||||
});
|
||||
}
|
||||
public void Dispose () { }
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_Http
|
||||
{
|
||||
public HttpRequest CreateHttpRequest () => new HttpRequest ();
|
||||
}
|
||||
[ComVisible (true)]
|
||||
[ClassInterface (ClassInterfaceType.AutoDual)]
|
||||
public class _I_Web
|
||||
{
|
||||
public _I_Http Http => new _I_Http ();
|
||||
}
|
||||
}
|
||||
@@ -60,9 +60,9 @@ namespace WAShell
|
||||
if (!issetdpi)
|
||||
{
|
||||
issetdpi = true;
|
||||
ExecScript ("Bridge.Frame.scale = Bridge.Frame.scale * Bridge.UI.dpi");
|
||||
ExecScript ("if (typeof Bridge !== \"undefined\") Bridge.Frame.scale = Bridge.Frame.scale * Bridge.UI.dpi");
|
||||
}
|
||||
ExecScript ("Windows.UI.DPI.mode = 1");
|
||||
ExecScript ("if (typeof Windows !== \"undefined\") Windows.UI.DPI.mode = 1");
|
||||
if (e.Url.ToString () == webui.Url.ToString ())
|
||||
{
|
||||
splash.FadeOut ();
|
||||
|
||||
@@ -49,6 +49,17 @@ bool IsURI (const std::wstring &str)
|
||||
}
|
||||
catch (...) { return false; }
|
||||
}
|
||||
std::wstring TrimQuotes (const std::wstring& str) {
|
||||
if (str.empty ()) return str;
|
||||
size_t len = str.size ();
|
||||
size_t start = (str.front () == L'"') ? 1 : 0;
|
||||
size_t end = len;
|
||||
if (str.back () == L'"')
|
||||
{
|
||||
if (end > start) end = len - 1;
|
||||
}
|
||||
return str.substr (start, end - start);
|
||||
}
|
||||
enum class paramtype
|
||||
{
|
||||
string,
|
||||
@@ -87,6 +98,7 @@ void ParseCmdArgs (LPWSTR *argv, DWORD argc, std::map <cmdkey, cmdvalue> &parser
|
||||
arg = arg.trim ();
|
||||
if (IsFile (arg)) parseresult [cmdkey (arg, paramtype::file)] = cmdvalue {L"", paramtype::file, true};
|
||||
else if (IsURI (arg)) parseresult [cmdkey (arg, paramtype::uri)] = cmdvalue {L"", paramtype::uri, true};
|
||||
else if (IsFile (TrimQuotes (arg))) parseresult [cmdkey (TrimQuotes (arg), paramtype::file)] = cmdvalue { L"", paramtype::file, true };
|
||||
else
|
||||
{
|
||||
for (auto &it : g_argslist)
|
||||
@@ -140,6 +152,11 @@ void ParseCmdArgs (LPWSTR *argv, DWORD argc, std::map <cmdkey, cmdvalue> &parser
|
||||
auto value = rightpart.substr (valuehead);
|
||||
paramtype ptype = paramtype::string;
|
||||
if (IsFile (value)) ptype = paramtype::file;
|
||||
else if (IsFile (TrimQuotes (value)))
|
||||
{
|
||||
value = TrimQuotes (value);
|
||||
ptype = paramtype::file;
|
||||
}
|
||||
else if (IsURI (StringTrim (value))) ptype = paramtype::uri;
|
||||
parseresult [cmdkey (it.uniquelabel, paramtype::string)] = cmdvalue {value, ptype, false};
|
||||
}
|
||||
|
||||
@@ -396,7 +396,7 @@
|
||||
</div>
|
||||
<div class="controls">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="preinst-enablelaunch" class="win-checkbox">
|
||||
<input type="checkbox" id="preinst-enablelaunch" class="win-checkbox" style="margin-left: 0;">
|
||||
<label for="preinst-enablelaunch" data-res-byname="IDS_LAUNCHWHENREADY"></label>
|
||||
</div>
|
||||
<div class="command">
|
||||
|
||||
@@ -118,4 +118,12 @@
|
||||
return Bridge.String.toupper(this);
|
||||
};
|
||||
}
|
||||
if (typeof String.prototype.format !== "function") {
|
||||
String.prototype.format = function() {
|
||||
var args = arguments;
|
||||
return this.replace(/{(\d+)}/g, function(match, number) {
|
||||
return typeof args[number] !== "undefined" ? args[number] : match;
|
||||
});
|
||||
};
|
||||
}
|
||||
})(this);
|
||||
@@ -363,6 +363,19 @@
|
||||
));
|
||||
}
|
||||
};
|
||||
Object.defineProperty(this, "length", {
|
||||
get: function() {
|
||||
return _list.length;
|
||||
},
|
||||
enumerable: true,
|
||||
});
|
||||
this.getDatas = function() { return _list; }
|
||||
this.forEach = function(callback, args) {
|
||||
if (typeof callback !== "function") return;
|
||||
for (var i = 0; i < _list.length; i++) {
|
||||
callback.apply(this, [_list[i], i].concat(Array.prototype.slice.call(arguments, 1)));
|
||||
}
|
||||
};
|
||||
this._getKey = getKey;
|
||||
}
|
||||
var MAX_ANIMATE_COUNT = 100;
|
||||
@@ -609,10 +622,16 @@
|
||||
});
|
||||
PMDataListView.prototype._updateEmptyView = function() {
|
||||
if (!this._emptyView) return;
|
||||
|
||||
// container 中是否还有 item
|
||||
var hasItem = this.container.children.length > 0;
|
||||
|
||||
var itemVisibleLength = 0;
|
||||
for (var i = 0; i < this.container.children.length; i++) {
|
||||
var child = this.container.children[i];
|
||||
if (!child) continue;
|
||||
if (child.style.display !== "none" && child.style.display !== "hidden" && child.style.opacity !== 0 && child.style.visibility !== "hidden") {
|
||||
itemVisibleLength++;
|
||||
}
|
||||
}
|
||||
hasItem = hasItem && itemVisibleLength > 0;
|
||||
if (hasItem) {
|
||||
if (this._emptyView.parentNode) {
|
||||
this._emptyView.style.display = "none";
|
||||
@@ -802,6 +821,7 @@
|
||||
};
|
||||
PMDataListView.prototype.refresh = function() {
|
||||
this._refreshVisibility();
|
||||
this._updateEmptyView();
|
||||
};
|
||||
global.DataView.ChangeEvent = PMChangeEvent;
|
||||
global.DataView.DataSource = PMDataSource;
|
||||
|
||||
562
shared/html/js/dboxapi.js
Normal file
562
shared/html/js/dboxapi.js
Normal file
@@ -0,0 +1,562 @@
|
||||
/**
|
||||
* DBox API
|
||||
* Docs: https://dbox.tools/api/docs
|
||||
*/
|
||||
(function(global) {
|
||||
"use strict";
|
||||
|
||||
function joinUrl(url, path) {
|
||||
if (url.charAt(url.length - 1) === "/") {
|
||||
url = url.slice(0, -1);
|
||||
}
|
||||
if (path.charAt(0) === "/") {
|
||||
path = path.slice(1);
|
||||
}
|
||||
return url + "/" + path;
|
||||
}
|
||||
|
||||
function buildParams(params) {
|
||||
var queryString = "";
|
||||
var keys = Object.keys(params);
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var key = keys[i];
|
||||
var value = params[key];
|
||||
if (value === null || value === void 0) {
|
||||
continue;
|
||||
}
|
||||
queryString += encodeURIComponent(key) + "=" + encodeURIComponent(value) + "&";
|
||||
}
|
||||
return queryString.slice(0, -1);
|
||||
}
|
||||
var baseUrl = "https://dbox.tools/";
|
||||
var baseApiUrl = joinUrl(baseUrl, "api");
|
||||
var dboxApi = {
|
||||
/**
|
||||
* @enum {string} DBox.API.System
|
||||
* @readonly
|
||||
*/
|
||||
System: {
|
||||
/** @type {string} Xbox */
|
||||
xbox: "XBOX",
|
||||
/** @type {string} Xbox 360 */
|
||||
xbox360: "XBOX360",
|
||||
/** @type {string} Xbox One */
|
||||
xboxOne: "XBOXONE",
|
||||
/** @type {string} Xbox Series X */
|
||||
xboxSeriesX: "XBOXSERIESX",
|
||||
/** @type {string} PC */
|
||||
pc: "PC",
|
||||
/** @type {string} PS3 */
|
||||
mobile: "MOBILE"
|
||||
},
|
||||
Discs: {
|
||||
/**
|
||||
* Get and filter discs
|
||||
* @param {string | null} name query
|
||||
* @param {DBox.API.System} system query
|
||||
* @param {integer | number} [limit] query, default: 100
|
||||
* @param {integer | number} [offset] query, default: 0
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getDiscs: function(name, system, limit, offset) {
|
||||
var params = {};
|
||||
if (name) params.name = name;
|
||||
if (system) params.system = system;
|
||||
if (limit) params.limit = limit;
|
||||
if (offset) params.offset = offset;
|
||||
|
||||
return joinUrl(baseApiUrl, "discs") +
|
||||
"?" + buildParams(params);
|
||||
},
|
||||
/**
|
||||
* Get single disc by DBox ID
|
||||
* @param {integer | number} discId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleDiscById: function(discId) {
|
||||
return joinUrl(baseApiUrl, "discs/" + discId);
|
||||
},
|
||||
/**
|
||||
* Get single disc by Redump ID
|
||||
* @param {integer | number} redumpId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleDiscByRedumpId: function(redumpId) {
|
||||
return joinUrl(baseApiUrl, "discs/redump/" + redumpId);
|
||||
},
|
||||
/**
|
||||
* Get single disc by its XMID (OG XBOX only)
|
||||
* @param {string} xmid path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleDiscByXMId: function(xmid) {
|
||||
return joinUrl(baseApiUrl, "discs/xmid/" + xmid);
|
||||
},
|
||||
/**
|
||||
* Get single disc by its XeMID (XBOX 360 only)
|
||||
* @param {string} xeMid path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleDiscByXeMId: function(xeMid) {
|
||||
return joinUrl(baseApiUrl, "discs/xemid/" + xeMid);
|
||||
},
|
||||
/**
|
||||
* Get single disc by its media ID. Media ID v1 (XBOX & XBOX 360) and Media ID v2 (XBOX One & XBOX Series) are combined in a single query
|
||||
* @param {string} mediaId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleDiscByMediaId: function(mediaId) {
|
||||
return joinUrl(baseApiUrl, "discs/media_id/" + mediaId);
|
||||
},
|
||||
/**
|
||||
* Get the dirs and files (if available) for a disc. Filetype indicates if it is a supported filetype that has further metadata available in the database.
|
||||
* @param {integer | number} discId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getDiscFiles: function(discId) {
|
||||
return joinUrl(baseApiUrl, "discs/" + discId + "/files");
|
||||
}
|
||||
},
|
||||
Releases: {
|
||||
/**
|
||||
* Get and filter releases
|
||||
* @param {string | null} name query
|
||||
* @param {string | null} edition query
|
||||
* @param {string | null} barcode query
|
||||
* @param {DBox.API.System} system query
|
||||
* @param {integer | number} limit query, default: 100
|
||||
* @param {integer | number} offset query, default: 0
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getReleases: function(name, edition, barcode, system, limit, offset) {
|
||||
var params = {};
|
||||
if (name) params.name = name;
|
||||
if (edition) params.edition = edition;
|
||||
if (barcode) params.barcode = barcode;
|
||||
if (system) params.system = system;
|
||||
if (limit) params.limit = limit;
|
||||
if (offset) params.offset = offset;
|
||||
return joinUrl(baseApiUrl, "releases") +
|
||||
"?" + buildParams(params);
|
||||
},
|
||||
/**
|
||||
* Get single release by DBox ID
|
||||
* @param {string} releaseId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleRelease: function(releaseId) {
|
||||
return joinUrl(baseApiUrl, "releases/" + releaseId);
|
||||
}
|
||||
},
|
||||
Files: {
|
||||
/**
|
||||
* Get all discs that contain a particular file. NOTE: not all discs have been parsed on file-level yet
|
||||
* @param {string} md5 path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getFiles: function(md5) {
|
||||
return joinUrl(baseApiUrl, "files/" + md5 + "/discs");
|
||||
},
|
||||
/**
|
||||
* Filter all distinct xbe files. NOTE: not all discs have been parsed on file-level yet
|
||||
* @param {string | null} titleId query
|
||||
* @param {integer | null} allowrdMedia query
|
||||
* @param {integer | null} region query, Available values: 1, 2, 3, 4, 7, 2147483648
|
||||
* @param {integer | null} gameRating query
|
||||
* @param {integer | null} discNumber query
|
||||
* @param {integer | null} version query
|
||||
* @param {integer | number} limit query, default: 100
|
||||
* @param {integer | number} offset query, default: 0
|
||||
* @returns
|
||||
*/
|
||||
getXbeFiles: function(titleId, allowrdMedia, region, gameRating, discNumber, version, limit, offset) {
|
||||
if (region !== null && region !== undefined) {
|
||||
var valid = [1, 2, 3, 4, 7, 2147483648];
|
||||
if (!valid.includes(region)) throw new Error('Invalid region');
|
||||
}
|
||||
var params = {};
|
||||
if (titleId) params.title_id = titleId;
|
||||
if (allowrdMedia) params.allowrd_media = allowrdMedia;
|
||||
if (region) params.region = region;
|
||||
if (gameRating) params.game_rating = gameRating;
|
||||
if (discNumber) params.disc_number = discNumber;
|
||||
if (version) params.version = version;
|
||||
if (limit) params.limit = limit;
|
||||
if (offset) params.offset = offset;
|
||||
return joinUrl(baseApiUrl, "files/xbe") +
|
||||
"?" + buildParams(params);
|
||||
},
|
||||
/**
|
||||
* Get xbe file by md5. NOTE: not all discs have been parsed on file-level yet
|
||||
* @param {string} md5 path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getXbeFileByMd5: function(md5) {
|
||||
return joinUrl(baseApiUrl, "files/xbe/" + md5);
|
||||
},
|
||||
/**
|
||||
* Get stfs file by md5. NOTE: not all discs have been parsed on file-level yet
|
||||
* @param {string} md5 path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getStfsFileByMd5: function(md5) {
|
||||
return joinUrl(baseApiUrl, "files/stfs/" + md5);
|
||||
},
|
||||
},
|
||||
TitleIDs: {
|
||||
/**
|
||||
* Get and filter title IDs
|
||||
* @param {string | (string | null)} name query
|
||||
* @param {DBox.API.System | null} system query
|
||||
* @param {string | (string | null)($uuid)} bingId query
|
||||
* @param {string | (string | null)($uuid)} serviceConfigId query
|
||||
* @param {integer} limit query, default: 100
|
||||
* @param {integer} offset query, default: 0
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getTitleIds: function(name, system, bingId, serviceConfigId, limit, offset) {
|
||||
var params = {};
|
||||
if (name) params.name = name;
|
||||
if (system) params.system = system;
|
||||
if (bingId) params.bing_id = bingId;
|
||||
if (serviceConfigId) params.service_config_id = serviceConfigId;
|
||||
if (limit) params.limit = limit;
|
||||
if (offset) params.offset = offset;
|
||||
return joinUrl(baseApiUrl, "title_ids") +
|
||||
"?" + buildParams(params);
|
||||
},
|
||||
/**
|
||||
* Get single title ID by its hexadecimal value
|
||||
* @param {string} titleId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleTitleId: function(titleId) {
|
||||
return joinUrl(baseApiUrl, "title_ids/" + titleId);
|
||||
}
|
||||
},
|
||||
Achievements: {
|
||||
/**
|
||||
* Get achievements for a title-id. Xbox 360/GFWL only
|
||||
* @param {string} titleId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getAchievementsV1: function(titleId) {
|
||||
return joinUrl(baseApiUrl, "achievements/v1/" + titleId);
|
||||
},
|
||||
/**
|
||||
* Get achievements for a title-id. Xbox One/Series only
|
||||
* @param {string} titleId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getAchievementsV2: function(titleId) {
|
||||
return joinUrl(baseApiUrl, "achievements/v2/" + titleId);
|
||||
},
|
||||
},
|
||||
Marketplace: {
|
||||
/**
|
||||
* Get and filter marketplace products
|
||||
* @param {integer | (integer | null)} productType query
|
||||
* @param {integer} limit query, default: 100
|
||||
* @param {integer} offset query, default: 0
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getProducts: function(productType, limit, offset) {
|
||||
var params = {};
|
||||
if (productType) params.product_type = productType;
|
||||
if (limit) params.limit = limit;
|
||||
if (offset) params.offset = offset;
|
||||
return joinUrl(baseApiUrl, "marketplace/products") +
|
||||
"?" + buildParams(params);
|
||||
},
|
||||
/**
|
||||
* Get single marketplace product by marketplace product ID
|
||||
* @param {string} productId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleProduct: function(productId) {
|
||||
return joinUrl(baseApiUrl, "marketplace/products/" + productId);
|
||||
},
|
||||
/**
|
||||
* Get children of a marketplace product
|
||||
* @param {string} productId path, required
|
||||
* @param {integer | (integer | null)} productType query
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getProductChildren: function(productId, productType) {
|
||||
var params = {};
|
||||
if (productType) params.product_type = productType;
|
||||
return joinUrl(baseApiUrl, "marketplace/products/" + productId + "/children") +
|
||||
"?" + buildParams(params);
|
||||
},
|
||||
/**
|
||||
* Get and filter marketplace product instances
|
||||
* @param {string | (string | null)($uuid)} productId query
|
||||
* @param {string | (string | null)} hexOfferId query
|
||||
* @param {integer | (integer | null)} licenseTypeId query
|
||||
* @param {integer | (integer | null)} packageType query
|
||||
* @param {integer | (integer | null)} gameRegion query
|
||||
* @param {integer} limit query, default: 100
|
||||
* @param {integer} offset query, default: 0
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getProductInstances: function(productId, hexOfferId, licenseTypeId, packageType, gameRegion, limit, offset) {
|
||||
var params = {};
|
||||
if (productId) params.product_id = productId;
|
||||
if (hexOfferId) params.hex_offer_id = hexOfferId;
|
||||
if (licenseTypeId) params.license_type_id = licenseTypeId;
|
||||
if (packageType) params.package_type = packageType;
|
||||
if (gameRegion) params.game_region = gameRegion;
|
||||
if (limit) params.limit = limit;
|
||||
if (offset) params.offset = offset;
|
||||
return joinUrl(baseApiUrl, "marketplace/product-instances") +
|
||||
"?" + buildParams(params);
|
||||
},
|
||||
/**
|
||||
* Get single marketplace product instance by marketplace product instance ID
|
||||
* @param {string} instanceId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getProductInstanceById: function(instanceId) {
|
||||
return joinUrl(baseApiUrl, "marketplace/product-instances/" + instanceId);
|
||||
},
|
||||
/**
|
||||
* Get all marketplace product types
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getProductTypes: function() {
|
||||
return joinUrl(baseApiUrl, "marketplace/product-types");
|
||||
},
|
||||
/**
|
||||
* Get single marketplace category
|
||||
* @param {integer} productTypeId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleProductType: function(productTypeId) {
|
||||
return joinUrl(baseApiUrl, "marketplace/product-types/" + productTypeId);
|
||||
},
|
||||
/**
|
||||
* Get and filter all marketplace categories
|
||||
* @param {integer | (integer | null)} parent query
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getCategories: function(parent) {
|
||||
var params = {};
|
||||
if (parent) params.parent = parent;
|
||||
return joinUrl(baseApiUrl, "marketplace/categories") +
|
||||
"?" + buildParams(params);
|
||||
},
|
||||
/**
|
||||
* Get single marketplace category
|
||||
* @param {integer} categoryId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleCategory: function(categoryId) {
|
||||
return joinUrl(baseApiUrl, "marketplace/categories/" + categoryId);
|
||||
},
|
||||
/**
|
||||
* Get all marketplace locales
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getLocales: function() {
|
||||
return joinUrl(baseApiUrl, "marketplace/locales");
|
||||
},
|
||||
/**
|
||||
* Get single marketplace locale by locale string
|
||||
* @param {string} localeId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleLocale: function(localeId) {
|
||||
return joinUrl(baseApiUrl, "marketplace/locales/" + localeId);
|
||||
},
|
||||
},
|
||||
/**
|
||||
* Enum for product types, used in store API
|
||||
* @enum {string} DBox.API.ProductType
|
||||
*/
|
||||
ProductType: {
|
||||
application: "Application",
|
||||
avatarItem: "AvatarItem",
|
||||
consumable: "Consumable",
|
||||
durable: "Durable",
|
||||
game: "Game",
|
||||
movie: "Movie",
|
||||
pass: "PASS",
|
||||
tvSeries: "TvSeries",
|
||||
tvSeason: "TvSeason",
|
||||
tvEpisode: "TVEpisode",
|
||||
unmanagedConsumable: "UnmanagedConsumable",
|
||||
},
|
||||
/**
|
||||
* Enum for product families, used in store API
|
||||
* @enum {string} DBox.API.ProductFamily
|
||||
*/
|
||||
ProductFamily: {
|
||||
apps: "Apps",
|
||||
avatars: "Avatars",
|
||||
games: "Games",
|
||||
movies: "Movies",
|
||||
passes: "Passes",
|
||||
tv: "TV",
|
||||
},
|
||||
/**
|
||||
* Enum for order by, used in store API
|
||||
* @enum {string} DBox.API.OrderBy
|
||||
*/
|
||||
OrderBy: {
|
||||
productId: "product_id",
|
||||
titleId: "title_id",
|
||||
revisionId: "revision_id",
|
||||
/** such as "23654onetwoonestudio.cctv_kdpw61jgbrs34" */
|
||||
packageFamilyName: "package_family_name",
|
||||
/** such as "23654onetwoonestudio.cctv" */
|
||||
packageIdentityName: "package_identity_name",
|
||||
},
|
||||
/**
|
||||
* Enum for order direction, used in store API
|
||||
* @enum {string} DBox.API.OrderDirection
|
||||
*/
|
||||
OrderDirection: {
|
||||
/** @type {string} 升序 */
|
||||
asc: "asc",
|
||||
/** @type {string} 降序 */
|
||||
desc: "desc",
|
||||
},
|
||||
Store: {
|
||||
/**
|
||||
* Get store products
|
||||
* @param {string | (string | null)} category query
|
||||
* @param {string | (string | null)} titleId query
|
||||
* @param {DBox.API.ProductType | null} productType query
|
||||
* @param {DBox.API.ProductFamily | null} productFamily query
|
||||
* @param {DBox.API.OrderBy | null} orderBy query, default: productId
|
||||
* @param {DBox.API.OrderDirection | null} orderDirection query, default: asc
|
||||
* @param {integer} limit query, default: 100
|
||||
* @param {integer} offset query, default: 0
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getProducts: function(category, titleId, productType, productFamily, orderBy, orderDirection, limit, offset) {
|
||||
var params = {};
|
||||
if (category) params.category = category;
|
||||
if (titleId) params.title_id = titleId;
|
||||
if (productType) params.product_type = productType;
|
||||
if (productFamily) params.product_family = productFamily;
|
||||
if (orderBy) params.order_by = orderBy;
|
||||
if (orderDirection) params.order_direction = orderDirection;
|
||||
if (limit) params.limit = limit;
|
||||
if (offset) params.offset = offset;
|
||||
return joinUrl(baseApiUrl, "store/products") +
|
||||
"?" + buildParams(params);
|
||||
},
|
||||
/**
|
||||
* Get single store product
|
||||
* @param {string} productId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleProduct: function(productId) {
|
||||
return joinUrl(baseApiUrl, "store/products/" + productId);
|
||||
},
|
||||
/**
|
||||
* Get all related products for a product id. Includes both child and parent relationships. Check the product-ids for relationship direction. The relationship_type is parent -> child direction. Same combinations can appear multiple times with different relationship types.
|
||||
* @param {string} productId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getAllReleatedProducts: function(productId) {
|
||||
return joinUrl(baseApiUrl, "store/products/" + productId + "/related");
|
||||
},
|
||||
/**
|
||||
* Get single sku for store product
|
||||
* @param {string} productId path, required
|
||||
* @param {string} skuId path, required
|
||||
* @returns {string} request URL, method: GET
|
||||
*/
|
||||
getSingleSkuFromProduct: function(productId, skuId) {
|
||||
return joinUrl(baseApiUrl, "store/products/" + productId + "/sku/" + skuId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getXhr() {
|
||||
var xmlhttp;
|
||||
try {
|
||||
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
|
||||
} catch (e) {
|
||||
try {
|
||||
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
} catch (E) {
|
||||
xmlhttp = false;
|
||||
}
|
||||
}
|
||||
if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
|
||||
xmlhttp = new XMLHttpRequest();
|
||||
}
|
||||
return xmlhttp;
|
||||
}
|
||||
/**
|
||||
* Send an HTTP request to the DBox API and return a Promise that resolves with the response.
|
||||
* @param {string} api DBox API
|
||||
* @param {string} method
|
||||
* @param {[boolean]} isAsync default: true
|
||||
* @param {[string]} username
|
||||
* @param {[string]} pwd
|
||||
* @returns {Promise <XMLHttpRequest>} A Promise that resolves with the response.
|
||||
*/
|
||||
var dboxXHR = function(api, method, isAsync, username, pwd) {
|
||||
method = method || "GET";
|
||||
if (typeof isAsync === "undefined" || isAsync === null) isAsync = true;
|
||||
var xhr = getXhr();
|
||||
if (username && pwd) {
|
||||
try {
|
||||
xhr.open(method, api, isAsync, username, pwd);
|
||||
} catch (e) {
|
||||
xhr.open(method, api, isAsync);
|
||||
}
|
||||
} else {
|
||||
xhr.open(method, api, isAsync);
|
||||
}
|
||||
return new Promise(function(c, e) {
|
||||
try {
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
if (c) c(xhr);
|
||||
} else {
|
||||
if (e) e(xhr.statusText + " (" + xhr.status + ")");
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send("");
|
||||
} catch (ex) {
|
||||
if (e) e(ex);
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Send an HTTP request to the DBox API and return a Promise that resolves with the response as JSON.
|
||||
* @param {string} api DBox API
|
||||
* @param {string} method
|
||||
* @param {[boolean]} isAsync default: true
|
||||
* @param {[string]} username
|
||||
* @param {[string]} pwd
|
||||
* @returns {Promise <object>} A Promise that resolves with the response as JSON.
|
||||
*/
|
||||
dboxXHR.parseJson = function(api, method, isAsync, username, pwd) {
|
||||
return dboxXHR(api, method, isAsync, username, pwd).then(function(xhr) {
|
||||
return JSON.parse(xhr.responseText);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* DBox namespace
|
||||
* @namespace {DBox}
|
||||
*/
|
||||
global.DBox = {
|
||||
/**
|
||||
* DBox API namespace
|
||||
* @namespace {DBox.API}
|
||||
*/
|
||||
API: dboxApi,
|
||||
/**
|
||||
* @function {DBox.XHR}
|
||||
*/
|
||||
xhr: dboxXHR,
|
||||
};
|
||||
})(this);
|
||||
206
shared/html/js/http.js
Normal file
206
shared/html/js/http.js
Normal file
@@ -0,0 +1,206 @@
|
||||
(function(global) {
|
||||
if (typeof global.Web === "undefined") global.Web = {};
|
||||
|
||||
function dataToString(obj) {
|
||||
if (typeof obj === "string") return obj;
|
||||
if (typeof obj === "object") return JSON.stringify(obj);
|
||||
return String(obj);
|
||||
}
|
||||
global.Web.Http = {
|
||||
Request: function() {
|
||||
var inst = external.Web.Http.createHttpRequest();
|
||||
this.open = function(method, url) { inst.open(method, url); };
|
||||
this.getHeaders = function() { return JSON.parse(inst.getHeadersToJson()); };
|
||||
this.getHeader = function(swName) { try { return inst.getHeader(swName); } catch (e) { return void 0; } };
|
||||
this.setHeader = function(swName, swValue) { inst.setHeader(swName, swValue); };
|
||||
this.removeHeader = function(swName) { inst.removeHeader(swName); };
|
||||
this.clearHeader = function() { inst.clearHeader(); };
|
||||
this.updateHeaders = function(headers) {
|
||||
var keys = Object.keys(headers);
|
||||
this.clearHeader();
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
this.setHeader(keys[i], dataToString(headers[keys[i]]));
|
||||
}
|
||||
};
|
||||
this.setHeaders = function(headers) {
|
||||
var keys = Object.keys(headers);
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
inst.setHeader(keys[i], dataToString(headers[keys[i]]));
|
||||
}
|
||||
};
|
||||
this.send = function(body, encoding) { return inst.send(body, encoding); };
|
||||
this.sendAsync = function(body, encoding) {
|
||||
if (!encoding) encoding = "utf-8";
|
||||
return new Promise(function(c, e) {
|
||||
try {
|
||||
inst.sendAsync(body, encoding, function(resp) {
|
||||
if (c) c(resp);
|
||||
});
|
||||
} catch (ex) { if (e) e(ex); }
|
||||
});
|
||||
};
|
||||
Object.defineProperty(this, "timeout", {
|
||||
get: function() { return inst.timeout; },
|
||||
set: function(value) { inst.timeout = value; }
|
||||
});
|
||||
Object.defineProperty(this, "readWriteTimeout", {
|
||||
get: function() { return inst.readWriteTimeout; },
|
||||
set: function(value) { inst.readWriteTimeout = value; }
|
||||
});
|
||||
Object.defineProperty(this, "allowAutoRedirect", {
|
||||
get: function() { return inst.allowAutoRedirect; },
|
||||
set: function(value) { inst.allowAutoRedirect = value; }
|
||||
});
|
||||
Object.defineProperty(this, "allowWriteStreamBuffering", {
|
||||
get: function() { return inst.allowWriteStreamBuffering; },
|
||||
set: function(value) { inst.allowWriteStreamBuffering = value; }
|
||||
});
|
||||
Object.defineProperty(this, "keepAlive", {
|
||||
get: function() { return inst.keepAlive; },
|
||||
set: function(value) { inst.keepAlive = value; }
|
||||
});
|
||||
Object.defineProperty(this, "maximumAutomaticRedirections", {
|
||||
get: function() { return inst.maximumAutomaticRedirections; },
|
||||
set: function(value) { inst.maximumAutomaticRedirections = value; }
|
||||
});
|
||||
Object.defineProperty(this, "userAgent", {
|
||||
get: function() { return inst.userAgent; },
|
||||
set: function(value) { inst.userAgent = value; }
|
||||
});
|
||||
Object.defineProperty(this, "referer", {
|
||||
get: function() { return inst.referer; },
|
||||
set: function(value) { inst.referer = value; }
|
||||
});
|
||||
Object.defineProperty(this, "contentType", {
|
||||
get: function() { return inst.contentType; },
|
||||
set: function(value) { inst.contentType = value; }
|
||||
});
|
||||
Object.defineProperty(this, "accept", {
|
||||
get: function() { return inst.accept; },
|
||||
set: function(value) { inst.accept = value; }
|
||||
});
|
||||
Object.defineProperty(this, "proxy", {
|
||||
get: function() { return inst.proxy; },
|
||||
set: function(value) { inst.proxy = value; }
|
||||
});
|
||||
Object.defineProperty(this, "cookieContainer", {
|
||||
get: function() { return inst.cookieContainer; },
|
||||
set: function(value) { inst.cookieContainer = value; }
|
||||
});
|
||||
Object.defineProperty(this, "protocolVersion", {
|
||||
get: function() { return inst.protocolVersion; },
|
||||
set: function(value) { inst.protocolVersion = value; }
|
||||
});
|
||||
Object.defineProperty(this, "preAuthenticate", {
|
||||
get: function() { return inst.preAuthenticate; },
|
||||
set: function(value) { inst.preAuthenticate = value; }
|
||||
});
|
||||
Object.defineProperty(this, "credentials", {
|
||||
get: function() { return inst.credentials; },
|
||||
set: function(value) { inst.credentials = value; }
|
||||
});
|
||||
Object.defineProperty(this, "automaticDecompression", {
|
||||
get: function() { return inst.automaticDecompression; },
|
||||
set: function(value) { inst.automaticDecompression = value; }
|
||||
});
|
||||
this.dispose = function() { inst.dispose(); };
|
||||
},
|
||||
Header: {
|
||||
// 通用头(既可用于请求也可用于响应)
|
||||
General: {
|
||||
cacheControl: "Cache-Control",
|
||||
connection: "Connection",
|
||||
date: "Date",
|
||||
pragma: "Pragma",
|
||||
trailer: "Trailer",
|
||||
transferEncoding: "Transfer-Encoding",
|
||||
upgrade: "Upgrade",
|
||||
via: "Via",
|
||||
warning: "Warning"
|
||||
},
|
||||
// 请求头
|
||||
Request: {
|
||||
accept: "Accept",
|
||||
acceptCharset: "Accept-Charset",
|
||||
acceptEncoding: "Accept-Encoding",
|
||||
acceptLanguage: "Accept-Language",
|
||||
authorization: "Authorization",
|
||||
expect: "Expect",
|
||||
from: "From",
|
||||
host: "Host",
|
||||
ifMatch: "If-Match",
|
||||
ifModifiedSince: "If-Modified-Since",
|
||||
ifNoneMatch: "If-None-Match",
|
||||
ifRange: "If-Range",
|
||||
ifUnmodifiedSince: "If-Unmodified-Since",
|
||||
maxForwards: "Max-Forwards",
|
||||
proxyAuthorization: "Proxy-Authorization",
|
||||
range: "Range",
|
||||
referer: "Referer",
|
||||
te: "TE",
|
||||
userAgent: "User-Agent"
|
||||
},
|
||||
// 响应头
|
||||
Response: {
|
||||
acceptRanges: "Accept-Ranges",
|
||||
age: "Age",
|
||||
allow: "Allow",
|
||||
contentEncoding: "Content-Encoding",
|
||||
contentLanguage: "Content-Language",
|
||||
contentLength: "Content-Length",
|
||||
contentLocation: "Content-Location",
|
||||
contentRange: "Content-Range",
|
||||
contentType: "Content-Type",
|
||||
etag: "ETag",
|
||||
expires: "Expires",
|
||||
lastModified: "Last-Modified",
|
||||
location: "Location",
|
||||
proxyAuthenticate: "Proxy-Authenticate",
|
||||
retryAfter: "Retry-After",
|
||||
server: "Server",
|
||||
setCookie: "Set-Cookie",
|
||||
vary: "Vary",
|
||||
wwwAuthenticate: "WWW-Authenticate"
|
||||
},
|
||||
// CORS 相关头(常单独列出,也可归入请求/响应)
|
||||
Cors: {
|
||||
accessControlAllowOrigin: "Access-Control-Allow-Origin",
|
||||
accessControlAllowCredentials: "Access-Control-Allow-Credentials",
|
||||
accessControlAllowHeaders: "Access-Control-Allow-Headers",
|
||||
accessControlAllowMethods: "Access-Control-Allow-Methods",
|
||||
accessControlExposeHeaders: "Access-Control-Expose-Headers",
|
||||
accessControlMaxAge: "Access-Control-Max-Age",
|
||||
accessControlRequestHeaders: "Access-Control-Request-Headers",
|
||||
accessControlRequestMethod: "Access-Control-Request-Method",
|
||||
origin: "Origin"
|
||||
},
|
||||
// 安全/非标准常用头
|
||||
Security: {
|
||||
xFrameOptions: "X-Frame-Options",
|
||||
xContentTypeOptions: "X-Content-Type-Options",
|
||||
xXssProtection: "X-XSS-Protection",
|
||||
strictTransportSecurity: "Strict-Transport-Security",
|
||||
contentSecurityPolicy: "Content-Security-Policy",
|
||||
referrerPolicy: "Referrer-Policy",
|
||||
xRequestedWith: "X-Requested-With",
|
||||
xForwardedFor: "X-Forwarded-For",
|
||||
xForwardedProto: "X-Forwarded-Proto",
|
||||
xRealIp: "X-Real-IP"
|
||||
}
|
||||
},
|
||||
Method: {
|
||||
get: "GET",
|
||||
post: "POST",
|
||||
put: "PUT",
|
||||
delete: "DELETE",
|
||||
head: "HEAD",
|
||||
options: "OPTIONS",
|
||||
trace: "TRACE",
|
||||
connect: "CONNECT"
|
||||
},
|
||||
Version: {
|
||||
v1_0: "1.0",
|
||||
v1_1: "1.1",
|
||||
}
|
||||
}
|
||||
})(this);
|
||||
@@ -162,15 +162,16 @@
|
||||
}
|
||||
oldTags.push(k);
|
||||
promises.push(
|
||||
anime.runAsync(p.page, [
|
||||
anime.Keyframes.Opacity.hidden
|
||||
]).then((function(page, key) {
|
||||
return function() {
|
||||
page.style.display = "none";
|
||||
page.style.opacity = 0;
|
||||
emit("unload", key);
|
||||
};
|
||||
})(p.page, k))
|
||||
(function(page, key) {
|
||||
// 返回 anime.runAsync 产生的 Promise
|
||||
return anime.runAsync(page, [anime.Keyframes.Opacity.hidden])
|
||||
.then(function() {
|
||||
page.style.display = "none";
|
||||
page.style.opacity = 0;
|
||||
page.style.height = 0;
|
||||
emit("unload", key);
|
||||
});
|
||||
})(p.page, k)
|
||||
);
|
||||
p.guide.classList.remove("selected");
|
||||
}
|
||||
|
||||
@@ -52,7 +52,13 @@
|
||||
},
|
||||
cancelAll: function() { external.Package.Reader.cancelAll(); },
|
||||
addApplicationReadItem: function(swItemName) { return external.Package.Reader.addApplicationItem(swItemName); },
|
||||
removeApplicationReadItem: function(swItemName) { return external.Package.Reader.removeApplicationItem(swItemName); }
|
||||
removeApplicationReadItem: function(swItemName) { return external.Package.Reader.removeApplicationItem(swItemName); },
|
||||
updateApplicationReadItems: function(aswArray) {
|
||||
external.Package.Reader.updateApplicationItems(aswArray);
|
||||
},
|
||||
getApplicationReadItems: function() {
|
||||
return JSON.parse(external.Package.Reader.getApplicationItemsToJson());
|
||||
},
|
||||
},
|
||||
manager: {
|
||||
add: function(swPkgPath, uOptions) {
|
||||
@@ -169,5 +175,76 @@
|
||||
cancelAll: function() { mgr.cancelAll(); },
|
||||
active: function(swAppUserModelID, swArgs) { return mgr.activeApp(swAppUserModelID, swArgs || null); }
|
||||
},
|
||||
utils: (function() {
|
||||
// 解析包全名,格式: <name>_<version>_<processorArchitecture>_<resourceId>_<publisherId>
|
||||
// resourceId 可能为空(表现为两个连续下划线)
|
||||
function parsePackageFullName(fullName) {
|
||||
var parts = fullName.split('_');
|
||||
// 按格式应有5部分: [name, version, architecture, resourceId, publisherId]
|
||||
return {
|
||||
name: parts[0],
|
||||
version: parts[1],
|
||||
architecture: parts[2],
|
||||
resourceId: parts[3],
|
||||
publisherId: parts[4]
|
||||
};
|
||||
}
|
||||
|
||||
// 解析包系列名,格式: <name>_<publisherId>
|
||||
function parsePackageFamilyName(familyName) {
|
||||
var underscoreIndex = familyName.indexOf('_');
|
||||
if (underscoreIndex === -1) {
|
||||
// 异常情况,按原字符串处理,但题目不会出现
|
||||
return { name: familyName, publisherId: '' };
|
||||
}
|
||||
return {
|
||||
name: familyName.substring(0, underscoreIndex),
|
||||
publisherId: familyName.substring(underscoreIndex + 1)
|
||||
};
|
||||
}
|
||||
|
||||
// 将对象转换为包全名字符串
|
||||
// 对象应包含 name, version, architecture, publisherId 字段,resourceId 可选
|
||||
function stringifyPackageFullName(pkg) {
|
||||
var resourcePart = (pkg.resourceId === undefined || pkg.resourceId === null) ? '' : pkg.resourceId;
|
||||
return pkg.name + '_' + pkg.version + '_' + pkg.architecture + '_' + resourcePart + '_' + pkg.publisherId;
|
||||
}
|
||||
|
||||
// 将对象转换为包系列名字符串
|
||||
// 对象应包含 name, publisherId 字段
|
||||
function stringifyPackageFamilyName(pkgFamily) {
|
||||
return pkgFamily.name + '_' + pkgFamily.publisherId;
|
||||
}
|
||||
return {
|
||||
parsePackageFullName: parsePackageFullName,
|
||||
parsePackageFamilyName: parsePackageFamilyName,
|
||||
stringifyPackageFullName: stringifyPackageFullName,
|
||||
stringifyPackageFamilyName: stringifyPackageFamilyName,
|
||||
isDependency: function(swPkgIdentityName) {
|
||||
var list = [
|
||||
"Microsoft.Net.Native.Framework",
|
||||
"Microsoft.Net.Native.Runtime",
|
||||
"Microsoft.Net.CoreRuntime",
|
||||
"WindowsPreview.Kinect",
|
||||
"Microsoft.VCLibs",
|
||||
"Microsoft.WinJS",
|
||||
"Microsoft.UI.Xaml",
|
||||
"Microsoft.WindowsAppRuntime",
|
||||
"Microsoft.Advertising.XAML",
|
||||
"Microsoft.Midi.Gmdls",
|
||||
"Microsoft.Services.Store.Engagement",
|
||||
"Microsoft.Media.PlayReadyClient"
|
||||
];
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (swPkgIdentityName.toLowerCase().indexOf(list[i].toLowerCase()) !== -1)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})()
|
||||
};
|
||||
global.Package.Reader = global.Package.reader;
|
||||
global.Package.Manager = global.Package.manager;
|
||||
global.Package.Utils = global.Package.utils;
|
||||
})(this);
|
||||
@@ -530,3 +530,101 @@
|
||||
global.Set = Set;
|
||||
}
|
||||
})(this);
|
||||
(function(global) {
|
||||
// 如果原生 WeakMap 已存在,则不覆盖
|
||||
if (typeof global.WeakMap !== "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
function WeakMap(iterable) {
|
||||
// 必须使用 new 调用
|
||||
if (!(this instanceof WeakMap)) {
|
||||
throw new TypeError('Constructor WeakMap requires "new"');
|
||||
}
|
||||
|
||||
// 私有存储:每个实例独立维护一个键值对数组
|
||||
var entries = [];
|
||||
|
||||
// 验证 key 必须是对象或函数(不能是 null 或原始值)
|
||||
function validateKey(key) {
|
||||
if (key === null || (typeof key !== 'object' && typeof key !== 'function')) {
|
||||
throw new TypeError('WeakMap key must be an object');
|
||||
}
|
||||
}
|
||||
|
||||
// 设置键值对
|
||||
this.set = function(key, value) {
|
||||
validateKey(key);
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
if (entries[i][0] === key) {
|
||||
entries[i][1] = value;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
entries.push([key, value]);
|
||||
return this;
|
||||
};
|
||||
|
||||
// 获取键对应的值
|
||||
this.get = function(key) {
|
||||
validateKey(key);
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
if (entries[i][0] === key) {
|
||||
return entries[i][1];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
// 判断是否存在指定键
|
||||
this.has = function(key) {
|
||||
validateKey(key);
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
if (entries[i][0] === key) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// 删除指定键及其值
|
||||
this.delete = function(key) {
|
||||
validateKey(key);
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
if (entries[i][0] === key) {
|
||||
entries.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// 处理可选的初始化参数(iterable,例如 [[key1, value1], [key2, value2]])
|
||||
if (iterable !== null && iterable !== undefined) {
|
||||
// 支持数组或类数组(具备 forEach 方法的对象)
|
||||
if (typeof iterable.forEach === 'function') {
|
||||
var self = this;
|
||||
iterable.forEach(function(item) {
|
||||
if (!Array.isArray(item) || item.length < 2) {
|
||||
throw new TypeError('Iterator value is not an entry object');
|
||||
}
|
||||
self.set(item[0], item[1]);
|
||||
});
|
||||
} else if (typeof iterable.length === 'number') {
|
||||
// 类数组对象(如 arguments)
|
||||
for (var i = 0; i < iterable.length; i++) {
|
||||
var item = iterable[i];
|
||||
if (!Array.isArray(item) || item.length < 2) {
|
||||
throw new TypeError('Iterator value is not an entry object');
|
||||
}
|
||||
this.set(item[0], item[1]);
|
||||
}
|
||||
} else {
|
||||
throw new TypeError('WeakMap iterable is not iterable');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 挂载到全局对象
|
||||
global.WeakMap = WeakMap;
|
||||
})(this);
|
||||
@@ -502,6 +502,22 @@
|
||||
if (!p.removeEventListener) p.removeEventListener = PromisePolyfill.removeEventListener;
|
||||
if (!p.dispatchEvent) p.dispatchEvent = PromisePolyfill.dispatchEvent;
|
||||
if (!p.onerror) p.onerror = null;
|
||||
if (typeof p.prototype.then !== "function") {
|
||||
p.prototype.then = function(onFulfilled, onRejected) {
|
||||
return new p(function(resolve, reject) {
|
||||
this.then(resolve, reject);
|
||||
}).then(onFulfilled, onRejected);
|
||||
};
|
||||
}
|
||||
if (typeof p.prototype.done !== "function") {
|
||||
p.prototype.done = function(onFulfilled, onRejected) {
|
||||
this.then(onFulfilled, onRejected)["catch"](function(ex) {
|
||||
setTimeout(function() {
|
||||
throw ex;
|
||||
}, 0);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
if (typeof global.WinJS !== "undefined" && typeof global.WinJS.Promise !== "undefined") {
|
||||
var wp = global.WinJS.Promise;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
});
|
||||
var themeColor = Bridge.UI.themeColor;
|
||||
pagemgr.register("reader", document.getElementById("tag-reader"), document.getElementById("page-reader"));
|
||||
pagemgr.register("acquire", document.getElementById("tag-acquire"), document.getElementById("page-acquire"));
|
||||
pagemgr.go("reader");
|
||||
});
|
||||
})(this);
|
||||
1357
shared/html/js/storergapi.js
Normal file
1357
shared/html/js/storergapi.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -352,6 +352,13 @@ aside>nav ul li div[role=img] {
|
||||
}
|
||||
|
||||
.ispage {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
box-sizing: border-box;
|
||||
opacity: 1;
|
||||
transition: all 0.4s cubic-bezier(0.1, 0.9, 0.2, 1);
|
||||
}
|
||||
|
||||
.ispage.padding {
|
||||
padding: 44px 60px;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Package Manager</title>
|
||||
<title>Package Reader</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -32,6 +32,9 @@
|
||||
<script type="text/javascript" src="libs/msgbox/msgbox.js"></script>
|
||||
<script type="text/javascript" src="js/init.js"></script>
|
||||
<script type="text/javascript" src="js/pkginfo.js"></script>
|
||||
<script type="text/javascript" src="js/http.js"></script>
|
||||
<script type="text/javascript" src="js/storergapi.js"></script>
|
||||
<script type="text/javascript" src="js/dboxapi.js"></script>
|
||||
<script type="text/javascript" src="js/datasrc.js"></script>
|
||||
<script type="text/javascript" src="js/appbar.js"></script>
|
||||
<script type="text/javascript" src="js/pagemgr.js"></script>
|
||||
@@ -55,8 +58,8 @@
|
||||
<body>
|
||||
<div id="readerpage" class="pagecontainer full">
|
||||
<div class="page full guide fold">
|
||||
<main class="main padding">
|
||||
<div id="page-reader" style="display: none;" class="ispage">
|
||||
<main class="main">
|
||||
<div id="page-reader" style="display: none;" class="ispage padding">
|
||||
<h2>读取</h2>
|
||||
<p>请选择一个包,获取其信息。</p>
|
||||
<div>
|
||||
@@ -365,6 +368,292 @@
|
||||
})(this);
|
||||
</script>
|
||||
</div>
|
||||
<div id="page-acquire" style="display: none;" class="ispage padding">
|
||||
<h2>获取</h2>
|
||||
<div id="acquire-forbidden" style="width: 100%;">
|
||||
<p>由于来自 store.rg-adguard.net 的限制,现在暂时无法实现对包的获取。请自行打开下面 URL 进行访问。</p>
|
||||
<a onclick="external.Process.open ('https://store.rg-adguard.net')">store.rg-adguard.net</a>
|
||||
</div>
|
||||
<div id="acquire-enable" style="width: 100%;">
|
||||
<p>请在下面的输入框中输入要查询的内容,设置好参数后将进行查询。</p>
|
||||
<div>
|
||||
<div>
|
||||
<input type="text" id="acquire-input">
|
||||
<select id="acquire-valuetype" name="type">
|
||||
<option value="url">分享链接</option>
|
||||
<option value="ProductId">产品 ID</option>
|
||||
<option value="PackageFamilyName">包系列名</option>
|
||||
<option value="CategoryId">类别 ID</option>
|
||||
</select>
|
||||
<select id="acquire-channel" name="ring">
|
||||
<option title="Windows Insider Fast" value="WIF">快速</option>
|
||||
<option title="Windows Insider Slow" value="WIS">慢速</option>
|
||||
<option title="Release Preview" value="RP" selected>发布预览</option>
|
||||
<option title="Default OS" value="Retail">正式</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<div class="itemrow">
|
||||
<input type="checkbox" id="acquire-smartquery" style="margin-left: 0px;">
|
||||
<label for="acquire-smartquery">自动查询</label>
|
||||
</div>
|
||||
<button id="acquire-query">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.acquire-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
align-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
width: 100%;
|
||||
margin: 5px 0;
|
||||
box-sizing: border-box;
|
||||
padding: 5px;
|
||||
border: 1px solid #ccc;
|
||||
-ms-user-select: element;
|
||||
user-select: all;
|
||||
}
|
||||
|
||||
.acquire-item #name {
|
||||
font-size: 11pt;
|
||||
width: 100%;
|
||||
line-height: 1.3em;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.acquire-item .medium {
|
||||
width: 100%;
|
||||
font-size: 10pt;
|
||||
line-height: 1.2em;
|
||||
font-weight: normal;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-content: center;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 3px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.acquire-item .medium div {
|
||||
text-align: center;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.acquire-item .medium #ext {
|
||||
text-align: left;
|
||||
max-width: 100px;
|
||||
/*min-width: 97px;*/
|
||||
}
|
||||
|
||||
.acquire-item .medium div:nth-child(1),
|
||||
.acquire-item .medium div:nth-child(3),
|
||||
.acquire-item .medium div:nth-child(5) {
|
||||
background-color: #e9fff5;
|
||||
}
|
||||
|
||||
.acquire-item .medium div:nth-child(2),
|
||||
.acquire-item .medium div:nth-child(4),
|
||||
.acquire-item .medium div:nth-child(6) {
|
||||
background-color: #ffffef;
|
||||
}
|
||||
|
||||
.acquire-item .bottom {
|
||||
font-weight: bold;
|
||||
font-size: 9pt;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: center;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.acquire-item #hashpart {
|
||||
flex: 1;
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.acquire-item:hover {
|
||||
background-color: rgba(0, 0, 0, 0.122);
|
||||
}
|
||||
|
||||
.acquire-item #download {
|
||||
cursor: pointer;
|
||||
font-size: 10pt;
|
||||
}
|
||||
</style>
|
||||
<div id="acquire-template" class="acquire-item" style="display: none;">
|
||||
<div id="name" class="top" title="Identity Name">Identity Name</div>
|
||||
<div class="medium">
|
||||
<div id="ext" title="File Type">Appx</div>
|
||||
<div id="version" title="Version">1.0.0.0</div>
|
||||
<div id="architecture" title="Processor Architecture">neutral</div>
|
||||
<div id="publisherId" title="Identity Publisher Id"></div>
|
||||
<div id="size" title="File Size"></div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div id="hashpart"><span>SHA-1: </span><span id="hash"></span></div>
|
||||
<div><a download id="download" href="">点击下载</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="acquire-loading">
|
||||
<br>
|
||||
<div class="container itemrow">
|
||||
<progress class="win-ring" style="margin-right: 10px;"></progress>
|
||||
<span class="win-label title" data-res-resxml="MANAGER_APP_INSTALLEDAPPS_LOADING"></span>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
<div id="acquire-result" style="width: 100%;">
|
||||
<p style="font-weight: normal;" title="Category ID"><span>类别 ID</span>: <span id="acquire-categoryid" style="user-select: text; -ms-user-select: element;"></span></p>
|
||||
<h3>以下可能为检索到的应用</h3>
|
||||
<div id="acquire-list-app" style="width: 100%;"></div>
|
||||
<h3>以下可能为检索到的依赖项</h3>
|
||||
<div id="acquire-list-dep" style="width: 100%;"></div>
|
||||
</div>
|
||||
<script>
|
||||
(function(global) {
|
||||
var conf = external.Config.current;
|
||||
var set = conf.getSection("Settings");
|
||||
var isForbidden = !set.getKey("EnableAcquire").readBool(false);
|
||||
var acquireInput = document.getElementById("acquire-input");
|
||||
var acquireValuetype = document.getElementById("acquire-valuetype");
|
||||
var acquireChannel = document.getElementById("acquire-channel");
|
||||
var acquireSmartquery = document.getElementById("acquire-smartquery");
|
||||
var acquireQuery = document.getElementById("acquire-query");
|
||||
var acquireResult = document.getElementById("acquire-result");
|
||||
var acquireListApp = document.getElementById("acquire-list-app");
|
||||
var acquireListDep = document.getElementById("acquire-list-dep");
|
||||
var acquireForbidden = document.getElementById("acquire-forbidden");
|
||||
var acquireEnable = document.getElementById("acquire-enable");
|
||||
var acquireCategoryid = document.getElementById("acquire-categoryid");
|
||||
var acquireTemplate = document.getElementById("acquire-template");
|
||||
var acquireLoading = document.getElementById("acquire-loading");
|
||||
var acquireLoadingRing = acquireLoading.querySelector(".win-ring");
|
||||
var acquireLoadingLabel = acquireLoading.querySelector(".win-label");
|
||||
acquireForbidden.style.display = isForbidden ? "" : "none";
|
||||
acquireEnable.style.display = isForbidden ? "none" : "";
|
||||
acquireResult.style.display = isForbidden ? "none" : "none";
|
||||
var dataSrc = {
|
||||
apps: new DataView.DataSource(),
|
||||
deps: new DataView.DataSource()
|
||||
};
|
||||
var putils = Package.Utils;
|
||||
var templateFunc = function(item, index) {
|
||||
var node = acquireTemplate.cloneNode(true);
|
||||
node.style.display = "";
|
||||
node.id = "";
|
||||
var lastDotIndex = item.file.lastIndexOf(".");
|
||||
var fileNamePart = lastDotIndex !== -1 ? item.file.substring(0, lastDotIndex) : item.file;
|
||||
var fileExtension = lastDotIndex !== -1 ? item.file.substring(lastDotIndex + 1) : "";
|
||||
var identityName = putils.parsePackageFullName(fileNamePart);
|
||||
node.querySelector("#name").textContent = identityName.name;
|
||||
node.querySelector("#ext").textContent = fileExtension;
|
||||
node.querySelector("#version").textContent = identityName.version;
|
||||
node.querySelector("#architecture").textContent = identityName.architecture;
|
||||
node.querySelector("#publisherId").textContent = identityName.publisherId;
|
||||
node.querySelector("#size").textContent = item.size;
|
||||
node.querySelector("#hash").textContent = item.sha1;
|
||||
node.title = item.file;
|
||||
node.querySelector("#download").href = item.url;
|
||||
node.querySelector("#download").title = item.url;
|
||||
return node;
|
||||
};
|
||||
var listView = {
|
||||
apps: new DataView.ListView(acquireListApp, templateFunc),
|
||||
deps: new DataView.ListView(acquireListDep, templateFunc)
|
||||
};
|
||||
listView.apps.bind(dataSrc.apps);
|
||||
listView.deps.bind(dataSrc.deps);
|
||||
var keys = Object.keys(listView);
|
||||
keys.forEach(function(k, i) {
|
||||
var listview = listView[k];
|
||||
var p = document.createElement("p");
|
||||
p.textContent = "还没有内容...";
|
||||
listview.emptyView = p;
|
||||
});
|
||||
acquireLoading.statusBar = new TransitionPanel(acquireLoading, {
|
||||
axis: "y",
|
||||
speed: 500,
|
||||
});
|
||||
acquireSmartquery.onchange = function() {
|
||||
acquireValuetype.disabled =
|
||||
acquireChannel.disabled = this.checked;
|
||||
};
|
||||
acquireSmartquery.checked = set.getKey("AcquireSmartQuery").readBool(false);
|
||||
acquireValuetype.disabled =
|
||||
acquireChannel.disabled = acquireSmartquery.checked;
|
||||
acquireQuery.onclick = function() {
|
||||
var self = this;
|
||||
self.disabled = true;
|
||||
acquireResult.style.display = "none";
|
||||
acquireLoadingRing.style.display = "";
|
||||
acquireLoading.statusBar.show();
|
||||
var queryFunc = StoreRG.xhr.parse;
|
||||
if (acquireSmartquery.checked) {
|
||||
queryFunc = StoreRG.xhr.smartQuery;
|
||||
}
|
||||
acquireInput.disabled =
|
||||
acquireSmartquery.disabled =
|
||||
acquireValuetype.disabled =
|
||||
acquireChannel.disabled = true;
|
||||
queryFunc = StoreRG.test;
|
||||
acquireLoadingLabel.textContent = "正在查询...";
|
||||
queryFunc(acquireInput.value, acquireValuetype.value, acquireChannel.value).then(function(result) {
|
||||
acquireCategoryid.textContent = result.categoryId;
|
||||
var applist = [];
|
||||
var deplist = [];
|
||||
result.datas.forEach(function(item, index) {
|
||||
if (item.file.indexOf(".BlockMap") >= 0) return;
|
||||
if (putils.isDependency(item.file)) {
|
||||
deplist.push(item);
|
||||
} else {
|
||||
applist.push(item);
|
||||
}
|
||||
});
|
||||
dataSrc.apps.updateList(applist, function(item) {
|
||||
return item.file;
|
||||
});
|
||||
listView.apps.refresh();
|
||||
dataSrc.deps.updateList(deplist, function(item) {
|
||||
return item.file;
|
||||
});
|
||||
listView.deps.refresh();
|
||||
acquireLoadingLabel.textContent = "已获取到 {0} 个信息"
|
||||
.replace("{0}", applist.length + deplist.length);
|
||||
}, function(err) {
|
||||
dataSrc.apps.clear();
|
||||
dataSrc.deps.clear();
|
||||
listView.apps.refresh();
|
||||
listView.deps.refresh();
|
||||
acquireLoadingLabel.textContent = err.message || err;
|
||||
return Promise.wrap();
|
||||
}).done(function() {
|
||||
acquireResult.style.display = "";
|
||||
setTimeout(function() {
|
||||
acquireLoading.statusBar.hide();
|
||||
}, 10000);
|
||||
self.disabled = false;
|
||||
acquireLoadingRing.style.display = "none";
|
||||
acquireInput.disabled =
|
||||
acquireSmartquery.disabled = false;
|
||||
acquireValuetype.disabled =
|
||||
acquireChannel.disabled = acquireSmartquery.checked;
|
||||
});
|
||||
}
|
||||
})(this);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<aside class="win-ui-dark">
|
||||
<nav class="container">
|
||||
@@ -390,6 +679,10 @@
|
||||
<div role="img"></div>
|
||||
<span class="win-type-base" data-res-resxml="MANAGER_MANAGE"></span>
|
||||
</li>
|
||||
<li id="tag-acquire">
|
||||
<div role="img"></div>
|
||||
<span class="win-type-base" data-res-resxml="MANAGER_MANAGE"></span>
|
||||
</li>
|
||||
<li id="tag-settings">
|
||||
<div role="img"></div>
|
||||
<span class="win-type-base" data-res-resxml="MANAGER_SETTINGS"></span>
|
||||
|
||||
Reference in New Issue
Block a user