Update manager and add features for App Installer.

This commit is contained in:
Bruce
2026-01-31 22:03:03 +08:00
parent 0c87a2cdcd
commit d91948eaff
37 changed files with 3645 additions and 923 deletions

View File

@@ -69,6 +69,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IEHelper", "IEHelper\IEHelp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernNotice", "ModernNotice\ModernNotice.csproj", "{C5587B6E-19C4-4484-AA97-5C20FBB07E43}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launch", "Launch\Launch.csproj", "{F0288B24-7B84-42A5-9A92-2E16A012E4DE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -293,6 +295,18 @@ Global
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Release|x64.Build.0 = Release|Any CPU
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Release|x86.ActiveCfg = Release|Any CPU
{C5587B6E-19C4-4484-AA97-5C20FBB07E43}.Release|x86.Build.0 = Release|Any CPU
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Debug|x64.ActiveCfg = Debug|Any CPU
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Debug|x64.Build.0 = Debug|Any CPU
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Debug|x86.ActiveCfg = Debug|Any CPU
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Debug|x86.Build.0 = Debug|Any CPU
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Release|Any CPU.Build.0 = Release|Any CPU
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Release|x64.ActiveCfg = Release|Any CPU
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Release|x64.Build.0 = Release|Any CPU
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Release|x86.ActiveCfg = Release|Any CPU
{F0288B24-7B84-42A5-9A92-2E16A012E4DE}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -112,10 +112,10 @@ namespace AppxPackage
[ClassInterface (ClassInterfaceType.AutoDual)]
public class BaseInfoSectWithPRISingle: BaseInfoSection
{
protected Ref<ManifestReader> m_reader = null;
protected Ref<PriReader> m_pri = null;
protected Ref<bool> m_usePri = false;
protected Ref<bool> m_enablePri = false;
protected Ref<ManifestReader> m_reader = new Ref<ManifestReader> (null);
protected Ref<PriReader> m_pri = new Ref<PriReader> (null);
protected Ref<bool> m_usePri = new Ref<bool> (false);
protected Ref<bool> m_enablePri = new Ref<bool> (false);
public BaseInfoSectWithPRISingle (ref IntPtr hReader, ManifestReader reader, ref PriReader pri, ref bool usePri, ref bool enablePri) : base (ref hReader)
{
m_reader.Set (reader);
@@ -577,6 +577,10 @@ namespace AppxPackage
{
dict [(kv.Key?.Trim () ?? "") + "_Base64"] = app.NewAtBase64 (kv.Key);
}
else
{
dict [kv.Key] = app.NewAt (kv.Key, m_usePri.Value && m_enablePri.Value) ?? kv.Value;
}
}
dict ["AppUserModelID"] = app.UserModelID;
return dict;
@@ -595,7 +599,7 @@ namespace AppxPackage
{
var ret = new List<string> ();
if (!IsValid) return ret;
IntPtr hList = PackageReadHelper.GetCapabilitiesList (m_hReader.Value);
IntPtr hList = PackageReadHelper.GetManifestCapabilitiesList (m_hReader.Value);
if (hList == IntPtr.Zero) return ret;
try
{
@@ -622,7 +626,7 @@ namespace AppxPackage
{
var ret = new List<string> ();
if (!IsValid) return ret;
IntPtr hList = PackageReadHelper.GetDeviceCapabilitiesList (m_hReader.Value);
IntPtr hList = PackageReadHelper.GetManifestDeviceCapabilitiesList (m_hReader.Value);
if (hList == IntPtr.Zero) return ret;
try
{
@@ -685,7 +689,7 @@ namespace AppxPackage
{
var output = new List<DependencyInfo> ();
if (!IsValid) return output;
IntPtr hList = PackageReadHelper.GetDependencesInfoList (m_hReader);
IntPtr hList = PackageReadHelper.GetManifestDependencesInfoList (m_hReader);
if (hList == IntPtr.Zero) return output;
try
{
@@ -737,7 +741,7 @@ namespace AppxPackage
var ret = new List<DXFeatureLevel> ();
try
{
var dw = PackageReadHelper.GetResourcesDxFeatureLevels (m_hReader);
var dw = PackageReadHelper.GetManifestResourcesDxFeatureLevels (m_hReader);
if ((dw & 0x1) != 0) ret.Add (DXFeatureLevel.Level9);
if ((dw & 0x2) != 0) ret.Add (DXFeatureLevel.Level10);
if ((dw & 0x4) != 0) ret.Add (DXFeatureLevel.Level11);
@@ -753,7 +757,7 @@ namespace AppxPackage
{
var ret = new List<string> ();
if (!IsValid) return ret;
IntPtr hList = PackageReadHelper.GetResourcesLanguages (m_hReader.Value);
IntPtr hList = PackageReadHelper.GetManifestResourcesLanguages (m_hReader.Value);
if (hList == IntPtr.Zero) return ret;
try
{
@@ -772,7 +776,7 @@ namespace AppxPackage
{
var ret = new List<int> ();
if (!IsValid) return ret;
IntPtr hList = PackageReadHelper.GetResourcesLanguagesToLcid (m_hReader.Value);
IntPtr hList = PackageReadHelper.GetManifestResourcesLanguagesToLcid (m_hReader.Value);
if (hList == IntPtr.Zero) return ret;
try
{
@@ -791,7 +795,7 @@ namespace AppxPackage
{
var ret = new List<int> ();
if (!IsValid) return ret;
IntPtr hList = PackageReadHelper.GetResourcesLanguagesToLcid (m_hReader.Value);
IntPtr hList = PackageReadHelper.GetManifestResourcesLanguagesToLcid (m_hReader.Value);
if (hList == IntPtr.Zero) return ret;
try
{
@@ -826,7 +830,7 @@ namespace AppxPackage
}
protected string GetVersionDescription (string name)
{
var ptr = PackageReadHelper.GetPackagePrerequistieSystemVersionName (m_hReader, name);
var ptr = PackageReadHelper.GetManifestPrerequistieSystemVersionName (m_hReader, name);
return PackageReadHelper.GetStringAndFreeFromPkgRead (ptr) ?? "";
}
public string OSMaxVersionDescription { get { return GetVersionDescription ("OSMaxVersionTested"); } }
@@ -854,7 +858,7 @@ namespace AppxPackage
private bool m_enablePRI = false;
private PriReader m_pri = null;
public IntPtr Instance => m_hReader;
public string FileRoot{ get { return Path.GetPathRoot (m_filePath); } }
public string FileRoot{ get { return Path.GetDirectoryName (m_filePath); } }
private void InitPri ()
{
m_pri?.Dispose ();
@@ -916,15 +920,15 @@ namespace AppxPackage
public MRDependencies Dependencies { get { return new MRDependencies (ref m_hReader); } }
public void Dispose ()
{
var lastvalue = m_usePRI;
m_usePRI = false;
InitPri ();
m_usePRI = lastvalue;
if (m_hReader != IntPtr.Zero)
{
PackageReadHelper.DestroyManifestReader (m_hReader);
m_hReader = IntPtr.Zero;
}
var lastvalue = m_usePRI;
m_usePRI = false;
InitPri ();
m_usePRI = lastvalue;
}
~ManifestReader () { Dispose (); }
public string FilePath
@@ -985,5 +989,7 @@ namespace AppxPackage
applications = Applications.BuildJSON ()
};
}
public static bool AddApplicationItem (string itemName) => PackageReadHelper.AddPackageApplicationItemGetName (itemName);
public static bool RemoveApplicationItem (string itemName) => PackageReadHelper.RemovePackageApplicationItemGetName (itemName);
}
}

View File

@@ -603,5 +603,17 @@ namespace AppxPackage
GC.KeepAlive (callback);
}
}
public static DataUtils._I_HResult ActiveApp (string appUserId)
{
uint processId;
var hr = PackageManageHelper.ActivateAppxApplication (appUserId, out processId);
return new DataUtils._I_HResult (hr);
}
public static DataUtils._I_HResult ActiveApp (string appUserId, string cmdargs)
{
uint processId;
var hr = PackageManageHelper.ActivateAppxApplicationWithArgs (appUserId, cmdargs, out processId);
return new DataUtils._I_HResult (hr);
}
}
}

View File

@@ -698,6 +698,10 @@ namespace AppxPackage
{
dict [(kv.Key?.Trim () ?? "") + "_Base64"] = app.NewAtBase64 (kv.Key);
}
else
{
dict [kv.Key] = app.NewAt (kv.Key, m_usePri.Value && m_enablePri.Value) ?? kv.Value;
}
}
dict ["AppUserModelID"] = app.UserModelID;
return dict;
@@ -1182,5 +1186,7 @@ namespace AppxPackage
applications = Applications.BuildJSON ()
};
}
public static bool AddApplicationItem (string itemName) => PackageReadHelper.AddPackageApplicationItemGetName (itemName);
public static bool RemoveApplicationItem (string itemName) => PackageReadHelper.RemovePackageApplicationItemGetName (itemName);
}
}

View File

@@ -143,6 +143,8 @@ namespace NativeWrappers
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode)]
public static extern void PackageManagerFreeString (IntPtr lpString);
[DllImport (DllName, CallingConvention = CallConv, CharSet = CharSet.Unicode, ExactSpelling = true)]
public static extern HRESULT ActivateAppxApplicationWithArgs ([MarshalAs (UnmanagedType.LPWStr)] string lpAppUserId, [MarshalAs (UnmanagedType.LPWStr)] string lpArguments, out DWORD pdwProcessId);
// ========== 托管辅助 ==========
public static string PtrToStringAndFree (IntPtr nativePtr)

View File

@@ -13,6 +13,8 @@ using Newtonsoft.Json;
using AppxPackage;
using ModernNotice;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace Bridge
{
@@ -182,8 +184,17 @@ namespace Bridge
}
internal static class JsAsyncRunner
{
public static void Run (
Func<Action<object>, JsAsyncResult> work,
private static readonly int MaxConcurrency =
Math.Min (8, Environment.ProcessorCount * 2);
private static readonly SemaphoreSlim _semaphore =
new SemaphoreSlim (MaxConcurrency);
private static CancellationTokenSource _cts =
new CancellationTokenSource ();
public static Task Run (
Func<CancellationToken, Action<object>, JsAsyncResult> work,
object jsSuccess,
object jsFailed,
object jsProgress)
@@ -191,18 +202,30 @@ namespace Bridge
var success = jsSuccess;
var failed = jsFailed;
var progress = jsProgress;
var token = _cts.Token;
System.Threading.ThreadPool.QueueUserWorkItem (_ =>
return Task.Factory.StartNew (() =>
{
bool entered = false;
try
{
_semaphore.Wait (token);
entered = true;
token.ThrowIfCancellationRequested ();
Action<object> reportProgress = p =>
{
if (progress != null)
if (!token.IsCancellationRequested && progress != null)
CallJS (progress, p);
};
JsAsyncResult result = work (reportProgress);
if (result == null) return;
var result = work (token, reportProgress);
if (token.IsCancellationRequested || result == null)
return;
switch (result.Kind)
{
case JsAsyncResultKind.Success:
@@ -212,19 +235,48 @@ namespace Bridge
case JsAsyncResultKind.Failed:
CallJS (failed, result.Value);
break;
case JsAsyncResultKind.None:
default:
break;
}
}
catch (OperationCanceledException)
{
// 只对“已进入执行态”的任务回调取消
if (!entered)
return;
var cancelObj = new
{
status = false,
canceled = true,
message = "Operation canceled",
jsontext = ""
};
CallJS (failed,
Newtonsoft.Json.JsonConvert.SerializeObject (cancelObj));
}
catch (Exception ex)
{
// 框架级异常兜底 → failed
CallJS (jsFailed, ex.Message);
var errObj = new
{
status = false,
message = ex.Message,
jsontext = ""
};
CallJS (failed,
Newtonsoft.Json.JsonConvert.SerializeObject (errObj));
}
});
finally
{
if (entered)
_semaphore.Release ();
}
},
token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
private static void CallJS (object jsFunc, params object [] args)
{
if (jsFunc == null) return;
@@ -235,18 +287,43 @@ namespace Bridge
if (args != null)
for (int i = 0; i < args.Length; i++)
invokeArgs [i + 1] = args [i];
jsFunc.GetType ().InvokeMember (
"call",
System.Reflection.BindingFlags.InvokeMethod,
BindingFlags.InvokeMethod,
null,
jsFunc,
invokeArgs
);
invokeArgs);
}
catch
{
}
}
// 兼容旧版:只有 reportProgress 的写法
public static Task Run (
Func<Action<object>, JsAsyncResult> work,
object jsSuccess,
object jsFailed,
object jsProgress)
{
return Run (
(token, report) => {
token.ThrowIfCancellationRequested ();
return work (report);
},
jsSuccess,
jsFailed,
jsProgress
);
}
public static void CancelAll ()
{
var old = _cts;
_cts = new CancellationTokenSource ();
old.Cancel ();
old.Dispose ();
}
}
private string BuildJsonText (object obj)
{
@@ -490,11 +567,17 @@ namespace Bridge
null
);
}
public _I_HResult ActiveApp (string appUserId, string args) { return PackageManager.ActiveApp (appUserId, args); }
public _I_HResult ActiveAppByIdentity (string idName, string appId, string args) { return ActiveApp ($"{idName?.Trim ()}!{appId?.Trim ()}", args); }
public void CancelAll () { JsAsyncRunner.CancelAll (); }
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_Package
public class _I_PackageReader
{
private static readonly int MaxConcurrency = Math.Min (8, Environment.ProcessorCount * 2);
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim (MaxConcurrency);
private static CancellationTokenSource _cts = new CancellationTokenSource ();
private static void CallJS (object jsFunc, params object [] args)
{
if (jsFunc == null) return;
@@ -518,160 +601,267 @@ namespace Bridge
// ignore errors in callback invocation
}
}
public AppxPackage.PackageReader Reader (string packagePath) { return new AppxPackage.PackageReader (packagePath); }
public _I_PackageManager Manager => new _I_PackageManager ();
private static Task RunAsync (Action<CancellationToken> work, object successCallback, object failedCallback)
{
var token = _cts.Token;
return Task.Factory.StartNew (() => {
_semaphore.Wait (token);
try
{
token.ThrowIfCancellationRequested ();
work (token);
}
catch (OperationCanceledException oce)
{
var errObj = new
{
status = false,
message = "Task is canceled. Message: " + oce.Message,
jsontext = ""
};
string errJson = Newtonsoft.Json.JsonConvert.SerializeObject (errObj);
if (failedCallback != null) CallJS (failedCallback, errJson);
}
catch (Exception ex)
{
var errObj = new
{
status = false,
message = ex.Message,
jsontext = ""
};
string errJson = Newtonsoft.Json.JsonConvert.SerializeObject (errObj);
if (failedCallback != null) CallJS (failedCallback, errJson);
}
finally
{
_semaphore.Release ();
}
},
token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
public AppxPackage.PackageReader Package (string packagePath) { return new AppxPackage.PackageReader (packagePath); }
public AppxPackage.ManifestReader Manifest (string manifestPath) { return new AppxPackage.ManifestReader (manifestPath); }
public AppxPackage.ManifestReader FromInstallLocation (string installLocation) { return Manifest (Path.Combine (installLocation, "AppxManifest.xml")); }
public void ReadFromPackageAsync (string packagePath, bool enablePri, object successCallback, object failedCallback)
public Task ReadFromPackageAsync (string packagePath, bool enablePri, object successCallback, object failedCallback)
{
Thread thread = new Thread (() => {
try
return RunAsync (token => {
string cacheKey = BuildCacheKey (packagePath, enablePri, ReadKind.Package);
if (TryHitCache (cacheKey, successCallback)) return;
using (var reader = Package (packagePath))
{
using (var reader = Reader (packagePath))
if (enablePri)
{
if (enablePri)
reader.EnablePri = true;
reader.UsePri = true;
}
token.ThrowIfCancellationRequested ();
if (!reader.IsValid)
{
var failObj = new
{
reader.EnablePri = true;
reader.UsePri = true;
}
if (!reader.IsValid)
{
var failObj = new
{
status = false,
message = "Reader invalid",
jsontext = ""
};
string failJson = Newtonsoft.Json.JsonConvert.SerializeObject (failObj);
if (failedCallback != null) CallJS (failedCallback, failJson);
return;
}
var obj = new
{
status = true,
message = "ok",
jsontext = reader.BuildJsonText () // 你之前写好的函数
status = false,
message = "Reader invalid",
jsontext = ""
};
string json = Newtonsoft.Json.JsonConvert.SerializeObject (obj);
if (successCallback != null) CallJS (successCallback, json);
string failJson = Newtonsoft.Json.JsonConvert.SerializeObject (failObj);
if (failedCallback != null) CallJS (failedCallback, failJson);
return;
}
var obj = new
{
status = true,
message = "ok",
jsontext = reader.BuildJsonText ()
};
string json = Newtonsoft.Json.JsonConvert.SerializeObject (obj);
if (!token.IsCancellationRequested && successCallback != null) CallJS (successCallback, json);
SaveCache (cacheKey, json);
}
}, successCallback, failedCallback);
}
public Task ReadFromManifestAsync (string manifestPath, bool enablePri, object successCallback, object failedCallback)
{
return RunAsync (token => {
string cacheKey = BuildCacheKey (manifestPath, enablePri, ReadKind.Manifest);
if (TryHitCache (cacheKey, successCallback)) return;
using (var reader = Manifest (manifestPath))
{
if (enablePri)
{
reader.EnablePri = true;
reader.UsePri = true;
}
token.ThrowIfCancellationRequested ();
if (!reader.IsValid)
{
var failObj = new
{
status = false,
message = "Reader invalid",
jsontext = ""
};
string failJson = Newtonsoft.Json.JsonConvert.SerializeObject (failObj);
if (failedCallback != null) CallJS (failedCallback, failJson);
return;
}
var obj = new
{
status = true,
message = "ok",
jsontext = reader.BuildJsonText ()
};
string json = Newtonsoft.Json.JsonConvert.SerializeObject (obj);
if (!token.IsCancellationRequested && successCallback != null) CallJS (successCallback, json);
SaveCache (cacheKey, json);
}
}, successCallback, failedCallback);
}
public Task ReadFromInstallLocationAsync (string installLocation, bool enablePri, object successCallback, object failedCallback)
{
return RunAsync (token => {
var manifestpath = Path.Combine (installLocation, "AppxManifest.xml");
string cacheKey = BuildCacheKey (manifestpath, enablePri, ReadKind.Manifest);
if (TryHitCache (cacheKey, successCallback)) return;
using (var reader = FromInstallLocation (installLocation))
{
if (enablePri)
{
reader.EnablePri = true;
reader.UsePri = true;
}
token.ThrowIfCancellationRequested ();
if (!reader.IsValid)
{
var failObj = new
{
status = false,
message = "Reader invalid",
jsontext = ""
};
string failJson = Newtonsoft.Json.JsonConvert.SerializeObject (failObj);
if (failedCallback != null) CallJS (failedCallback, failJson);
return;
}
var obj = new
{
status = true,
message = "ok",
jsontext = reader.BuildJsonText ()
};
string json = Newtonsoft.Json.JsonConvert.SerializeObject (obj);
if (!token.IsCancellationRequested && successCallback != null) CallJS (successCallback, json);
SaveCache (cacheKey, json);
}
}, successCallback, failedCallback);
}
public void CancelAll ()
{
var old = _cts;
_cts = new CancellationTokenSource ();
old.Cancel ();
old.Dispose ();
}
public bool AddApplicationItem (string itemName) => PackageReader.AddApplicationItem (itemName);
public bool RemoveApplicationItem (string itemName) => PackageReader.RemoveApplicationItem (itemName);
// Cache about
private const int MaxCacheItems = 64; // 最大缓存数量
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes (30);
internal sealed class CacheEntry
{
public string Json { get; private set; }
public DateTime ExpireAt { get; private set; }
public DateTime LastAccessUtc { get; private set; }
public CacheEntry (string json, DateTime expireAt)
{
Json = json;
ExpireAt = expireAt;
LastAccessUtc = DateTime.UtcNow;
}
public bool IsExpired { get { return DateTime.UtcNow > ExpireAt; } }
public void Touch () { LastAccessUtc = DateTime.UtcNow; }
}
private static readonly ConcurrentDictionary<string, CacheEntry> _cache = new ConcurrentDictionary<string, CacheEntry> ();
private static readonly object _cacheCleanupLock = new object ();
private static bool TryHitCache (string cacheKey, object successCallback)
{
CacheEntry entry;
if (_cache.TryGetValue (cacheKey, out entry))
{
if (!entry.IsExpired)
{
entry.Touch ();
if (successCallback != null) CallJS (successCallback, entry.Json);
return true;
}
CacheEntry removed;
_cache.TryRemove (cacheKey, out removed);
}
return false;
}
private static void SaveCache (string cacheKey, string json)
{
var entry = new CacheEntry (
json,
DateTime.UtcNow.Add (CacheDuration)
);
_cache [cacheKey] = entry;
EnsureCacheSize ();
}
private static void EnsureCacheSize ()
{
if (_cache.Count <= MaxCacheItems) return;
lock (_cacheCleanupLock)
{
if (_cache.Count <= MaxCacheItems) return;
foreach (var kv in _cache)
{
if (kv.Value.IsExpired)
{
CacheEntry removed;
_cache.TryRemove (kv.Key, out removed);
}
}
catch (Exception ex)
if (_cache.Count <= MaxCacheItems) return;
while (_cache.Count > MaxCacheItems)
{
var errObj = new
string oldestKey = null;
DateTime oldest = DateTime.MaxValue;
foreach (var kv in _cache)
{
status = false,
message = ex.Message,
jsontext = ""
};
string errJson = Newtonsoft.Json.JsonConvert.SerializeObject (errObj);
if (failedCallback != null) CallJS (failedCallback, errJson);
}
});
thread.IsBackground = true;
thread.SetApartmentState (ApartmentState.MTA);
thread.Start ();
}
public void ReadFromManifestAsync (string manifestPath, bool enablePri, object successCallback, object failedCallback)
{
Thread thread = new Thread (() => {
try
{
using (var reader = Manifest (manifestPath))
{
if (enablePri)
if (kv.Value.LastAccessUtc < oldest)
{
reader.EnablePri = true;
reader.UsePri = true;
oldest = kv.Value.LastAccessUtc;
oldestKey = kv.Key;
}
if (!reader.IsValid)
{
var failObj = new
{
status = false,
message = "Reader invalid",
jsontext = ""
};
string failJson = Newtonsoft.Json.JsonConvert.SerializeObject (failObj);
if (failedCallback != null) CallJS (failedCallback, failJson);
return;
}
var obj = new
{
status = true,
message = "ok",
jsontext = reader.BuildJsonText () // 你之前写好的函数
};
string json = Newtonsoft.Json.JsonConvert.SerializeObject (obj);
if (successCallback != null) CallJS (successCallback, json);
}
if (oldestKey == null) break;
CacheEntry removed;
_cache.TryRemove (oldestKey, out removed);
}
catch (Exception ex)
{
var errObj = new
{
status = false,
message = ex.Message,
jsontext = ""
};
string errJson = Newtonsoft.Json.JsonConvert.SerializeObject (errObj);
if (failedCallback != null) CallJS (failedCallback, errJson);
}
});
thread.IsBackground = true;
thread.SetApartmentState (ApartmentState.MTA);
thread.Start ();
}
}
public void ReadFromInstallLocationAsync (string installLocation, bool enablePri, object successCallback, object failedCallback)
private static string NormalizePath (string path)
{
Thread thread = new Thread (() => {
try
{
using (var reader = FromInstallLocation (installLocation))
{
if (enablePri)
{
reader.EnablePri = true;
reader.UsePri = true;
}
if (!reader.IsValid)
{
var failObj = new
{
status = false,
message = "Reader invalid",
jsontext = ""
};
string failJson = Newtonsoft.Json.JsonConvert.SerializeObject (failObj);
if (failedCallback != null) CallJS (failedCallback, failJson);
return;
}
var obj = new
{
status = true,
message = "ok",
jsontext = reader.BuildJsonText () // 你之前写好的函数
};
string json = Newtonsoft.Json.JsonConvert.SerializeObject (obj);
if (successCallback != null) CallJS (successCallback, json);
}
}
catch (Exception ex)
{
var errObj = new
{
status = false,
message = ex.Message,
jsontext = ""
};
string errJson = Newtonsoft.Json.JsonConvert.SerializeObject (errObj);
if (failedCallback != null) CallJS (failedCallback, errJson);
}
});
thread.IsBackground = true;
thread.SetApartmentState (ApartmentState.MTA);
thread.Start ();
if (string.IsNullOrWhiteSpace (path)) return string.Empty;
path = path.Trim ();
while (path.EndsWith ("\\") || path.EndsWith ("/")) path = path.Substring (0, path.Length - 1);
return path.ToLowerInvariant ();
}
private enum ReadKind { Package, Manifest }
private static string BuildCacheKey (string path, bool enablePri, ReadKind kind)
{
return NormalizePath (path) + "|" + enablePri.ToString () + "|" + kind.ToString ();
}
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]
public class _I_Package
{
public _I_PackageReader Reader => new _I_PackageReader ();
public _I_PackageManager Manager => new _I_PackageManager ();
}
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.AutoDual)]

90
Launch/Launch.csproj Normal file
View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F0288B24-7B84-42A5-9A92-2E16A012E4DE}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Launch</RootNamespace>
<AssemblyName>Launch</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="app.manifest" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AppxPackage\AppxPackage.csproj">
<Project>{bd681a4f-eb60-4bb8-90b5-65968fc7da59}</Project>
<Name>AppxPackage</Name>
</ProjectReference>
<ProjectReference Include="..\DataUtils\DataUtils.csproj">
<Project>{FFD3FD52-37A8-4F43-883C-DE8D996CB0E0}</Project>
<Name>DataUtils</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

68
Launch/Program.cs Normal file
View File

@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Launch
{
static class Program
{
/// <summary>
/// 从 args[startIndex..] 生成安全的命令行字符串
/// </summary>
private static string BuildCommandLine (string [] args, int startIndex)
{
if (args.Length <= startIndex) return null;
var sb = new StringBuilder ();
for (int i = startIndex; i < args.Length; i++)
{
if (i > startIndex) sb.Append (' ');
sb.Append (EscapeArgument (args [i]));
}
return sb.ToString ();
}
/// <summary>
/// 按 Win32 命令行规则转义单个参数
/// </summary>
private static string EscapeArgument (string arg)
{
if (string.IsNullOrEmpty (arg)) return "\"\"";
bool needQuotes = false;
foreach (char c in arg)
{
if (char.IsWhiteSpace (c) || c == '"')
{
needQuotes = true;
break;
}
}
if (!needQuotes) return arg;
var sb = new StringBuilder ();
sb.Append ('"');
foreach (char c in arg)
{
if (c == '"') sb.Append ("\\\"");
else sb.Append (c);
}
sb.Append ('"');
return sb.ToString ();
}
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main (string [] args)
{
if (args == null || args.Length == 0)
{
MessageBox.Show ("Missing AppUserModelId.", "Launch Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
string appUserModelId = args [0];
string argumentLine = BuildCommandLine (args, 1);
AppxPackage.PackageManager.ActiveApp (appUserModelId, string.IsNullOrEmpty (argumentLine) ? null : argumentLine);
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle ("Launch")]
[assembly: AssemblyDescription ("")]
[assembly: AssemblyConfiguration ("")]
[assembly: AssemblyCompany ("")]
[assembly: AssemblyProduct ("Launch")]
[assembly: AssemblyCopyright ("Copyright © 2026")]
[assembly: AssemblyTrademark ("")]
[assembly: AssemblyCulture ("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible (false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid ("f0288b24-7b84-42a5-9a92-2e16a012e4de")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion ("1.0.0.0")]
[assembly: AssemblyFileVersion ("1.0.0.0")]

71
Launch/Properties/Resources.Designer.cs generated Normal file
View File

@@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Launch.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute ("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute ()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute ()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute ("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources ()
{
}
/// <summary>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute (global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager ("Launch.Properties.Resources", typeof (Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 覆盖当前线程的 CurrentUICulture 属性
/// 使用此强类型的资源类的资源查找。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute (global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

30
Launch/Properties/Settings.Designer.cs generated Normal file
View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Launch.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute ()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute ("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings: global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized (new Settings ())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

75
Launch/app.manifest Normal file
View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC 清单选项
如果想要更改 Windows 用户帐户控制级别,请使用
以下节点之一替换 requestedExecutionLevel 节点。n
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
如果你的应用程序需要此虚拟化来实现向后兼容性,则删除此
元素。
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的
Windows 版本的列表。取消评论适当的元素Windows 将
自动选择最兼容的环境。 -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
<!-- Windows 8 -->
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
<!-- Windows 8.1 -->
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
<!-- Windows 10 -->
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
</application>
</compatibility>
<!-- 指示该应用程序可以感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI无需
选择加入。选择加入此设置的 Windows 窗体应用程序(目标设定为 .NET Framework 4.6 )还应
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。-->
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
<!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) -->
<!--
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
-->
</assembly>

View File

@@ -34,6 +34,24 @@
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -56,6 +74,7 @@
<Compile Include="Polyfill.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ShortcutCreateForm.cs" />
<EmbeddedResource Include="ManagerShell.resx">
<DependentUpon>ManagerShell.cs</DependentUpon>
</EmbeddedResource>

View File

@@ -1,13 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
namespace Manager
{
public partial class ManagerShell: WAShell.WebAppForm

View File

@@ -15,6 +15,7 @@ namespace Manager
[STAThread]
static void Main ()
{
AppxPackage.PackageReader.AddApplicationItem ("SmallLogo");
DataUtils.BrowserEmulation.SetWebBrowserEmulation ();
Application.EnableVisualStyles ();
Application.SetCompatibleTextRenderingDefault (false);

View File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Manager
{
class ShortcutCreateForm
{
}
}

Binary file not shown.

View File

@@ -821,7 +821,8 @@ public ref class AppListWnd: public System::Windows::Forms::Form, public IScript
if (color.empty () || color.equals (L"transparent")) color = MPStringToStdW (ColorToHtml (GetDwmThemeColor ()));
std::wnstring displayName = app [L"DisplayName"];
if (displayName.empty ()) displayName = app [L"ShortName"];
auto &logo = app [L"Square44x44Logo"];
auto logo = app [L"Square44x44Logo"];
if (std::wnstring::empty (logo)) logo = app [L"SmallLogo"];
InvokeCallScriptFunction (
"addAppToList",
CStringToMPString (displayName),

View File

@@ -1003,3 +1003,33 @@ HRESULT WRTAppDataClearAll (HWRTAPPDATA hAppData, LPWSTR *pErrorCode, LPWSTR *pD
}
return E_FAIL;
}
[STAThread]
HRESULT ActivateAppxApplicationWithArgs (LPCWSTR lpAppUserId, LPCWSTR lpArguments, PDWORD pdwProcessId)
{
HRESULT hr = CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED);
if (FAILED (hr) && hr != RPC_E_CHANGED_MODE) return hr;
if (!lpAppUserId) return E_INVALIDARG;
std::wstring appUserModelId (lpAppUserId);
IApplicationActivationManager *pAam = nullptr;
destruct autoRelease ([&] {
if (pAam) pAam->Release ();
});
hr = CoCreateInstance (
CLSID_ApplicationActivationManager,
nullptr,
CLSCTX_LOCAL_SERVER,
IID_IApplicationActivationManager,
(void **)&pAam
);
if (FAILED (hr)) return hr;
CoAllowSetForegroundWindow (pAam, nullptr);
DWORD pid = 0;
hr = pAam->ActivateApplication (
appUserModelId.c_str (),
lpArguments && *lpArguments ? lpArguments : nullptr, // 允许空
AO_NONE,
&pid
);
if (SUCCEEDED (hr) && pdwProcessId) *pdwProcessId = pid;
return hr;
}

View File

@@ -203,6 +203,8 @@ extern "C"
PKGMGR_API HRESULT CreateAppDataManager (LPCWSTR lpFamilyName, HWRTAPPDATA *ppApplicationData, LPWSTR *pErrorCode, LPWSTR *pDetailMsg);
// 从本地、漫游和临时应用数据存储中删除所有应用程序数据。
PKGMGR_API HRESULT WRTAppDataClearAll (HWRTAPPDATA hAppData, LPWSTR *pErrorCode, LPWSTR *pDetailMsg);
PKGMGR_API HRESULT ActivateAppxApplicationWithArgs (LPCWSTR lpAppUserId, LPCWSTR lpArguments, PDWORD pdwProcessId);
#ifdef _DEFAULT_INIT_VALUE_
#undef _DEFAULT_INIT_VALUE_
#endif

View File

@@ -509,11 +509,137 @@ namespace appx_info
class appx_apps: virtual public com_info <IAppxManifestApplicationsEnumerator>
{
using Base = com_info <IAppxManifestApplicationsEnumerator>;
CComPtr <IAppxManifestReader> manifest = nullptr;
protected:
mutable std::map<std::wstring, std::map<std::wstring, std::wstring>> xml_cache;
mutable bool xml_parsed = false;
void parse_xml () const
{
if (xml_parsed || !manifest) return;
CComPtr<IStream> xmlstream;
if (FAILED (manifest->GetStream (&xmlstream)) || !xmlstream)
return;
LARGE_INTEGER zero {};
xmlstream->Seek (zero, STREAM_SEEK_SET, nullptr);
CComPtr<IXmlReader> reader;
if (FAILED (CreateXmlReader (__uuidof(IXmlReader), (void**)&reader, nullptr)))
return;
reader->SetInput (xmlstream);
XmlNodeType nodeType;
bool inApplication = false;
std::wstring currentId;
std::map<std::wstring, std::wstring> currentValues;
while (S_OK == reader->Read (&nodeType))
{
if (nodeType == XmlNodeType_Element)
{
LPCWSTR name = nullptr;
reader->GetLocalName (&name, nullptr);
if (!_wcsicmp (name, L"Application"))
{
inApplication = true;
currentValues.clear ();
currentId.clear ();
auto read_attr = [&] (const wchar_t* xmlName, const wchar_t* key)
{
if (SUCCEEDED (reader->MoveToAttributeByName (xmlName, nullptr)))
{
LPCWSTR v = nullptr;
reader->GetValue (&v, nullptr);
if (v) currentValues [key] = v;
reader->MoveToElement ();
}
};
read_attr (L"Id", L"ID");
read_attr (L"Executable", L"Executable");
read_attr (L"EntryPoint", L"EntryPoint");
read_attr (L"StartPage", L"StartPage");
currentId = currentValues [L"ID"];
}
else if (inApplication)
{
auto read_attr = [&] (const wchar_t* xmlName, const wchar_t* key)
{
if (SUCCEEDED (reader->MoveToAttributeByName (xmlName, nullptr)))
{
LPCWSTR v = nullptr;
reader->GetValue (&v, nullptr);
if (v) currentValues [key] = v;
reader->MoveToElement ();
}
};
if (!_wcsicmp (name, L"VisualElements"))
{
read_attr (L"DisplayName", L"DisplayName");
read_attr (L"Description", L"Description");
read_attr (L"BackgroundColor", L"BackgroundColor");
read_attr (L"ForegroundText", L"ForegroundText");
read_attr (L"Logo", L"Logo");
read_attr (L"SmallLogo", L"SmallLogo");
read_attr (L"Square44x44Logo", L"Square44x44Logo");
read_attr (L"Square150x150Logo", L"Square150x150Logo");
}
else if (!_wcsicmp (name, L"DefaultTile"))
{
read_attr (L"ShortName", L"ShortName");
read_attr (L"WideLogo", L"WideLogo");
read_attr (L"Wide310x150Logo", L"Wide310x150Logo");
read_attr (L"Square310x310Logo", L"Square310x310Logo");
read_attr (L"Square71x71Logo", L"Square71x71Logo");
}
else if (!_wcsicmp (name, L"LockScreen"))
{
read_attr (L"BadgeLogo", L"LockScreenLogo");
read_attr (L"Notification", L"LockScreenNotification");
}
}
}
else if (nodeType == XmlNodeType_EndElement)
{
LPCWSTR name = nullptr;
reader->GetLocalName (&name, nullptr);
if (!_wcsicmp (name, L"Application"))
{
// fallback常量
if (currentValues [L"Wide310x150Logo"].empty ())
currentValues [L"Wide310x150Logo"] = currentValues [L"WideLogo"];
if (currentValues [L"Square70x70Logo"].empty ())
currentValues [L"Square70x70Logo"] = currentValues [L"Square71x71Logo"];
if (!currentId.empty ()) xml_cache [currentId] = currentValues;
inApplication = false;
currentValues.clear ();
currentId.clear ();
}
}
}
xml_parsed = true;
}
std::wstring get_value_ext (const std::wstring& appId, const std::wstring& item) const
{
parse_xml (); // 只会解析一次
auto it = xml_cache.find (appId);
if (it == xml_cache.end ()) return L"";
auto jt = it->second.find (item);
return (jt != it->second.end ()) ? jt->second : L"";
}
public:
using Base::Base;
appx_apps (IAppxManifestApplicationsEnumerator *ptr, IAppxManifestReader *mptr):
Base (ptr), manifest (mptr) {}
size_t applications (_Out_ std::vector <app_info> &output) const
{
return EnumerateComInterface <IAppxManifestApplicationsEnumerator, IAppxManifestApplication *, app_info> (pointer (), output, [] (IAppxManifestApplication *&p) -> app_info {
auto ret = EnumerateComInterface <IAppxManifestApplicationsEnumerator, IAppxManifestApplication *, app_info> (pointer (), output, [] (IAppxManifestApplication *&p) -> app_info {
raii rel ([&p] () {
if (p) p->Release ();
p = nullptr;
@@ -544,6 +670,16 @@ namespace appx_info
}
return app;
});
for (auto &it : output)
{
auto id = it [L"Id"];
for (auto &kv : it)
{
if (IsNormalizeStringEmpty (kv.second))
kv.second = get_value_ext (id, kv.first);
}
}
return ret;
}
size_t app_user_model_ids (_Out_ std::vector <std::wstring> &output) const
{
@@ -910,9 +1046,11 @@ class appxreader: virtual public com_info_quote <IAppxPackageReader>
HRESULT get_applications (_Outptr_ IAppxManifestApplicationsEnumerator **output) const { return get_from_manifest <IAppxManifestApplicationsEnumerator *> (&Manifest::GetApplications, output); }
appx_info::appx_apps applications () const
{
IAppxManifestReader *m = nullptr;
IAppxManifestApplicationsEnumerator *ip = nullptr;
manifest (&m);
get_applications (&ip);
return appx_info::appx_apps (ip);
return appx_info::appx_apps (ip, m);
}
HRESULT get_capabilities (_Outptr_ APPX_CAPABILITIES *output) const { return get_from_manifest <APPX_CAPABILITIES> (&Manifest::GetCapabilities, output); }
HRESULT get_device_capabilities (_Outptr_ IAppxManifestDeviceCapabilitiesEnumerator **output) const { return get_from_manifest <IAppxManifestDeviceCapabilitiesEnumerator *> (&Manifest::GetDeviceCapabilities, output); }
@@ -1377,7 +1515,7 @@ class appxmanifest: virtual public com_info_quote <IAppxManifestReader>
{
IAppxManifestApplicationsEnumerator *ip = nullptr;
get_applications (&ip);
return appx_info::appx_apps (ip);
return appx_info::appx_apps (ip, pointer ());
}
HRESULT get_capabilities (_Outptr_ APPX_CAPABILITIES *output) const { return get_from_manifest <APPX_CAPABILITIES> (&Manifest::GetCapabilities, output); }
HRESULT get_device_capabilities (_Outptr_ IAppxManifestDeviceCapabilitiesEnumerator **output) const { return get_from_manifest <IAppxManifestDeviceCapabilitiesEnumerator *> (&Manifest::GetDeviceCapabilities, output); }

View File

@@ -101,7 +101,8 @@ std::vector <std::wstring> appitems =
L"BackgroundColor",
L"ForegroundText",
L"ShortName",
L"Square44x44Logo"
L"Square44x44Logo",
L"SmallLogo"
};
std::vector <std::wstring> &GetApplicationAttributeItems () { return appitems; }
static CriticalSection g_appcs;

View File

@@ -0,0 +1,29 @@
.statusbar {
overflow-x: hidden;
overflow-y: hidden;
}
.statusbar.x {
width: 0;
}
.statusbar.y {
height: 0;
}
.statusbar.both {
width: 0;
height: 0;
}
.statusbar.fast {
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);
}
.statusbar.medium {
transition: all 0.5s cubic-bezier(0.1, 0.9, 0.2, 1);
}
.statusbar.slow {
transition: all 0.7s cubic-bezier(0.1, 0.9, 0.2, 1);
}

View File

@@ -312,9 +312,15 @@
function hideTouchHide() {
touchHide.style.display = "none";
}
var timerHide = null;
this.show = function() {
try {
if (!_enable) return;
if (timerHide) {
clearTimeout(timerHide);
timerHide = null;
}
this.element.style.display = "";
if (!this.element.classList.contains("show"))
this.element.classList.add("show");
waitTimer(500);
@@ -323,8 +329,16 @@
};
this.hide = function() {
try {
if (timerHide) {
clearTimeout(timerHide);
timerHide = null;
}
if (this.element.classList.contains("show"))
this.element.classList.remove("show");
timerHide = setTimeout(function() {
timerHide = null;
self.element.style.display = "none";
}, 500);
waitTimer(500);
hideTouchHide();
} catch (e) {}

View File

@@ -102,4 +102,20 @@
get: function() { return ext.System.UI.SplashImage; },
});
} catch (e) {}
// 下面是有关 String 方法的补充
if (typeof String.prototype.trim !== "function") {
String.prototype.trim = function() {
return Bridge.String.trim(this);
};
}
if (typeof String.prototype.toLowerCase !== "function") {
String.prototype.toLowerCase = function() {
return Bridge.String.tolower(this);
};
}
if (typeof String.prototype.toUpperCase !== "function") {
String.prototype.toUpperCase = function() {
return Bridge.String.toupper(this);
};
}
})(this);

View File

@@ -13,6 +13,7 @@
var childAnimeDuration = 120;
var parentAnimeDuration = 400;
function showItemAmine(node) {
return Windows.UI.Animation.runAsync(node, [
Windows.UI.Animation.Keyframes.Scale.up,
@@ -27,6 +28,23 @@
], childAnimeDuration);
}
function noAnime(node) {
return Promise.resolve(node);
}
function runShowAnime(node, enable) {
if (enable === void 0) enable = true;
if (!enable) return noAnime(node);
return showItemAmine(node);
}
function runHideAnime(node, enable) {
if (enable === void 0) enable = true;
if (!enable) return noAnime(node);
return hideItemAmine(node);
}
function updateItemAmine(node, updateCallback) {
return Windows.UI.Animation.runAsync(node, [
Windows.UI.Animation.Keyframes.Opacity.hidden,
@@ -53,6 +71,43 @@
function PMDataSource() {
var _list = [];
var _listeners = [];
var _keySelector = null;
var _autoKeySeed = 1;
this.setKeySelector = function(fn) {
_keySelector = (typeof fn === "function") ? fn : null;
};
function getKey(item) {
if (!item) return null;
// 用户提供
if (_keySelector) {
return _keySelector(item);
}
// 自动注入(对象)
if (typeof item === "object") {
if (item.__pm_key !== void 0) {
return item.__pm_key;
}
try {
Object.defineProperty(item, "__pm_key", {
value: "pm_" + (_autoKeySeed++),
enumerable: false
});
} catch (e) {
// IE10 兜底
item.__pm_key = "pm_" + (_autoKeySeed++);
}
return item.__pm_key;
}
// 原始类型兜底
return typeof item + ":" + item;
}
this.subscribe = function(fn) {
if (typeof fn === "function") {
_listeners.push(fn);
@@ -64,26 +119,47 @@
_listeners[i](evt);
}
}
this.indexOf = function(item) {
var key = getKey(item);
for (var i = 0; i < _list.length; i++) {
if (getKey(_list[i]) === key) {
return i;
}
}
return -1;
};
this.add = function(item) {
_list.push(item);
emit(new PMChangeEvent(
DataView.ChangeType.add, [item], { index: _list.length - 1 }
DataView.ChangeType.add, [{ item: item, index: _list.length - 1, key: getKey(item) }]
));
};
this.removeAt = function(index) {
if (index < 0 || index >= _list.length) return;
var item = _list.splice(index, 1)[0];
emit(new PMChangeEvent(
DataView.ChangeType.remove, [item], { index: index }
DataView.ChangeType.remove, [{ item: item, index: index, key: getKey(item) }]
));
};
this.remove = function(item) {
var index = this.indexOf(item);
if (index >= 0) {
this.removeAt(index);
}
};
this.changeAt = function(index, newItem) {
if (index < 0 || index >= _list.length) return;
_list[index] = newItem;
emit(new PMChangeEvent(
DataView.ChangeType.change, [newItem], { index: index }
DataView.ChangeType.change, [{ item: newItem, index: index, key: getKey(newItem) }]
));
};
this.change = function(oldItem, newItem) {
var index = this.indexOf(oldItem);
if (index >= 0) {
this.changeAt(index, newItem);
}
};
this.clear = function() {
_list.length = 0;
emit(new PMChangeEvent(
@@ -224,7 +300,6 @@
var changed = [];
var removed = [];
// 1⃣ 找 remove
for (i = oldList.length - 1; i >= 0; i--) {
var oldItem = oldList[i];
var oldKey = getKey(oldItem);
@@ -238,7 +313,6 @@
}
}
// 2⃣ 找 add / change
for (i = 0; i < newList.length; i++) {
var newItem = newList[i];
var newKey = getKey(newItem);
@@ -263,7 +337,6 @@
}
}
// 3⃣ 执行 remove从后往前
if (removed.length > 0) {
for (i = 0; i < removed.length; i++) {
_list.splice(removed[i].index, 1);
@@ -274,7 +347,6 @@
));
}
// 4⃣ 执行 add / change重建顺序
_list = newList.slice(0);
if (added.length > 0) {
@@ -291,25 +363,50 @@
));
}
};
this._getKey = getKey;
}
var MAX_ANIMATE_COUNT = 100;
function PMDataListView(container, templateFn) {
this.container = container;
this.templateFn = templateFn;
this.listViewControl = this;
this._emptyView = null;
// === 新增 ===
this._filter = null;
this._searchHandler = null;
this._searchText = null;
this._searchSuggestProvider = null;
this.onSearchSuggest = null; // function(text, list)
this._isSearching = false;
this.onsearchstart = null;
this.onsearchend = null;
}
PMDataListView.prototype.bind = function(ds) {
var self = this;
var items = ds.get();
this._ds = ds;
self.container.innerHTML = "";
var items = ds.get();
// 动画队列,保证异步操作不会乱序
var queue = Promise.resolve();
function renderItem(data, index) {
var el = self.templateFn(data, index);
var key = ds && ds._getKey ? ds._getKey(data) : null;
el.__pm_item = data;
el.__pm_key = key;
if (key != null) {
el.setAttribute("data-pm-key", key);
}
el.addEventListener("click", function() {
self._toggleSelect(el);
});
@@ -317,10 +414,13 @@
return el;
}
// 初始化渲染
for (var i = 0; i < items.length; i++) {
self.container.appendChild(renderItem(items[i], i));
}
// 初始化 emptyView 状态
self._updateEmptyView();
ds.subscribe(function(evt) {
@@ -337,37 +437,58 @@
var nodes = [];
for (var i = 0; i < datas.length; i++) {
var n = renderItem(datas[i].item, datas[i].index);
n.style.display = "none";
nodes.push(n);
self.container.appendChild(n);
}
// 如果数量>=20动画并行否则串行
if (datas.length >= 20) {
var enableAnime = datas.length <= MAX_ANIMATE_COUNT;
if (!enableAnime) {
return Promise.resolve();
}
// 如果数量>=20动画串行否则并行
if (datas.length <= 20) {
var promises = [];
for (var j = 0; j < nodes.length; j++) {
promises.push(showItemAmine(nodes[j]));
promises.push((function(node) {
node.style.display = "";
return showItemAmine(node);
})(nodes[j]));
}
return Promise.all(promises);
} else {
// 串行
var p = Promise.resolve();
var group = [];
for (var k = 0; k < nodes.length; k++) {
(function(node) {
p = p.then(function() {
group.push((function(node) {
node.style.display = "";
return showItemAmine(node);
});
})(nodes[k]);
})
(nodes[k]));
if (group.length === 20 || k === nodes.length - 1) {
(function(g) {
p = p.then(function() {
return Promise.join(g);
});
})(group);
group = [];
}
}
(function(g) {
p = p.then(function() {
return Promise.join(g);
});
})(group);
return p;
}
}
case DataView.ChangeType.remove:
{
var node = self.container.children[evt.detail.index];
var info = evt.datas[0];
var node = self._findNodeByKey(info.key);
if (!node) return;
// 隐藏动画完成后再移除
return hideItemAmine(node).then(function() {
self.container.removeChild(node);
});
@@ -375,29 +496,30 @@
case DataView.ChangeType.change:
{
var oldNode = self.container.children[evt.detail.index];
var info = evt.datas[0];
var oldNode = self._findNodeByKey(info.key);
if (!oldNode) return;
// 先淡出旧节点
return hideItemAmine(oldNode).then(function() {
// 替换节点
var newNode = renderItem(evt.datas[0], evt.detail.index);
var newNode = renderItem(info.item);
self.container.replaceChild(newNode, oldNode);
// 再淡入新节点
return showItemAmine(newNode);
});
}
case DataView.ChangeType.clear:
self.container.innerHTML = "";
return Promise.resolve();
case DataView.ChangeType.move:
{
var node = self.container.children[evt.detail.from];
var info = evt.datas[0];
var node = self._findNodeByKey(info.key);
if (!node) return;
var ref = self.container.children[evt.detail.to] || null;
if (node) self.container.insertBefore(node, ref);
self.container.insertBefore(node, ref);
return Promise.resolve();
}
@@ -410,9 +532,22 @@
return Promise.resolve();
}
}
promises.push(self._refreshVisibility());
return Promise.join(promises);
});
});
};
PMDataListView.prototype._findNodeByKey = function(key) {
if (key == null) return null;
var children = this.container.children;
for (var i = 0; i < children.length; i++) {
if (children[i].__pm_key === key) {
return children[i];
}
}
return null;
};
PMDataListView.prototype._toggleSelect = function(ele) {
// 如果选择模式为 none则不处理
@@ -472,7 +607,202 @@
return Array.prototype.slice.call(this.container.querySelectorAll(".selected"));
}
});
PMDataListView.prototype._updateEmptyView = function() {
if (!this._emptyView) return;
// container 中是否还有 item
var hasItem = this.container.children.length > 0;
if (hasItem) {
if (this._emptyView.parentNode) {
this._emptyView.style.display = "none";
}
} else {
if (!this._emptyView.parentNode) {
this.container.appendChild(this._emptyView);
}
this._emptyView.style.display = "";
}
};
Object.defineProperty(PMDataListView.prototype, "emptyView", {
get: function() {
return this._emptyView;
},
set: function(value) {
// 只接受 HTMLElement 或 null / undefined
if (value !== null && value !== void 0 && !(value instanceof HTMLElement)) {
return;
}
// 移除旧的
if (this._emptyView && this._emptyView.parentNode) {
this._emptyView.parentNode.removeChild(this._emptyView);
}
this._emptyView = value || null;
// 设置后立刻刷新一次
this._updateEmptyView();
}
});
PMDataListView.prototype._isItemVisible = function(item) {
// 1⃣ filter
if (this._filter) {
if (!this._filter(item)) return false;
}
// 2⃣ search自动启用 / 禁用)
var handler = this._searchHandler;
var text = this._searchText;
if (typeof handler === "function") {
if (text != null) {
text = ("" + text).replace(/^\s+|\s+$/g, "");
}
if (text && text.length > 0) {
if (!handler(text, item)) {
return false;
}
}
}
return true;
};
PMDataListView.prototype._refreshVisibility = function() {
var self = this;
var children = self.container.children;
var animes = [];
for (var i = 0; i < children.length; i++) {
(function(node) {
var item = node.__pm_item;
if (!item) return;
var visible = self._isItemVisible(item);
var enableAnime = animes.length < MAX_ANIMATE_COUNT;
if (visible) {
if (node.style.display === "none") {
node.style.display = "";
animes.push(runShowAnime(node, enableAnime));
}
} else {
if (node.style.display !== "none") {
// 移除选择状态
node.classList.remove("selected");
animes.push(runHideAnime(node, enableAnime).then(function() {
node.style.display = "none";
}));
}
}
})(children[i]);
}
return Promise.join(animes);
};
Object.defineProperty(PMDataListView.prototype, "filter", {
get: function() {
return this._filter;
},
set: function(fn) {
this._filter = (typeof fn === "function") ? fn : null;
this._refreshVisibility();
}
});
Object.defineProperty(PMDataListView.prototype, "searchHandler", {
get: function() {
return this._searchHandler;
},
set: function(fn) {
this._searchHandler = (typeof fn === "function") ? fn : null;
this._refreshVisibility();
}
});
Object.defineProperty(PMDataListView.prototype, "searchText", {
get: function() {
return this._searchText;
},
set: function(text) {
var oldText = this._searchText;
this._searchText = text;
var oldActive = !!(oldText && oldText.trim());
var newActive = !!(text && ("" + text).trim());
//if (!oldActive && newActive) {
this._isSearching = true;
this._emitSearchEvent("searchstart");
//}
var handler = this._searchHandler;
var provider = this._searchSuggestProvider;
var cb = this.onSearchSuggest;
var t = text;
if (t != null) {
t = ("" + t).replace(/^\s+|\s+$/g, "");
}
// 搜索建议
if (
typeof handler === "function" &&
t &&
t.length > 0 &&
typeof provider === "function" &&
typeof cb === "function"
) {
var list = provider(t);
if (list && list.length) {
cb(t, list.slice(0, 10));
}
}
var self = this;
var func = function() {
//if (oldActive && !newActive) {
self._isSearching = false;
self._emitSearchEvent("searchend");
//}
};
this._refreshVisibility().done(func, func);
}
});
Object.defineProperty(PMDataListView.prototype, "searchSuggestProvider", {
get: function() {
return this._searchSuggestProvider;
},
set: function(fn) {
this._searchSuggestProvider = (typeof fn === "function") ? fn : null;
}
});
Object.defineProperty(PMDataListView.prototype, "findItemLength", {
get: function() {
var count = 0;
var children = this.container.children;
for (var i = 0; i < children.length; i++) {
var item = children[i].__pm_item;
if (this._isItemVisible(item)) {
count++;
}
}
return count;
}
});
PMDataListView.prototype._emitSearchEvent = function(type) {
if (typeof this["on" + type] === "function") {
try {
this["on" + type].call(this);
} catch (e) {}
}
try {
var ev = document.createEvent("Event");
ev.initEvent(type, true, true);
this.container.dispatchEvent(ev);
} catch (e) {}
};
PMDataListView.prototype.refresh = function() {
this._refreshVisibility();
};
global.DataView.ChangeEvent = PMChangeEvent;
global.DataView.DataSource = PMDataSource;
global.DataView.ListView = PMDataListView;

View File

@@ -1,6 +1,7 @@
(function(global) {
"use strict";
var pkg_ns = external.Package;
var strres = external.StringResources;
function archsToStr(archs) {
var arr = [];
@@ -28,9 +29,23 @@
}
return arr.join(", ");
}
var showAppDetailTimer = null;
function updateAppDataSource(page, result, bar) {
try {
var json = result.json;
console.log(json);
page.appDataSource.updateList(json.applications);
} catch (e) {}
showAppDetailTimer = setTimeout(function() {
showAppDetailTimer = null;
bar.hide();
}, 3000);
}
function setAppInfoPageContent(info) {
var page = document.getElementById("page-appinfo");
page.data = info;
page.querySelector(".display-name").textContent = info.Properties.DisplayName;
page.querySelector(".publisher-display-name").textContent = info.Properties.Publisher;
page.querySelector(".version").textContent = info.Identity.Version.Expression;
@@ -42,9 +57,72 @@
page.querySelector(".identity .full-name").textContent = info.Identity.FullName;
page.querySelector(".identity .architecture").textContent = archsToStr(info.Identity.ProcessArchitecture);
var il = info.InstallLocation;
var pkg = pkg_ns.fromInstallLocation(il);
var json = pkg.jsonText;
console.log(JSON.parse(json));
try { page.appDataSource.clear(); } catch (e) {}
var appLoading = page.querySelector("#appinfo-loading");
appLoading.classList.remove("noloading");
if (showAppDetailTimer) clearTimeout(showAppDetailTimer);
if (typeof appLoading.bar === "undefined") {
appLoading.bar = new TransitionPanel(appLoading, {
axis: 'y',
duration: 500,
});
}
appLoading.bar.show();
var appLoadingStatus = page.querySelector(".title");
appLoadingStatus.textContent = strres.get("MANAGER_APP_INSTALLEDAPPS_LOADING");
return Package.reader.readFromInstallLocation(il, true).then(
function(result) {
try {
var displayNameNode = page.querySelector(".display-name");
displayNameNode.textContent = displayNameNode.textContent || result.json.properties.display_name;
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
displayNameNode.textContent = "";
}
if (result.json.applications.length === 1) {
displayNameNode.textContent = displayNameNode.textContent || result.json.applications[0].DisplayName || result.json.applications[0].ShortName;
}
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
displayNameNode.textContent = "";
}
if (result.json.applications.length === 1) {
displayNameNode.textContent = displayNameNode.textContent || result.json.applications[0].ShortName;
}
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
displayNameNode.textContent = "";
}
displayNameNode.textContent = displayNameNode.textContent || info.Identity.FamilyName;
} catch (e) {}
appLoadingStatus.textContent = strres.get("MANAGER_APP_INSTALLEDAPPS_SUCCEED");
appLoading.classList.add("noloading");
updateAppDataSource(page, result, appLoading.bar);
},
function(result) {
try {
var displayNameNode = page.querySelector(".display-name");
displayNameNode.textContent = displayNameNode.textContent || result.json.properties.display_name;
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
displayNameNode.textContent = "";
}
if (result.json.applications.length === 1) {
displayNameNode.textContent = displayNameNode.textContent || result.json.applications[0].DisplayName || result.json.applications[0].ShortName;
}
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
displayNameNode.textContent = "";
}
if (result.json.applications.length === 1) {
displayNameNode.textContent = displayNameNode.textContent || result.json.applications[0].ShortName;
}
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
displayNameNode.textContent = "";
}
displayNameNode.textContent = displayNameNode.textContent || info.Identity.FamilyName;
} catch (e) {}
var msg = result.message;
appLoadingStatus.textContent = external.String.format(strres.get("MANAGER_APP_INSTALLEDAPPS_FAILED"), msg);
appLoading.classList.add("noloading");
updateAppDataSource(page, result, appLoading.bar);
}
);
}
global.setAppInfoPageContent = setAppInfoPageContent;
})(this);

View File

@@ -1,369 +1,5 @@
(function(global) {
function _createImage(src, onload, onerror) {
var img = new Image();
img.onload = function() {
onload(img);
};
img.onerror = function() {
onerror && onerror();
};
img.src = src;
}
function getSolidOpaqueBackgroundColor(source, callback) {
function processImage(img) {
if (!img || !img.complete) {
callback(null);
return;
}
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = img.naturalWidth || img.width;
canvas.height = img.naturalHeight || img.height;
ctx.drawImage(img, 0, 0);
try {
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
} catch (e) {
// 跨域导致的安全异常
callback(null);
return;
}
var data = imageData.data;
var w = canvas.width;
var h = canvas.height;
var colors = {};
var total = 0;
function pushColor(r, g, b, a) {
if (a !== 255) return;
var key = r + "," + g + "," + b;
colors[key] = (colors[key] || 0) + 1;
total++;
}
// top + bottom
for (var x = 0; x < w; x++) {
var topIndex = (0 * w + x) * 4;
var botIndex = ((h - 1) * w + x) * 4;
pushColor(data[topIndex], data[topIndex + 1], data[topIndex + 2], data[topIndex + 3]);
pushColor(data[botIndex], data[botIndex + 1], data[botIndex + 2], data[botIndex + 3]);
}
// left + right
for (var y = 1; y < h - 1; y++) {
var leftIndex = (y * w + 0) * 4;
var rightIndex = (y * w + (w - 1)) * 4;
pushColor(data[leftIndex], data[leftIndex + 1], data[leftIndex + 2], data[leftIndex + 3]);
pushColor(data[rightIndex], data[rightIndex + 1], data[rightIndex + 2], data[rightIndex + 3]);
}
if (total === 0) {
callback(null);
return;
}
var bestKey = null;
var bestCount = 0;
for (var key in colors) {
if (colors.hasOwnProperty(key)) {
if (colors[key] > bestCount) {
bestCount = colors[key];
bestKey = key;
}
}
}
// 95% 纯色阈值
if (bestCount / total < 0.95) {
callback(null);
return;
}
callback(bestKey);
}
// 如果传入的是 img 元素
if (source && source.tagName && source.tagName.toLowerCase() === "img") {
processImage(source);
return;
}
// 如果传入的是 data url 或普通 url
if (typeof source === "string") {
_createImage(source, processImage, function() {
callback(null);
});
return;
}
callback(null);
}
function getHamonyColor(source, callback) {
function _createImage(src, onload, onerror) {
var img = new Image();
img.onload = function() { onload(img); };
img.onerror = function() { onerror && onerror(); };
img.src = src;
}
function _toKey(r, g, b) {
return r + "," + g + "," + b;
}
function _rgbToHsl(r, g, b) {
r /= 255;
g /= 255;
b /= 255;
var max = Math.max(r, g, b);
var min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0;
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return { h: h, s: s, l: l };
}
function _hslToRgb(h, s, l) {
var r, g, b;
function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
if (s === 0) {
r = g = b = l;
} else {
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255)
};
}
function _lum(r, g, b) {
function f(x) {
x = x / 255;
return x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
}
return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
}
function _contrast(a, b) {
var L1 = _lum(a.r, a.g, a.b);
var L2 = _lum(b.r, b.g, b.b);
var lighter = Math.max(L1, L2);
var darker = Math.min(L1, L2);
return (lighter + 0.05) / (darker + 0.05);
}
function _tryPureBackground(data, w, h) {
var edgeColors = {};
var edgeTotal = 0;
function push(r, g, b, a) {
if (a !== 255) return;
var k = _toKey(r, g, b);
edgeColors[k] = (edgeColors[k] || 0) + 1;
edgeTotal++;
}
for (var x = 0; x < w; x++) {
var top = (0 * w + x) * 4;
var bot = ((h - 1) * w + x) * 4;
push(data[top], data[top + 1], data[top + 2], data[top + 3]);
push(data[bot], data[bot + 1], data[bot + 2], data[bot + 3]);
}
for (var y = 1; y < h - 1; y++) {
var left = (y * w + 0) * 4;
var right = (y * w + (w - 1)) * 4;
push(data[left], data[left + 1], data[left + 2], data[left + 3]);
push(data[right], data[right + 1], data[right + 2], data[right + 3]);
}
if (edgeTotal === 0) return null;
var best = null,
bestCount = 0;
for (var k in edgeColors) {
if (edgeColors.hasOwnProperty(k) && edgeColors[k] > bestCount) {
bestCount = edgeColors[k];
best = k;
}
}
if (best && bestCount / edgeTotal >= 0.95) return best;
return null;
}
function _process(img) {
if (!img || !img.complete) { callback(null); return; }
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = img.naturalWidth || img.width;
canvas.height = img.naturalHeight || img.height;
ctx.drawImage(img, 0, 0);
var imageData;
try {
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
} catch (e) {
callback(null);
return;
}
var data = imageData.data;
var w = canvas.width,
h = canvas.height;
// 1) 尝试纯色背景
var pure = _tryPureBackground(data, w, h);
if (pure) { callback(pure); return; }
// 2) 统计不透明像素(抽样)
var sumR = 0,
sumG = 0,
sumB = 0,
count = 0;
var samples = 0;
var step = 4; // 4x抽样减少性能消耗
for (var y = 0; y < h; y += step) {
for (var x = 0; x < w; x += step) {
var i = (y * w + x) * 4;
var a = data[i + 3];
if (a === 255) {
sumR += data[i];
sumG += data[i + 1];
sumB += data[i + 2];
count++;
}
samples++;
}
}
if (count === 0) { callback(null); return; }
var avgR = sumR / count,
avgG = sumG / count,
avgB = sumB / count;
// 3) 生成候选色(借鉴流行配色)
var base = _rgbToHsl(avgR, avgG, avgB);
function clamp(v, min, max) { return Math.max(min, Math.min(max, v)); }
var candidates = [];
// 中性色(低饱和)
candidates.push(_hslToRgb(base.h, 0.05, 0.5));
candidates.push(_hslToRgb(base.h, 0.1, 0.6));
candidates.push(_hslToRgb(base.h, 0.1, 0.4));
// 平均色去饱和
candidates.push(_hslToRgb(base.h, clamp(base.s * 0.4, 0.05, 0.2), clamp(base.l, 0.2, 0.8)));
// 互补色(活泼)
candidates.push(_hslToRgb((base.h + 0.5) % 1, clamp(base.s * 0.6, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
// 类似色
candidates.push(_hslToRgb((base.h + 0.083) % 1, clamp(base.s * 0.5, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
candidates.push(_hslToRgb((base.h - 0.083 + 1) % 1, clamp(base.s * 0.5, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
// 三分色
candidates.push(_hslToRgb((base.h + 0.333) % 1, clamp(base.s * 0.6, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
candidates.push(_hslToRgb((base.h - 0.333 + 1) % 1, clamp(base.s * 0.6, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
// 4) 计算最小对比度(与所有不透明像素)
function minContrastWithImage(bg) {
var bgObj = { r: bg.r, g: bg.g, b: bg.b };
var minC = Infinity;
for (var y = 0; y < h; y += step) {
for (var x = 0; x < w; x += step) {
var i = (y * w + x) * 4;
if (data[i + 3] !== 255) continue;
var px = { r: data[i], g: data[i + 1], b: data[i + 2] };
var c = _contrast(bgObj, px);
if (c < minC) minC = c;
}
}
return minC;
}
var best = null;
for (var i = 0; i < candidates.length; i++) {
var c = candidates[i];
var minC = minContrastWithImage(c);
if (minC >= 4.5) {
best = c;
break;
}
}
if (best) {
callback(_toKey(best.r, best.g, best.b));
} else {
callback(null);
}
}
if (source && source.tagName && source.tagName.toLowerCase() === "img") {
_process(source);
} else if (typeof source === "string") {
_createImage(source, _process, function() { callback(null); });
} else {
callback(null);
}
}
function getSuitableBackgroundColor(source, callback) {
getSolidOpaqueBackgroundColor(source, function(color) {
if (color) {
callback(color);
} else {
getHamonyColor(source, callback);
}
});
}
var strres = external.StringResources;
function createLocalizedCompare(locale) {
return function(a, b) {
@@ -383,9 +19,17 @@
var mgr = Package.manager;
var nstr = Bridge.NString;
var datasrc = new DataView.DataSource();
datasrc.setKeySelector(function(item) {
if (item === null || item === void 0) return null;
return Bridge.String.tolower(Bridge.String.trim(item.Identity.FullName));
});
var themeColor = Bridge.UI.themeColor;
var loadingDisplay = document.getElementById("applist-loading");
var loadingStatus = loadingDisplay.querySelector(".title");
var emptyDisplay = document.createElement("div");
var dataLengthDisplay = document.getElementById("applist-datalen");
var appSearchList = document.getElementById("applist-search");
emptyDisplay.textContent = strres.get("MANAGER_MANAGE_LISTEMPTY");
var listView = new DataView.ListView(listContainer, function(item) {
var appItem = appItemTemplate.cloneNode(true);
appItem.id = "";
@@ -407,17 +51,102 @@
appItem.setAttribute("data-version", item.Identity.Version.Expression);
appItem.setAttribute("data-users", item.Users);
appItem.setAttribute("data-publisher-id", item.Identity.PublisherId);
setTimeout(function(a, b) {
getSolidOpaqueBackgroundColor(a, function(color) {
try {
var pipes = color.split(",");
var colorobj = new Color(parseInt(pipes[0]), parseInt(pipes[1]), parseInt(pipes[2]));
if (colorobj.hex == "#ffffff" || colorobj.hex == "#000000") throw "too white or black";
var rgbstr = colorobj.RGB.toString();
b.style.backgroundColor = rgbstr;
} catch (e) {}
});
}, 0, item.Properties.LogoBase64, logoimg.parentElement);
logoimg.parentElement.style.backgroundColor = item.BackgroundColor;
if (item.BackgroundColor === "transparent") {
logoimg.parentElement.style.backgroundColor = themeColor;
}
var uninstallButton = appItem.querySelector("div[role=control] .uninstall");
Windows.UI.Event.Util.addEvent(uninstallButton, "click", function(e) {
e.stopPropagation();
this.disabled = true;
var itemNode = this.parentNode.parentNode.parentNode;
var flyout = document.getElementById("app-uninstall-flyout");
if (typeof flyout.appDataSource !== "undefined") flyout.appDataSource.clear();
if (typeof flyout.appDataSource !== "undefined") {
Package.reader.readFromInstallLocation(this.parentNode.parentNode.parentNode.data.InstallLocation, true).then(function(result) {
try {
if (typeof result.json.applications === "undefined" || result.json.applications.length === 0) {
result.json.applications = [{
DisplayName: item.Properties.DisplayName || item.Identity.Name,
SmallLogo_Base64: item.Properties.LogoBase64,
}];
}
flyout.appDataSource.updateList(result.json.applications);
} catch (e) {}
}, function(result) {
try { flyout.appDataSource.updateList(result.json.applications); } catch (e) {}
});
}
var self = this;
var confirm = flyout.querySelector(".confirm");
confirm.onclick = null;
confirm.onclick = function() {
self.disabled = true;
flyout.winControl.hide();
var fullName = itemNode.getAttribute("data-full-name");
itemNode.classList.add("uninstalling");
var progressPart = itemNode.querySelector("div[role=progress]");
var statusDisplay = progressPart.querySelector(".status");
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_ING");
var progressDisplay = progressPart.querySelector(".progress");
progressDisplay.removeAttribute("value");
self.disabled = true;
(function(itemNode, statusDisplay, progressDisplay, self) {
mgr.remove(fullName).then(function(_s) {
itemNode.classList.remove("uninstalling");
itemNode.classList.add("uninstalled");
if (_s.succeeded) {
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_SUCCEED");
datasrc.remove(itemNode.data);
} else {
statusDisplay.textContent = _s.message;
setTimeout(function(iNode, uButton) {
iNode.classList.remove("uninstalled");
uButton.disabled = false;
}, 5000, itemNode, self);
}
}, function(_f) {
itemNode.classList.remove("uninstalling");
itemNode.classList.add("uninstalled");
try {
if (_f.succeeded) {
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_SUCCEED");
datasrc.remove(itemNode.data);
} else {
statusDisplay.textContent = _f.message;
setTimeout(function(iNode, uButton) {
iNode.classList.remove("uninstalled");
uButton.disabled = false;
}, 5000, itemNode, self);
}
} catch (e) {
statusDisplay.textContent = e.message;
setTimeout(function(iNode, uButton) {
iNode.classList.remove("uninstalled");
uButton.disabled = false;
}, 5000, itemNode, self);
}
self.disabled = false;
}, function(_p) {
statusDisplay.textContent = Bridge.String.format(
strres.get("MANAGER_APP_UNINSTALL_PROGRESSING"),
_p
);
progressDisplay.value = _p;
});
})(itemNode, statusDisplay, progressDisplay, self);
};
var winFlyout = flyout.winControl;
if (winFlyout._beforehideHandler) {
winFlyout.removeEventListener("beforehide", winFlyout._beforehideHandler);
}
winFlyout._beforehideHandler = function() {
self.disabled = false;
};
winFlyout.addEventListener("beforehide", winFlyout._beforehideHandler);
flyout.winControl.show(this);
});
Windows.UI.Event.Util.addEvent(appItem.querySelector("div[role=advance] a"), "click", function(e) {
e.stopPropagation();
try {
@@ -428,93 +157,385 @@
});
listView.selectionMode = "single";
listView.bind(datasrc);
listView.emptyView = emptyDisplay;
listView.searchHandler = function(text, item) {
return ((item.Properties.DisplayName || item.Identity.Name || "") + (item.Properties.Publisher || "")).indexOf(text) >= 0;
};
appSearchList.control = new Search.Box(appSearchList, {
placeholderText: strres.get("MANAGER_MANAGE_SEARCHPLACEHOLDER"),
chooseSuggestionOnEnter: false
});
appSearchList.control.ontextchanged = function(ev) {
console.log(ev.text);
listView.searchText = ev.detail.text;
};
listView.onsearchend = function() {
dataLengthDisplay.textContent = external.String.format(strres.get("MANAGER_MANAGE_FINDAPPS"), listView.findItemLength);
};
var timer = null;
function refreshAppList() {
dataLengthDisplay.textContent = "";
function processData(manifest, dataitem) {
//if (dataitem.Identity.FamilyName = "Microsoft.MicrosoftEdge.Stable_8wekyb3d8bbwe") debugger;
dataitem.Properties.DisplayName = dataitem.Properties.DisplayName || manifest.properties.display_name || dataitem.Properties.DisplayName;
if ((dataitem.Properties.DisplayName || "").indexOf("ms-resource:") === 0) {
dataitem.Properties.DisplayName = "";
}
if (manifest.applications.length === 1) {
dataitem.Properties.DisplayName = dataitem.Properties.DisplayName || manifest.applications[0].DisplayName || "";
}
if ((dataitem.Properties.DisplayName || "").indexOf("ms-resource:") === 0) {
dataitem.Properties.DisplayName = "";
}
if (manifest.applications.length === 1) {
dataitem.Properties.DisplayName = dataitem.Properties.DisplayName || manifest.applications[0].ShortName || "";
}
if ((dataitem.Properties.DisplayName || "").indexOf("ms-resource:") === 0) {
dataitem.Properties.DisplayName = "";
}
dataitem.Properties.DisplayName = dataitem.Properties.DisplayName || dataitem.Identity.FamilyName;
dataitem.Properties.Puvlisher = dataitem.Properties.Publisher || manifest.properties.publisher_display_name || dataitem.Properties.Publisher;
dataitem.Properties.Framework = dataitem.Properties.Framework || manifest.properties.framework;
dataitem.Properties.Logo = dataitem.Properties.Logo || manifest.properties.logo;
dataitem.Properties.LogoBase64 = dataitem.Properties.LogoBase64 || manifest.properties.logo_base64;
if (manifest.applications.length === 1) {
dataitem.Properties.LogoBase64 = dataitem.Properties.LogoBase64 || manifest.applications[0].Square44x44Logo_Base64 || manifest.applications[0].SmallLogo_Base64;
}
dataitem.Properties.ResourcePackage = dataitem.Properties.ResourcePackage || manifest.properties.resource_package;
dataitem.Properties.Description = dataitem.Properties.Description || manifest.properties.description;
try {
dataitem.BackgroundColor = manifest.applications[0].BackgroundColor || "transparent";
} catch (e) {
dataitem.BackgroundColor = "transparent";
}
return dataitem;
}
function update(datas) {
var newDatas = [];
var promises = [];
for (var i = 0; i < datas.length; i++) {
var data = datas[i];
if (data.Properties.Framework) continue; // 过滤依赖项
var isfind = false; // 过滤系统应用
for (var j = 0; data && data.Users && j < data.Users.length; j++) {
if (Bridge.NString.equals(data.Users[j], "NT AUTHORITY\\SYSTEM")) {
isfind = true;
break;
if (external.System.isWindows10) {
if (data.Properties.DisplayName === null || data.Properties.DisplayName === "" || data.Properties.DisplayName === void 0 ||
data.Properties.LogoBase64 === null || data.Properties.LogoBase64 === "" || data.Properties.LogoBase64 === void 0
) {
promises.push(function(item, arr) {
return Package.reader.readFromInstallLocation(item.InstallLocation, true).then(function(result) {
try {
arr.push(processData(result.json, item));
} catch (e) {
item.BackgroundColor = "transparent";
arr.push(item);
}
}, function(result) {
try {
arr.push(processData(result.json, item));
} catch (e) {
item.BackgroundColor = "transparent";
arr.push(item);
}
});
}(data, newDatas));
} else {
promises.push(function(item, arr) {
return Package.reader.readFromInstallLocation(item.InstallLocation, false).then(function(result) {
try {
item.BackgroundColor = result.json.applications[0].BackgroundColor;
arr.push(item);
} catch (e) {
item.BackgroundColor = "transparent";
arr.push(item);
}
}, function(result) {
try {
item.BackgroundColor = result.json.applications[0].BackgroundColor;
arr.push(item);
} catch (e) {
item.BackgroundColor = "transparent";
arr.push(item);
}
});
}(data, newDatas));
}
} else {
promises.push(function(item, arr) {
return Package.reader.readFromInstallLocation(item.InstallLocation, true).then(function(result) {
try {
arr.push(processData(result.json, item));
} catch (e) {
item.BackgroundColor = "transparent";
arr.push(item);
}
}, function(result) {
try {
arr.push(processData(result.json, item));
} catch (e) {
item.BackgroundColor = "transparent";
arr.push(item);
}
});
}(data, newDatas));
}
}
function updateDatas() {
datasrc.updateList(newDatas, function(item) {
return item.Identity.FullName || "";
});
var compare = function(a, b) { return a - b; };
try {
compare = createLocalizedCompare(external.System.Locale.currentLocale);
} catch (e) {
try {
compare = createLocalizedCompare(navigator.language);
} catch (e) {
compare = function(a, b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
};
}
}
if (isfind) continue;
newDatas.push(data);
datasrc.sort(function(a, b) {
return compare(a.Properties.DisplayName, b.Properties.DisplayName);
});
dataLengthDisplay.textContent = external.String.format(strres.get("MANAGER_MANAGE_FINDAPPS"), listView.findItemLength);
}
datasrc.updateList(newDatas, function(item) {
return item.Identity.FullName || "";
});
var compare = function(a, b) { return a - b; };
try {
compare = createLocalizedCompare(external.System.Locale.currentLocale);
} catch (e) {
try {
compare = createLocalizedCompare(navigator.language);
} catch (e) {
compare = function(a, b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
};
}
}
datasrc.sort(function(a, b) {
return compare(a.Properties.DisplayName, b.Properties.DisplayName);
});
return Promise.join(promises).then(updateDatas, updateDatas);
}
if (timer) clearTimeout(timer);
timer = null;
loadingDisplay.style.display = "";
loadingDisplay.classList.remove("noloading");
loadingDisplay.bar.show();
function waitAndHide() {
if (timer) clearTimeout(timer);
timer = null;
timer = setTimeout(function() {
loadingDisplay.style.display = "none";
}, 10000);
return new Promise(function(resolve, reject) {
if (timer) clearTimeout(timer);
timer = null;
timer = setTimeout(function(rs, rj) {
//loadingDisplay.style.display = "none";
loadingDisplay.bar.hide();
rs();
}, 5000, resolve, reject);
});
}
loadingStatus.textContent = "正在加载数据...";
loadingStatus.textContent = strres.get("MANAGER_APP_INSTALLEDAPPS_LOADING");
return mgr.get().then(function(result) {
loadingDisplay.classList.add("noloading");
loadingStatus.textContent = "已经加载了所有数据";
update(result.list);
waitAndHide();
return update(result.list).then(function() {
loadingDisplay.classList.add("noloading");
loadingStatus.textContent = strres.get("MANAGER_APP_INSTALLEDAPPS_SUCCEED");
setTimeout(function(lv) {
lv.refresh();
}, 500, listView);
}).then(waitAndHide);
}, function(error) {
loadingDisplay.classList.add("noloading");
loadingStatus.textContent = "更新时出错: " + (error.result ? (error.result.message || error.result.ErrorCode || "获取失败") : (error.message || error.error || error));
var errmsg = (error.result ? (error.result.message || error.result.ErrorCode || "获取失败") : (error.message || error.error || error));
loadingStatus.textContent = external.String.format(strres.get("MANAGER_APP_INSTALLEDAPPS_FAILED"), errmsg);
try { update(error.list); } catch (e) {}
waitAndHide();
})
setTimeout(function(lv) {
lv.refresh();
}, 500, listView);
return waitAndHide();
});
}
var appbar = document.getElementById("appBar");
var appbarControl = new AppBar.AppBar(appbar);
var refreshButton = new AppBar.Command();
refreshButton.icon = "&#57623;";
refreshButton.label = "刷新";
refreshButton.label = strres.get("MANAGER_APP_REFRESH");
global.refreshAppList2 = function refreshAppList2() {
appbarControl.hide();
refreshButton.disabled = true;
refreshAppList().done(function() {
return refreshAppList().then(function() {
refreshButton.disabled = false;
}, function(error) {
refreshButton.disabled = false;
});
}
var showSystemApps = document.getElementById("applist-showsystemapp");
var showFrameworks = document.getElementById("applist-showframework");
listView.filter = function(item) {
try {
if (!showFrameworks.checked && item.Properties.Framework) return false;
if (!showSystemApps.checked && item.Users.indexOf("NT AUTHORITY\\SYSTEM") !== -1) return false;
return true;
} catch (e) {
return false;
}
};
Windows.UI.Event.Util.addEvent(showSystemApps, "change", function() {
listView.refresh();
dataLengthDisplay.textContent = external.String.format(strres.get("MANAGER_MANAGE_FINDAPPS"), listView.findItemLength);
});
Windows.UI.Event.Util.addEvent(showFrameworks, "change", function() {
listView.refresh();
dataLengthDisplay.textContent = external.String.format(strres.get("MANAGER_MANAGE_FINDAPPS"), listView.findItemLength);
});
refreshButton.addEventListener("click", refreshAppList2);
appbarControl.add(refreshButton);
refreshAppList2();
var appDetailPage = document.getElementById("page-appinfo");
pagemgr.register("manager", document.getElementById("tag-manager"), document.getElementById("page-manager"));
pagemgr.register("appinfo", document.getElementById("tag-appinfo"), document.getElementById("page-appinfo"), setAppInfoPageContent);
var appinfoBackPage = document.getElementById("page-appinfo").querySelector(".win-backbutton");
var appinfoBackPage = appDetailPage.querySelector(".win-backbutton");
Windows.UI.Event.Util.addEvent(appinfoBackPage, "click", function(e) {
pagemgr.back();
});
appDetailPage.appDataSource = new DataView.DataSource();
var appListView = new DataView.ListView(appDetailPage.querySelector(".apps"), function(item) {
var appItem = appItemTemplate.cloneNode(true);
appItem.id = "";
appItem.style.display = "";
var logoimg = appItem.querySelector("img");
logoimg.src = item.Square44x44Logo_Base64 || item.SmallLogo_Base64;
if (logoimg.src == "" || logoimg.src == null || logoimg.src == void 0) logoimg.removeAttribute("src");
logoimg.parentElement.style.backgroundColor = item.BackgroundColor;
if (Bridge.NString.equals(item.BackgroundColor, "transparent")) logoimg.parentElement.style.backgroundColor = themeColor;
var appName = appItem.querySelector(".displayName");
appName.textContent = item.DisplayName || item.ShortName;
var appPub = appItem.querySelector(".publisher");
appPub.style.display = "none";
appItem.querySelector("div[role=advance]").style.display = "none";
var ctrls = appItem.querySelector("div[role=control]");
ctrls.innerHTML = "";
appItem.data = item;
var launchButton = document.createElement("button");
launchButton.textContent = strres.get("MANAGER_APP_LAUNCH");
launchButton.setAttribute("data-app-user-model-id", item.AppUserModelID);
var createShortcutButton = document.createElement("button");
createShortcutButton.textContent = strres.get("MANAGER_APP_CREATESHORTCUT");
createShortcutButton.style.marginRight = "10px";
Windows.UI.Event.Util.addEvent(launchButton, "click", function(e) {
e.stopPropagation();
Package.manager.active(this.getAttribute("data-app-user-model-id"));
});
ctrls.appendChild(launchButton);
ctrls.appendChild(createShortcutButton);
return appItem;
});
appListView.selectionMode = "single";
appListView.bind(appDetailPage.appDataSource);
appListView.emptyView = emptyDisplay.cloneNode(true);
var appDetailUninstall = appDetailPage.querySelector("#detail-uninstall-btn");
var appDetailUninstallStatusBlock = appDetailPage.querySelector("#appinfo-uninstallstatus");
var appDetailUninstallProgress = appDetailUninstallStatusBlock.querySelector(".progress");
var appDetailUninstallProgressStatus = appDetailUninstallStatusBlock.querySelector(".status");
appDetailUninstallStatusBlock.bar = new TransitionPanel(appDetailUninstallStatusBlock, {
axis: 'y',
duration: 500,
});
Windows.UI.Event.Util.addEvent(appDetailUninstall, "click", function(e) {
e.stopPropagation();
appinfoBackPage.disabled = true;
appDetailUninstallProgress.removeAttribute("value");
var item = appDetailPage.data;
var flyout = document.getElementById("app-uninstall-flyout");
if (typeof flyout.appDataSource !== "undefined") flyout.appDataSource.clear();
if (typeof flyout.appDataSource !== "undefined") {
flyout.appDataSource.updateList(appDetailPage.appDataSource.get());
}
var self = this;
var confirm = flyout.querySelector(".confirm");
confirm.onclick = null;
confirm.onclick = function() {
self.disabled = true;
flyout.winControl.hide();
var fullName = item.Identity.FullName;
var progressPart = appDetailUninstallStatusBlock;
var statusDisplay = appDetailUninstallProgressStatus;
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_ING");
var progressDisplay = appDetailUninstallProgress;
progressDisplay.style.display = "";
self.disabled = true;
progressPart.bar.show();
(function(statusDisplay, progressDisplay, self, item) {
mgr.remove(fullName).then(function(_s) {
if (_s.succeeded) {
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_SUCCEED");
datasrc.remove(item);
appinfoBackPage.disabled = false;
} else {
statusDisplay.textContent = _s.message;
}
setTimeout(function(uButton, isSuccess) {
appinfoBackPage.disabled = false;
uButton.disabled = isSuccess;
progressPart.bar.hide();
}, 5000, self, _s.succeeded);
progressDisplay.style.display = "none";
}, function(_f) {
try {
if (_f.succeeded) {
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_SUCCEED");
datasrc.remove(item);
appinfoBackPage.disabled = false;
} else {
statusDisplay.textContent = _f.message;
}
setTimeout(function(uButton, isSuccess) {
appinfoBackPage.disabled = false;
uButton.disabled = isSuccess;
progressPart.bar.hide();
}, 5000, self, _f.succeeded);
} catch (e) {
statusDisplay.textContent = e.message;
appinfoBackPage.disabled = false;
setTimeout(function(uButton, isSuccess) {
appinfoBackPage.disabled = false;
uButton.disabled = isSuccess;
progressPart.bar.hide();
}, 5000, self, _f.succeeded);
}
self.disabled = false;
progressDisplay.style.display = "none";
}, function(_p) {
statusDisplay.textContent = Bridge.String.format(
strres.get("MANAGER_APP_UNINSTALL_PROGRESSING"),
_p
);
progressDisplay.value = _p;
});
})(statusDisplay, progressDisplay, self, item);
};
var winFlyout = flyout.winControl;
if (winFlyout._beforehideHandler) {
winFlyout.removeEventListener("beforehide", winFlyout._beforehideHandler);
}
winFlyout._beforehideHandler = function() {
self.disabled = false;
};
winFlyout.addEventListener("beforehide", winFlyout._beforehideHandler);
flyout.winControl.show(this);
});
var uninstallFlyout = document.getElementById("app-uninstall-flyout");
uninstallFlyout.appListView = new DataView.ListView(uninstallFlyout.querySelector(".applist"), function(item) {
var appItem = appItemTemplate.cloneNode(true);
appItem.id = "";
appItem.style.display = "";
var logoimg = appItem.querySelector("img");
logoimg.src = item.Square44x44Logo_Base64 || item.SmallLogo_Base64;
if (logoimg.src == "" || logoimg.src == null || logoimg.src == void 0) logoimg.removeAttribute("src");
logoimg.parentElement.style.backgroundColor = item.BackgroundColor;
if (Bridge.NString.equals(item.BackgroundColor, "transparent")) logoimg.parentElement.style.backgroundColor = themeColor;
var appName = appItem.querySelector(".displayName");
appName.style.wordBreak = "normal";
appName.style.wordWrap = "normal";
appName.textContent = item.DisplayName || item.ShortName;
var appPub = appItem.querySelector(".publisher");
appPub.style.display = "none";
appItem.querySelector("div[role=advance]").style.display = "none";
var ctrls = appItem.querySelector("div[role=control]");
ctrls.innerHTML = "";
appItem.data = item;
return appItem;
});
uninstallFlyout.appDataSource = new DataView.DataSource();
uninstallFlyout.appListView.bind(uninstallFlyout.appDataSource);
pagemgr.addEventListener("load", function(e) {
appbarControl.enabled = e == "manager";
refreshButton.style.display = e == "manager" ? "" : "none";

View File

@@ -16,7 +16,44 @@
if (callback) callback(ret);
}
global.Package = {
reader: function(pkgPath) { return external.Package.reader(pkgPath); },
reader: {
package: function(pkgPath) { return external.Package.Reader.package(pkgPath); },
manifest: function(swManifestPath) { return external.Package.Reader.manifest(swManifestPath); },
manifestFromInstallLocation: function(swInstallLocation) { return external.Package.Reader.fromInstallLocation(swInstallLocation); },
readFromPackage: function(swPkgPath, bUsePri) {
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
return new Promise(function(resolve, reject) {
external.Package.Reader.readFromPackageAsync(swPkgPath, bUsePri, function(result) {
parseJsonCallback(result, resolve);
}, function(error) {
parseJsonCallback(error, reject);
});
});
},
readFromManifest: function(swManifestPath, bUsePri) {
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
return new Promise(function(resolve, reject) {
external.Package.Reader.readFromManifestAsync(swManifestPath, bUsePri, function(result) {
parseJsonCallback(result, resolve);
}, function(error) {
parseJsonCallback(error, reject);
});
});
},
readFromInstallLocation: function(swInstallLocation, bUsePri) {
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
return new Promise(function(resolve, reject) {
external.Package.Reader.readFromInstallLocationAsync(swInstallLocation, bUsePri, function(result) {
parseJsonCallback(result, resolve);
}, function(error) {
parseJsonCallback(error, reject);
});
});
},
cancelAll: function() { external.Package.Reader.cancelAll(); },
addApplicationReadItem: function(swItemName) { return external.Package.Reader.addApplicationItem(swItemName); },
removeApplicationReadItem: function(swItemName) { return external.Package.Reader.removeApplicationItem(swItemName); }
},
manager: {
add: function(swPkgPath, uOptions) {
return new Promise(function(resolve, reject, progress) {
@@ -129,38 +166,8 @@
});
});
},
},
manifest: function(swManifestPath) { return external.Package.manifest(swManifestPath); },
manifestFromInstallLocation: function(swInstallLocation) { return external.Package.fromInstallLocation(swInstallLocation); },
readFromPackage: function(swPkgPath, bUsePri) {
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
return new Promise(function(resolve, reject) {
external.Package.readFromPackageAsync(swPkgPath, bUsePri, function(result) {
parseJsonCallback(result, resolve);
}, function(error) {
parseJsonCallback(error, reject);
});
});
},
readFromManifest: function(swPkgPath, bUsePri) {
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
return new Promise(function(resolve, reject) {
external.Package.readFromManifestAsync(swPkgPath, bUsePri, function(result) {
parseJsonCallback(result, resolve);
}, function(error) {
parseJsonCallback(error, reject);
});
});
},
readFromInstallLocation: function(swPkgPath, bUsePri) {
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
return new Promise(function(resolve, reject) {
external.Package.readFromInstallLocationAsync(swPkgPath, bUsePri, function(result) {
parseJsonCallback(result, resolve);
}, function(error) {
parseJsonCallback(error, reject);
});
});
cancelAll: function() { mgr.cancelAll(); },
active: function(swAppUserModelID, swArgs) { return mgr.activeApp(swAppUserModelID, swArgs || null); }
},
};
})(this);

View File

@@ -13,7 +13,11 @@
var byName = el.getAttribute('data-res-byname');
var byId = el.getAttribute('data-res-byid');
var fromFile = el.getAttribute('data-res-fromfile');
if ((byName && !Bridge.NString.empty(byName)) || (byId && parseInt(byId, 10) > 0) || (fromFile && !Bridge.NString.empty(fromFile))) {
var byXml = el.getAttribute('data-res-resxml');
if ((byName && !Bridge.NString.empty(byName)) ||
(byId && parseInt(byId, 10) > 0) ||
(fromFile && !Bridge.NString.empty(fromFile)) ||
(byXml && !Bridge.NString.empty(byXml))) {
result.push(el);
}
}
@@ -47,6 +51,16 @@
} catch (e) {
nodes[i].textContent = "";
}
} else if (nodes[i].hasAttribute('data-res-resxml')) {
try {
var obj = nodes[i].getAttribute('data-res-resxml');
var strres = external.StringResources;
if (strres && strres.isValid) {
nodes[i].textContent = strres.get(obj);
}
} catch (e) {
nodes[i].textContent = "";
}
} else {
nodes[i].textContent = "";
}

720
shared/html/js/search.js Normal file
View File

@@ -0,0 +1,720 @@
/*!
* Search.Box - standalone SearchBox control (ES5, IE10 compatible)
* Exposes constructor as global.Search.Box
*
* Features:
* - API compatible-ish with WinJS.UI.SearchBox: properties (placeholderText, queryText, chooseSuggestionOnEnter, disabled)
* - Events: querychanged, querysubmitted, resultsuggestionchosen, suggestionsrequested
* - supports both `element.addEventListener("querychanged", handler)` and `instance.onquerychanged = handler`
* - Methods: setSuggestions(array), clearSuggestions(), dispose(), setLocalContentSuggestionSettings(settings) (noop)
* - Suggestions kinds: Query (0), Result (1), Separator (2) OR string names 'query'/'result'/'separator'
* - Hit highlighting: uses item.hits if provided, otherwise simple substring match of current input
* - No WinRT / WinJS dependency
*
* Usage:
* var box = new Search.Box(hostElement, options);
* box.setSuggestions([{ kind: 0, text: "hello" }, ...]);
*/
(function(global) {
"use strict";
// Ensure namespace
if (!global.Search) {
global.Search = {};
}
// Suggestion kinds
var SuggestionKind = {
Query: 0,
Result: 1,
Separator: 2
};
// Utility: create id
function uniqueId(prefix) {
return prefix + Math.random().toString(36).slice(2);
}
// Simple CustomEvent fallback for IE10
function createCustomEvent(type, detail) {
var ev;
try {
ev = document.createEvent("CustomEvent");
ev.initCustomEvent(type, true, true, detail || {});
} catch (e) {
ev = document.createEvent("Event");
ev.initEvent(type, true, true);
ev.detail = detail || {};
}
return ev;
}
// Constructor
function SearchBox(element, options) {
element = element || document.createElement("div");
if (element.__searchBoxInstance) {
throw new Error("Search.Box: duplicate construction on same element");
}
element.__searchBoxInstance = this;
// DOM elements
this._root = element;
this._input = document.createElement("input");
this._input.type = "search";
this._button = document.createElement("div");
this._button.tabIndex = -1;
this._flyout = document.createElement("div");
this._repeater = document.createElement("div"); // container for suggestion items
this._flyout.style.display = "none";
// state
this._suggestions = [];
this._currentSelectedIndex = -1; // fake focus/selection index
this._currentFocusedIndex = -1; // navigation focus index
this._prevQueryText = "";
this._chooseSuggestionOnEnter = false;
this._disposed = false;
this._lastKeyPressLanguage = "";
// classes follow WinJS naming where convenient (so your existing CSS can still be used)
this._root.className = (this._root.className ? this._root.className + " " : "") + "win-searchbox";
this._input.className = "win-searchbox-input";
this._button.className = "win-searchbox-button";
this._flyout.className = "win-searchbox-flyout";
this._repeater.className = "win-searchbox-repeater";
// assemble
this._flyout.appendChild(this._repeater);
this._root.appendChild(this._input);
this._root.appendChild(this._button);
this._root.appendChild(this._flyout);
// accessibility basics
this._root.setAttribute("role", "group");
this._input.setAttribute("role", "textbox");
this._button.setAttribute("role", "button");
this._repeater.setAttribute("role", "listbox");
if (!this._repeater.id) {
this._repeater.id = uniqueId("search_repeater_");
}
this._input.setAttribute("aria-controls", this._repeater.id);
this._repeater.setAttribute("aria-live", "polite");
// user-assignable event handlers (older style)
this.onquerychanged = null;
this.onquerysubmitted = null;
this.onresultsuggestionchosen = null;
this.onsuggestionsrequested = null;
// wire events
this._wireEvents();
// options
options = options || {};
if (options.placeholderText) this.placeholderText = options.placeholderText;
if (options.queryText) this.queryText = options.queryText;
if (options.chooseSuggestionOnEnter) this.chooseSuggestionOnEnter = !!options.chooseSuggestionOnEnter;
if (options.disabled) this.disabled = !!options.disabled;
// new events
this.ontextchanged = null;
}
// Prototype
SearchBox.prototype = {
// Properties
get element() {
return this._root;
},
get placeholderText() {
return this._input.placeholder;
},
set placeholderText(value) {
this._input.placeholder = value || "";
},
get queryText() {
return this._input.value;
},
set queryText(value) {
this._input.value = value == null ? "" : value;
},
get chooseSuggestionOnEnter() {
return this._chooseSuggestionOnEnter;
},
set chooseSuggestionOnEnter(v) {
this._chooseSuggestionOnEnter = !!v;
this._updateButtonClass();
},
get disabled() {
return !!this._input.disabled;
},
set disabled(v) {
var val = !!v;
if (val === this.disabled) return;
this._input.disabled = val;
try { this._button.disabled = val; } catch (e) {}
if (val) {
this._root.className = (this._root.className + " win-searchbox-disabled").trim();
this.hideFlyout();
} else {
this._root.className = this._root.className.replace(/\bwin-searchbox-disabled\b/g, "").trim();
}
},
// Public methods
setSuggestions: function(arr) {
// Expect array of objects with keys: kind (0/1/2 or 'query'/'result'/'separator'), text, detailText, tag, imageUrl, hits
this._suggestions = (arr && arr.slice(0)) || [];
this._currentSelectedIndex = -1;
this._currentFocusedIndex = -1;
this._renderSuggestions();
if (this._suggestions.length) this.showFlyout();
else this.hideFlyout();
},
clearSuggestions: function() {
this.setSuggestions([]);
},
showFlyout: function() {
if (!this._suggestions || this._suggestions.length === 0) return;
this._flyout.style.display = "block";
this._updateButtonClass();
},
hideFlyout: function() {
this._flyout.style.display = "none";
this._updateButtonClass();
},
dispose: function() {
if (this._disposed) return;
// detach event listeners by cloning elements (simple way)
var newRoot = this._root.cloneNode(true);
if (this._root.parentNode) {
this._root.parentNode.replaceChild(newRoot, this._root);
}
try {
delete this._root.__searchBoxInstance;
} catch (e) {}
this._disposed = true;
},
setLocalContentSuggestionSettings: function(settings) {
// No-op in non-WinRT environment; kept for API compatibility.
},
// Internal / rendering
_wireEvents: function() {
var that = this;
this._input.addEventListener("input", function(ev) {
that._onInputChange(ev);
}, false);
this._input.addEventListener("keydown", function(ev) {
that._onKeyDown(ev);
}, false);
this._input.addEventListener("keypress", function(ev) {
// capture locale if available
try { that._lastKeyPressLanguage = ev.locale || that._lastKeyPressLanguage; } catch (e) {}
}, false);
this._input.addEventListener("focus", function() {
if (that._suggestions.length) {
that.showFlyout();
that._updateFakeFocus();
}
that._root.className = (that._root.className + " win-searchbox-input-focus").trim();
that._updateButtonClass();
}, false);
this._input.addEventListener("blur", function() {
// small timeout to allow suggestion click to process
setTimeout(function() {
if (!that._root.contains(document.activeElement)) {
that.hideFlyout();
that._root.className = that._root.className.replace(/\bwin-searchbox-input-focus\b/g, "").trim();
that._currentFocusedIndex = -1;
that._currentSelectedIndex = -1;
}
}, 0);
}, false);
this._button.addEventListener("click", function(ev) {
that._input.focus();
that._submitQuery(that._input.value, ev);
that.hideFlyout();
}, false);
// delegate click for suggestions: attach on repeater container (works in IE10)
this._repeater.addEventListener("click", function(ev) {
var el = ev.target;
// climb until we find child with data-index
while (el && el !== that._repeater) {
if (el.hasAttribute && el.hasAttribute("data-index")) break;
el = el.parentNode;
}
if (el && el !== that._repeater) {
var idx = parseInt(el.getAttribute("data-index"), 10);
var item = that._suggestions[idx];
if (item) {
that._input.focus();
that._processSuggestionChosen(item, ev);
}
}
}, false);
},
_onInputChange: function(ev) {
if (this.disabled) return;
var v = this._input.value;
this._emit("textchanged", {
text: v
}, this.ontextchanged);
var changed = (v !== this._prevQueryText);
this._prevQueryText = v;
// fire querychanged
var evDetail = {
language: this._getBrowserLanguage(),
queryText: v,
linguisticDetails: { queryTextAlternatives: [], queryTextCompositionStart: 0, queryTextCompositionLength: 0 }
};
this._emit("querychanged", evDetail, this.onquerychanged);
// fire suggestionsrequested - allow client to call setSuggestions
var suggestionsDetail = {
queryText: v,
language: this._getBrowserLanguage(),
setSuggestions: (function(thatRef) {
return function(arr) {
thatRef.setSuggestions(arr || []);
};
})(this)
};
this._emit("suggestionsrequested", suggestionsDetail, this.onsuggestionsrequested);
},
_submitQuery: function(queryText, ev) {
var detail = {
language: this._getBrowserLanguage(),
queryText: queryText,
keyModifiers: this._getKeyModifiers(ev)
};
this._emit("querysubmitted", detail, this.onquerysubmitted);
},
_processSuggestionChosen: function(item, ev) {
// normalize kind
var kind = item.kind;
if (typeof kind === "string") {
if (kind.toLowerCase() === "query") kind = SuggestionKind.Query;
else if (kind.toLowerCase() === "result") kind = SuggestionKind.Result;
else if (kind.toLowerCase() === "separator") kind = SuggestionKind.Separator;
}
this.queryText = item.text || "";
if (kind === SuggestionKind.Query || kind === undefined) {
// choose query -> submit
this._submitQuery(item.text || "", ev);
} else if (kind === SuggestionKind.Result) {
this._emit("resultsuggestionchosen", {
tag: item.tag,
keyModifiers: this._getKeyModifiers(ev),
storageFile: null
}, this.onresultsuggestionchosen);
}
this.hideFlyout();
},
_renderSuggestions: function() {
// clear repeater
while (this._repeater.firstChild) this._repeater.removeChild(this._repeater.firstChild);
var frag = document.createDocumentFragment();
for (var i = 0; i < this._suggestions.length; i++) {
var s = this._suggestions[i];
var itemEl = this._renderSuggestion(s, i);
frag.appendChild(itemEl);
}
this._repeater.appendChild(frag);
this._updateFakeFocus();
},
_renderSuggestion: function(item, index) {
var that = this;
var kind = item.kind;
if (typeof kind === "string") {
kind = kind.toLowerCase() === "query" ? SuggestionKind.Query :
kind.toLowerCase() === "result" ? SuggestionKind.Result :
kind.toLowerCase() === "separator" ? SuggestionKind.Separator : kind;
}
var root = document.createElement("div");
root.setAttribute("data-index", index);
root.id = this._repeater.id + "_" + index;
if (kind === SuggestionKind.Separator) {
root.className = "win-searchbox-suggestion-separator";
if (item.text) {
var textEl = document.createElement("div");
textEl.innerText = item.text;
textEl.setAttribute("aria-hidden", "true");
root.appendChild(textEl);
}
root.insertAdjacentHTML("beforeend", "<hr/>");
root.setAttribute("role", "separator");
root.setAttribute("aria-label", item.text || "");
return root;
}
if (kind === SuggestionKind.Result) {
root.className = "win-searchbox-suggestion-result";
// image
var img = document.createElement("img");
img.setAttribute("aria-hidden", "true");
if (item.imageUrl) {
img.onload = function() {
img.style.opacity = "1";
};
img.style.opacity = "0";
img.src = item.imageUrl;
} else {
img.style.display = "none";
}
root.appendChild(img);
var textDiv = document.createElement("div");
textDiv.className = "win-searchbox-suggestion-result-text";
textDiv.setAttribute("aria-hidden", "true");
this._addHitHighlightedText(textDiv, item, item.text || "");
textDiv.title = item.text || "";
root.appendChild(textDiv);
var detail = document.createElement("span");
detail.className = "win-searchbox-suggestion-result-detailed-text";
detail.setAttribute("aria-hidden", "true");
this._addHitHighlightedText(detail, item, item.detailText || "");
textDiv.appendChild(document.createElement("br"));
textDiv.appendChild(detail);
root.setAttribute("role", "option");
root.setAttribute("aria-label", (item.text || "") + " " + (item.detailText || ""));
return root;
}
// default / query
root.className = "win-searchbox-suggestion-query";
this._addHitHighlightedText(root, item, item.text || "");
root.title = item.text || "";
root.setAttribute("role", "option");
root.setAttribute("aria-label", item.text || "");
return root;
},
_addHitHighlightedText: function(container, item, text) {
// Remove existing children
while (container.firstChild) container.removeChild(container.firstChild);
if (!text) return;
// Build hits from item.hits if present (array of {startPosition, length}), otherwise simple substring matches of current input
var hits = [];
if (item && item.hits && item.hits.length) {
for (var i = 0; i < item.hits.length; i++) {
hits.push({ startPosition: item.hits[i].startPosition, length: item.hits[i].length });
}
} else {
var q = this._input.value || "";
if (q) {
var low = text.toLowerCase();
var lq = q.toLowerCase();
var pos = 0;
while (true) {
var idx = low.indexOf(lq, pos);
if (idx === -1) break;
hits.push({ startPosition: idx, length: q.length });
pos = idx + q.length;
}
}
}
// Merge overlapping hits & sort
hits.sort(function(a, b) { return a.startPosition - b.startPosition; });
var merged = [];
for (var j = 0; j < hits.length; j++) {
if (merged.length === 0) {
merged.push({ startPosition: hits[j].startPosition, length: hits[j].length });
} else {
var cur = merged[merged.length - 1];
var curEnd = cur.startPosition + cur.length;
if (hits[j].startPosition <= curEnd) {
var nextEnd = hits[j].startPosition + hits[j].length;
if (nextEnd > curEnd) {
cur.length = nextEnd - cur.startPosition;
}
} else {
merged.push({ startPosition: hits[j].startPosition, length: hits[j].length });
}
}
}
var last = 0;
for (var k = 0; k < merged.length; k++) {
var h = merged[k];
if (h.startPosition > last) {
var pre = document.createElement("span");
pre.innerText = text.substring(last, h.startPosition);
pre.setAttribute("aria-hidden", "true");
container.appendChild(pre);
}
var hitSpan = document.createElement("span");
hitSpan.innerText = text.substring(h.startPosition, h.startPosition + h.length);
hitSpan.className = "win-searchbox-flyout-highlighttext";
hitSpan.setAttribute("aria-hidden", "true");
container.appendChild(hitSpan);
last = h.startPosition + h.length;
}
if (last < text.length) {
var post = document.createElement("span");
post.innerText = text.substring(last);
post.setAttribute("aria-hidden", "true");
container.appendChild(post);
}
if (merged.length === 0) {
// no hits - append plain text
var whole = document.createElement("span");
whole.innerText = text;
whole.setAttribute("aria-hidden", "true");
container.appendChild(whole);
}
},
_updateFakeFocus: function() {
var firstIndex = -1;
if ((this._flyout.style.display !== "none") && this._chooseSuggestionOnEnter) {
for (var i = 0; i < this._suggestions.length; i++) {
var s = this._suggestions[i];
var kind = s.kind;
if (typeof kind === "string") {
kind = kind.toLowerCase() === "query" ? SuggestionKind.Query :
kind.toLowerCase() === "result" ? SuggestionKind.Result :
kind.toLowerCase() === "separator" ? SuggestionKind.Separator : kind;
}
if (kind === SuggestionKind.Query || kind === SuggestionKind.Result) {
firstIndex = i;
break;
}
}
}
this._selectSuggestionAtIndex(firstIndex);
},
_selectSuggestionAtIndex: function(index) {
for (var i = 0; i < this._repeater.children.length; i++) {
var el = this._repeater.children[i];
if (!el) continue;
if (i === index) {
if (el.className.indexOf("win-searchbox-suggestion-selected") === -1) {
el.className = (el.className + " win-searchbox-suggestion-selected").trim();
}
el.setAttribute("aria-selected", "true");
try {
this._input.setAttribute("aria-activedescendant", el.id);
} catch (e) {}
// ensure visible
try {
var top = el.offsetTop;
var bottom = top + el.offsetHeight;
var scrollTop = this._flyout.scrollTop;
var height = this._flyout.clientHeight;
if (bottom > scrollTop + height) this._flyout.scrollTop = bottom - height;
else if (top < scrollTop) this._flyout.scrollTop = top;
} catch (e) {}
} else {
el.className = el.className.replace(/\bwin-searchbox-suggestion-selected\b/g, "").trim();
el.setAttribute("aria-selected", "false");
}
}
if (index === -1) {
try { this._input.removeAttribute("aria-activedescendant"); } catch (e) {}
}
this._currentSelectedIndex = index;
this._updateButtonClass();
},
_updateButtonClass: function() {
if ((this._currentSelectedIndex !== -1) || (document.activeElement !== this._input)) {
this._button.className = this._button.className.replace(/\bwin-searchbox-button-input-focus\b/g, "").trim();
} else if (document.activeElement === this._input) {
if (this._button.className.indexOf("win-searchbox-button-input-focus") === -1) {
this._button.className = (this._button.className + " win-searchbox-button-input-focus").trim();
}
}
},
_onKeyDown: function(ev) {
// Normalize key
var key = ev.key || "";
if (!key && ev.keyCode) {
if (ev.keyCode === 13) key = "Enter";
else if (ev.keyCode === 27) key = "Esc";
else if (ev.keyCode === 38) key = "Up";
else if (ev.keyCode === 40) key = "Down";
else if (ev.keyCode === 9) key = "Tab";
}
if (key === "Tab") {
// handle tab navigation into suggestions
if (ev.shiftKey) {
// shift+tab: allow default behavior
} else {
if (this._currentFocusedIndex === -1) {
this._currentFocusedIndex = this._findNextSuggestionElementIndex(-1);
}
if (this._currentFocusedIndex !== -1) {
this._selectSuggestionAtIndex(this._currentFocusedIndex);
this._updateQueryTextWithSuggestionText(this._currentFocusedIndex);
ev.preventDefault();
ev.stopPropagation();
}
}
} else if (key === "Esc") {
if (this._currentFocusedIndex !== -1) {
this.queryText = this._prevQueryText;
this._currentFocusedIndex = -1;
this._selectSuggestionAtIndex(-1);
this._updateButtonClass();
ev.preventDefault();
ev.stopPropagation();
} else if (this.queryText !== "") {
this.queryText = "";
// trigger querychanged handlers
this._onInputChange(null);
this._updateButtonClass();
ev.preventDefault();
ev.stopPropagation();
}
} else if (key === "Up") {
var prev;
if (this._currentSelectedIndex !== -1) {
prev = this._findPreviousSuggestionElementIndex(this._currentSelectedIndex);
if (prev === -1) this.queryText = this._prevQueryText;
} else {
prev = this._findPreviousSuggestionElementIndex(this._suggestions.length);
}
this._currentFocusedIndex = prev;
this._selectSuggestionAtIndex(prev);
this._updateQueryTextWithSuggestionText(this._currentFocusedIndex);
this._updateButtonClass();
ev.preventDefault();
ev.stopPropagation();
} else if (key === "Down") {
var next = this._findNextSuggestionElementIndex(this._currentSelectedIndex);
if ((this._currentSelectedIndex !== -1) && (next === -1)) this.queryText = this._prevQueryText;
this._currentFocusedIndex = next;
this._selectSuggestionAtIndex(next);
this._updateQueryTextWithSuggestionText(this._currentFocusedIndex);
this._updateButtonClass();
ev.preventDefault();
ev.stopPropagation();
} else if (key === "Enter") {
if (this._currentSelectedIndex === -1) {
this._submitQuery(this._input.value, ev);
} else {
var chosen = this._suggestions[this._currentSelectedIndex];
if (chosen) this._processSuggestionChosen(chosen, ev);
else this._submitQuery(this._input.value, ev);
}
this.hideFlyout();
ev.preventDefault();
ev.stopPropagation();
} else {
// typing -> clear selection
if (this._currentFocusedIndex !== -1) {
this._currentFocusedIndex = -1;
this._selectSuggestionAtIndex(-1);
this._updateFakeFocus();
}
}
},
_findNextSuggestionElementIndex: function(curIndex) {
var start = curIndex + 1;
if (start < 0) start = 0;
for (var i = start; i < this._suggestions.length; i++) {
var s = this._suggestions[i];
var k = s.kind;
if (typeof k === "string") {
k = k.toLowerCase() === "query" ? SuggestionKind.Query :
k.toLowerCase() === "result" ? SuggestionKind.Result :
k.toLowerCase() === "separator" ? SuggestionKind.Separator : k;
}
if (k === SuggestionKind.Query || k === SuggestionKind.Result) return i;
}
return -1;
},
_findPreviousSuggestionElementIndex: function(curIndex) {
var start = curIndex - 1;
if (start >= this._suggestions.length) start = this._suggestions.length - 1;
for (var i = start; i >= 0; i--) {
var s = this._suggestions[i];
var k = s.kind;
if (typeof k === "string") {
k = k.toLowerCase() === "query" ? SuggestionKind.Query :
k.toLowerCase() === "result" ? SuggestionKind.Result :
k.toLowerCase() === "separator" ? SuggestionKind.Separator : k;
}
if (k === SuggestionKind.Query || k === SuggestionKind.Result) return i;
}
return -1;
},
_updateQueryTextWithSuggestionText: function(idx) {
if ((idx >= 0) && (idx < this._suggestions.length)) {
this.queryText = this._suggestions[idx].text || "";
}
},
_emit: function(type, detail, handler) {
var ev = createCustomEvent(type, detail);
// call handler property first
if (typeof handler === "function") {
try { handler.call(this, ev); } catch (e) { /* swallow */ }
}
try { this._root.dispatchEvent(ev); } catch (e) { /* swallow */ }
return ev;
},
_getBrowserLanguage: function() {
try {
return (navigator && (navigator.language || navigator.userLanguage)) || "";
} catch (e) {
return "";
}
},
_getKeyModifiers: function(ev) {
var m = 0;
if (!ev) return m;
if (ev.ctrlKey) m |= 1;
if (ev.altKey) m |= 2;
if (ev.shiftKey) m |= 4;
return m;
}
};
// export
global.Search.Box = SearchBox;
})(this);

184
shared/html/js/statusbar.js Normal file
View File

@@ -0,0 +1,184 @@
(function(global) {
"use strict";
/**
* TransitionPanel
* axis: 'x' | 'y' | 'both'
* speed: 'fast' | 'medium' | 'slow'
* el: DOM 元素
*/
function TransitionPanel(el, options) {
if (!el) throw new Error("TransitionPanel requires a DOM element.");
this.el = el;
this.opts = options || {};
this.axis = this.opts.axis || 'y';
this.speed = this.opts.speed || 'medium';
// 初始化状态
this._shown = false;
this._events = {};
// 确保基础类 statusbar
if (!el.classList.contains('statusbar')) el.classList.add('statusbar');
// 确保 axis 类存在x/y/both
if (this.axis === 'x' && !el.classList.contains('x')) el.classList.add('x');
else if (this.axis === 'y' && !el.classList.contains('y')) el.classList.add('y');
else if (this.axis === 'both' && !el.classList.contains('both')) el.classList.add('both');
// 添加速度类
if (this.speed === 'fast') el.classList.add('fast');
else if (this.speed === 'medium') el.classList.add('medium');
else el.classList.add('slow');
// 内容变化自动刷新
this._bindContentChange();
}
function maxWidth(el) {
var cw = 0;
var ow = 0;
var rw = 0;
var sw = 0;
try { cw = el.clientWidth; } catch (e) {}
try { ow = el.offsetWidth; } catch (e) {}
try { rw = el.getBoundingClientRect().width; } catch (e) {}
try { sw = el.scrollWidth; } catch (e) {}
return Math.max(cw, ow, rw, sw);
}
function maxHeight(el) {
var ch = 0;
var oh = 0;
var rh = 0;
var sh = 0;
try { ch = el.clientHeight; } catch (e) {}
try { oh = el.offsetHeight; } catch (e) {}
try { rh = el.getBoundingClientRect().height; } catch (e) {}
try { sh = el.scrollHeight; } catch (e) {}
return Math.max(ch, oh, rh, sh);
}
// 显示
TransitionPanel.prototype.show = function() {
if (this._shown) return;
this._emit('beforeshow');
this._shown = true;
var el = this.el;
setTimeout(function() {
this._emit('show');
if (this.axis !== 'x') el.style.height = maxHeight(el) + 'px';
if (this.axis !== 'y') el.style.width = maxWidth(el) + 'px';
if (this.axis === 'both') {
el.style.height = maxHeight(el) + 'px';
el.style.width = maxWidth(el) + 'px';
}
this._afterTransition('aftershow');
}.bind(this), 16);
};
// 隐藏
TransitionPanel.prototype.hide = function() {
if (!this._shown) return;
this._emit('beforehide');
this._shown = false;
var el = this.el;
// 锁定当前尺寸
if (this.axis !== 'x') el.style.height = maxHeight(el) + 'px';
if (this.axis !== 'y') el.style.width = maxWidth(el) + 'px';
if (this.axis === 'both') {
el.style.height = maxHeight(el) + 'px';
el.style.width = maxWidth(el) + 'px';
}
setTimeout(function() {
this._emit('hide');
// 回到折叠状态尺寸(依赖 x/y/both 类)
if (this.axis !== 'x') el.style.height = '';
if (this.axis !== 'y') el.style.width = '';
if (this.axis === 'both') {
el.style.height = '';
el.style.width = '';
}
this._afterTransition('afterhide');
}.bind(this), 16);
};
// 刷新尺寸(显示中)
TransitionPanel.prototype.refresh = function() {
if (!this._shown) return;
var el = this.el;
if (this.axis !== 'x') el.style.height = el.scrollHeight + 'px';
if (this.axis !== 'y') el.style.width = el.scrollWidth + 'px';
};
// 内容变化自动刷新
TransitionPanel.prototype._bindContentChange = function() {
if (!global.setTextChangeEvent) return;
var self = this;
global.setTextChangeEvent(this.el, function() {
if (self._shown) self.refresh();
});
};
// transitionend 回调处理
TransitionPanel.prototype._afterTransition = function(evt) {
var el = this.el;
var called = false;
var duration = this.speed === 'fast' ? 300 : (this.speed === 'medium' ? 500 : 700);
function done() {
if (called) return;
called = true;
el.removeEventListener('transitionend', done);
if (evt) this._emit(evt);
}
el.addEventListener('transitionend', done.bind(this));
setTimeout(done.bind(this), duration + 30);
};
// 生命周期事件绑定
TransitionPanel.prototype.on = function(name, fn) {
(this._events[name] || (this._events[name] = [])).push(fn);
};
// 事件触发
TransitionPanel.prototype._emit = function(name) {
var list = this._events[name];
if (!list) return;
for (var i = 0; i < list.length; i++) {
try { list[i].call(this); } catch (e) { console.error(e); }
}
};
// 只读属性 shown
Object.defineProperty(TransitionPanel.prototype, 'shown', {
get: function() { return this._shown; }
});
// 销毁
TransitionPanel.prototype.dispose = function() {
// 移除所有事件回调
this._events = {};
// 清理 el 内联样式
if (this.el) {
this.el.style.height = '';
this.el.style.width = '';
}
this._shown = false;
// 可选:删除内容变化监听(如果使用全局 setTextChangeEvent
if (global.Windows && global.Windows.UI && global.Windows.UI.Event && global.Windows.UI.Event.Monitor) {
// 这里可以 detach 所有回调
// 视具体实现可扩展
}
};
// 全局暴露
global.TransitionPanel = TransitionPanel;
})(this);

View File

@@ -33,6 +33,9 @@
<script type="text/javascript" src="js/datasrc.js"></script>
<script type="text/javascript" src="js/appbar.js"></script>
<script type="text/javascript" src="js/pagemgr.js"></script>
<script type="text/javascript" src="js/search.js"></script>
<link rel="stylesheet" href="css/statusbar.css">
<script type="text/javascript" src="js/statusbar.js"></script>
<script type="text/javascript" src="js/manager/pages.js"></script>
<script type="text/javascript" src="js/mgrinit.js"></script>
</head>
@@ -42,15 +45,39 @@
<div class="page full guide fold">
<main class="main padding">
<div id="page-manager" style="display: none;" class="ispage">
<h2>应用</h2>
<p>在这里,可以对安装的 Windows 商店应用进行管理。</p>
<h3>安装的应用</h3>
<h2 data-res-resxml="MANAGER_APP_TITLE"></h2>
<p data-res-resxml="MANAGER_APP_DESCRIPTION"></p>
<h3 data-res-resxml="MANAGER_APP_INSTALLEDAPPS"></h3>
<br>
<div class="app-loading" id="applist-loading" style="display: none;">
<progress class="win-ring"></progress>
<span class="win-label title">正在加载应用...</span>
<br>
<div class="win-searchbox win-disposable" id="applist-search" role="group" aria-label="搜索框"></div>
<div class="applist-options">
<div class="item">
<input type="checkbox" id="applist-showsystemapp">
<label for="applist-showsystemapp" data-res-resxml="MANAGER_APP_SHOWSYSTEMAPP"></label>
</div>
<div class="item">
<input type="checkbox" id="applist-showframework">
<label for="applist-showframework" data-res-resxml="MANAGER_APP_SHOWFRAMEWORK"></label>
</div>
</div>
<div class="app-loading" id="applist-loading" style="display: none;">
<br>
<div class="container">
<progress class="win-ring"></progress>
<span class="win-label title" data-res-resxml="MANAGER_APP_INSTALLEDAPPS_LOADING"></span>
<br>
</div>
</div>
<p id="applist-datalen"></p>
<script>
(function(global) {
var appLoading = document.getElementById("applist-loading");
appLoading.bar = new TransitionPanel(appLoading, {
axis: 'y',
duration: 500,
});
})(this);
</script>
<div class="appitem" id="appitem-template" style="display: none;">
<div role="img" style="pointer-events: none;">
<img width="" height="" src="images/applogo.default.png" />
@@ -58,14 +85,18 @@
<div role="divide" style="pointer-events: none;"></div>
<div role="excepticon">
<div role="title" class="win-type-x-small" style="pointer-events: none;">
<span class="displayName">App Name</span><br>
<span class="publisher">Publisher</span>
<span class="displayName"></span><br>
<span class="publisher"></span>
</div>
<div role="advance">
<a>高级选项</a>
<a data-res-resxml="MANAGER_APP_ADVANCEOPTIONS"></a>
</div>
<div role="progress">
<span class="status" data-res-resxml="MANAGER_APP_UNINSTALL_ING"></span><br>
<progress class="win-progress progress" min="0" max="100"></progress>
</div>
<div role="control">
<button name="uninstall">卸载</button>
<button class="uninstall" name="uninstall" data-res-resxml="MANAGER_APP_UNINSTALL"></button>
</div>
</div>
</div>
@@ -73,7 +104,7 @@
</div>
<div class="bottom-compensate"></div>
</div>
<div id="page-appinfo" class="ispage app-detailpage">
<div id="page-appinfo" class="ispage app-detailpage" style="display: none;">
<header>
<button class="win-backbutton"></button>
<h2 class="display-name">App DisplayName</h2>
@@ -81,18 +112,37 @@
<span class="publisher-display-name">App PublisherDisplayName</span><br>
<span class="version">App Version</span><br>
<span class="description">App Description</span>
<p><strong>应用身份</strong></p>
<p><strong data-res-resxml="MANAGER_APP_IDENTITY"></strong></p>
<div class="identity win-type-body" style="width: 100%; max-width: 100%; box-sizing: border-box; -ms-user-select: element;">
<span style="font-weight: bold;">名称</span><span>: </span><span class="name"></span><br>
<span style="font-weight: bold;">发布者</span><span>: </span><span class="publisher"></span><br>
<span style="font-weight: bold;">发布者 ID</span><span>: </span><span class="publisher-id"></span><br>
<span style="font-weight: bold;">系列名</span><span>: </span><span class="family-name"></span><br>
<span style="font-weight: bold;">全名</span><span>: </span><span class="full-name"></span><br>
<span style="font-weight: bold;">支持的处理器架构</span><span>: </span><span class="architecture"></span><br>
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_NAME"></span><span>: </span><span class="name"></span><br>
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_PUBLISHER"></span><span>: </span><span class="publisher"></span><br>
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_PUBLISHERID"></span><span>: </span><span class="publisher-id"></span><br>
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_FAMILYNAME"></span><span>: </span><span class="family-name"></span><br>
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_FULLNAME"></span><span>: </span><span class="full-name"></span><br>
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_ARCHITECTURE"></span><span>: </span><span class="architecture"></span><br>
</div>
<p><strong>卸载</strong></p>
<p>卸载此应用及其设置。</p>
<button id="detail-uninstall-btn" data-app-fullname="">卸载</button>
<p><strong data-res-resxml="MANAGER_APP_HASAPPS"></strong></p>
<p data-res-resxml="MANAGER_APP_HASAPPS_DESC"></p>
<div class="loadingstatus" id="appinfo-loading">
<div class="container">
<progress class="win-ring"></progress>
<span class="win-label title" data-res-resxml="MANAGER_APP_INSTALLEDAPPS_LOADING"></span>
<br>
</div>
</div>
<div class="apps">
</div>
<p><strong data-res-resxml="MANAGER_APP_UNINSTALL"></strong></p>
<p data-res-resxml="MANAGER_APP_UNINSTALL_DESC"></p>
<div class="loadingstatus" id="appinfo-uninstallstatus">
<div style="width: 100%;">
<span class="status" data-res-resxml="MANAGER_APP_UNINSTALL_ING"></span><br>
<progress class="win-progress progress" min="0" max="100"></progress>
</div>
<br>
</div>
<button id="detail-uninstall-btn" data-res-resxml="MANAGER_APP_UNINSTALL">卸载</button>
<div class="bottom-compensate"></div>
</div>
</main>
<aside class="win-ui-dark">
@@ -100,8 +150,8 @@
<ul class="list top">
<li class="title">
<div role="img">&#58344;</div>
<div role="placeholder"></div>
<span class="win-type-base">应用管理</span>
<!--<div role="placeholder"></div>-->
<span class="win-type-base" data-res-resxml="MANAGER_APPTITLE"></span>
</li>
<script>
(function($) {
@@ -117,7 +167,7 @@
<ul class="list">
<li id="tag-manager">
<div role="img">&#57587;</div>
<span class="win-type-base">管理</span>
<span class="win-type-base" data-res-resxml="MANAGER_MANAGE"></span>
</li>
<li id="tag-appinfo" class="subitem">
<div role="img">&#57650;</div>
@@ -134,6 +184,39 @@
</div>
<div class="win-overlay win-commandlayout win-appbar win-bottom appbar win-ui-dark" id="appBar" role="menubar">
</div>
<div data-win-control="WinJS.UI.Flyout" id="app-uninstall-flyout" style="position: absolute; width: 336px; padding: 0; max-height: 284px;">
<div class="top" style="padding: 20px 20px 0 20px;">
<span data-res-resxml="MANAGER_APP_UNINSTALL_DESC"></span>
</div>
<div class="sapplist applist"></div>
<style>
#app-uninstall-flyout {
/*min-height: 88px;
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);*/
}
#app-uninstall-flyout .sapplist {
padding: 0 20px;
width: 100%;
box-sizing: border-box;
overflow-x: hidden;
overflow-y: auto;
-ms-overflow-style: -ms-autohiding-scrollbar;
max-height: 160px;
}
</style>
<div class="bottom" style="padding: 20px 20px 20px 20px; height: 32px;">
<button class="confirm" data-res-resxml="MANAGER_APP_UNINSTALL" style="float: right;"></button>
</div>
</div>
<div id="app-deskshortcut-create" style="position: absolute;">
<p>即将在桌面创建快捷方式,这里做一些调整。快捷方式不建议固定到开始菜单中,因为本快捷方式只是一种启动器。不具有其余磁贴功能。</p>
<div>
<div>
<div class="win-radio"></div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -32,6 +32,7 @@
}
.appitem div[role=img] {
position: relative;
width: 40px;
height: 40px;
background-color: #464646;
@@ -58,6 +59,16 @@
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);
}
.appitem div[role=img]::after {
border: 1px solid rgba(254, 254, 254, 0.1);
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.appitem div[role=img] img {
width: 30px;
height: 30px;
@@ -113,6 +124,11 @@
width: calc(100% - 40px - 10px);
}
.appitem div[role=excepticon] div[role=progress] {
display: none;
width: 100%;
}
.appitem div[role=excepticon] div[role=control] {
display: none;
/* IE10 */
@@ -136,11 +152,45 @@
height: 0;
}
.appitem div[role=excepticon] div[role=progress] {
width: 100%;
box-sizing: border-box;
}
.appitem.uninstalling,
.appitem.selected {
height: 119px;
background-color: rgba(232, 232, 232, 1);
}
.appitem.uninstalled div[role=excepticon] div[role=progress],
.appitem.uninstalling div[role=excepticon] div[role=progress] {
display: block;
flex: 1 0 auto;
-ms-flex: 1 0 auto;
width: 100%;
}
.appitem.uninstalling div[role=excepticon] div[role=progress] progress {
max-width: 100%;
}
.appitem.uninstalled div[role=excepticon] div[role=progress] progress {
display: none;
}
.appitem.uninstalling div[role=excepticon] div[role=progress],
.appitem.uninstalled div[role=excepticon] div[role=progress],
.appitem.uninstalling div[role=excepticon] div[role=progress] .status,
.appitem.uninstalled div[role=excepticon] div[role=progress] .status {
word-break: break-all;
word-wrap: break-word;
}
.appitem.uninstalled {
height: auto;
}
.appitem.selected div[role=excepticon] div[role=control] {
display: flex;
display: -ms-flexbox;
@@ -148,6 +198,23 @@
height: auto;
}
.appitem.uninstalling div[role=excepticon] div[role=advance],
.appitem.uninstalling div[role=excepticon] div[role=control],
.appitem.uninstalling.selected div[role=excepticon] div[role=advance],
.appitem.uninstalling.selected div[role=excepticon] div[role=control],
.appitem.uninstalled div[role=excepticon] div[role=advance],
.appitem.uninstalled div[role=excepticon] div[role=control],
.appitem.uninstalled.selected div[role=excepticon] div[role=advance],
.appitem.uninstalled.selected div[role=excepticon] div[role=control] {
display: none;
}
.appitem.uninstalling div[role=excepticon] div[role=title],
.appitem.uninstalled div[role=excepticon] div[role=title] {
-ms-flex: none;
flex: none;
}
ul.appitem-list,
ul.appitem-list li {
margin: 0;
@@ -169,6 +236,11 @@ ul.appitem-list li {
}
.app-loading {
width: 100%;
height: auto;
}
.app-loading .container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
@@ -176,7 +248,17 @@ ul.appitem-list li {
justify-content: flex-start;
align-items: center;
width: 100%;
height: auto;
/*****/
display: -ms-flexbox;
/* IE10 */
-ms-flex-direction: row;
/* flex-direction: row */
-ms-flex-wrap: wrap;
/* flex-wrap: wrap */
-ms-flex-pack: start;
/* justify-content: flex-start */
-ms-flex-align: center;
/* align-items: center */
}
.app-loading.noloading progress {
@@ -204,6 +286,13 @@ ul.appitem-list li {
height: 67px;
box-sizing: border-box;
max-width: 100%;
display: -ms-flexbox;
-ms-flex-direction: row;
/* flex-direction: row */
-ms-flex-wrap: nowrap;
/* flex-wrap: nowrap */
-ms-flex-pack: start;
/* justify-content: flex-start */
}
.app-detailpage header .win-backbutton {
@@ -223,3 +312,91 @@ ul.appitem-list li {
overflow-x: hidden;
text-overflow: ellipsis;
}
.app-detailpage .identity,
.app-detailpage .publisher-display-name,
.app-detailpage .version,
.app-detailpage .description {
word-break: break-all;
}
.loadingstatus {
width: 100%;
height: auto;
}
.loadingstatus .container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-content: center;
justify-content: flex-start;
align-items: center;
width: 100%;
/* IE10 */
display: -ms-flexbox;
-ms-flex-direction: row;
/* flex-direction: row */
-ms-flex-wrap: wrap;
/* flex-wrap: wrap */
-ms-flex-pack: start;
/* justify-content: flex-start */
-ms-flex-align: center;
/* align-items: center */
}
.loadingstatus.noloading progress {
display: none;
}
.loadingstatus .title {
margin-left: 10px;
}
.loadingstatus.noloading .title {
margin-left: 0;
}
.applist-options {
margin: 10px 0 0;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-content: flex-start;
justify-content: flex-start;
align-items: center;
/* IE10 */
display: -ms-flexbox;
-ms-flex-direction: row;
/* flex-direction: row */
-ms-flex-wrap: wrap;
/* flex-wrap: wrap */
-ms-flex-pack: start;
/* justify-content: flex-start */
-ms-flex-align: center;
/* align-items: center */
}
.applist-options .item {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: flex-start;
justify-content: flex-start;
align-items: center;
margin-right: 20px;
/* IE10 */
display: -ms-flexbox;
-ms-flex-direction: row;
/* flex-direction: row */
-ms-flex-wrap: nowrap;
/* flex-wrap: nowrap */
-ms-flex-pack: start;
/* justify-content: flex-start */
-ms-flex-align: center;
/* align-items: center */
}
.applist-options .item input[type="checkbox"] {
margin-left: 0;
}

View File

@@ -1,233 +1,361 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<resource id="ms-resource://Microsoft.WinJS.1.0/ui/off">
<lang name="zh-CN"></lang>
<lang name="en-US">Off</lang>
<lang name="af-ZA">Af</lang>
<lang name="am-ET">አጥፋ</lang>
<lang name="ar-SA">إيقاف التشغيل</lang>
<lang name="as-IN">অফ</lang>
<lang name="az-LATN-AZ">Qeyri-aktiv</lang>
<lang name="be-BY">Выкл.</lang>
<lang name="bg-BG">Изключено</lang>
<lang name="bn-BD">বন্ধ</lang>
<lang name="bn-IN">বন্ধ</lang>
<lang name="bs-LATN-BA">Isključeno</lang>
<lang name="ca-ES">Inactiva</lang>
<lang name="ca-ES-VALENCIA">Inactiva</lang>
<lang name="chr-CHER-US">ᎠᏍᏚᏗ</lang>
<lang name="cs-CZ">Vypnuto</lang>
<lang name="cy-GB">Diffodd</lang>
<lang name="da-DK">Fra</lang>
<lang name="de-DE">Aus</lang>
<lang name="el-GR">Ανενεργό</lang>
<lang name="en-GB">Off</lang>
<lang name="es-ES">Desactivado</lang>
<lang name="et-EE">Väljas</lang>
<lang name="eu-ES">Desaktibatuta</lang>
<lang name="fa-IR">خاموش</lang>
<lang name="fi-FI">Ei käytössä</lang>
<lang name="fil-PH">Naka-off</lang>
<lang name="fr-FR">Inactif</lang>
<lang name="ga-IE">As</lang>
<lang name="gd-GB">Dheth</lang>
<lang name="gl-ES">Desactivado</lang>
<lang name="gu-IN">બંધ</lang>
<lang name="ha-LATN-NG">Kashe</lang>
<lang name="he-IL">לא פעיל</lang>
<lang name="hi-IN">बंद</lang>
<lang name="hr-HR">Isključeno</lang>
<lang name="hu-HU">Kikapcsolva</lang>
<lang name="hy-AM">Անջատ</lang>
<lang name="id-ID">Nonaktif</lang>
<lang name="ig-NG">Gbanyọ</lang>
<lang name="is-IS">Óvirkt</lang>
<lang name="it-IT">Disattivato</lang>
<lang name="iu-LATN-CA">Qaminngajuq</lang>
<lang name="ja-JP">オフ</lang>
<lang name="ka-GE">გამორთვა</lang>
<lang name="kk-KZ">Өшірілген</lang>
<lang name="km-KH">បិទ</lang>
<lang name="kn-IN">ಆಫ್</lang>
<lang name="ko-KR">해제</lang>
<lang name="kok-IN">ऑफ करचें</lang>
<lang name="ku-ARAB-IQ">کوژاوە</lang>
<lang name="ky-KG">Өчүрулгөн</lang>
<lang name="lb-LU">Aus</lang>
<lang name="lt-LT">Išjungta</lang>
<lang name="lv-LV">Izslēgts</lang>
<lang name="mi-NZ">Weto ana</lang>
<lang name="mk-MK">Исклучено</lang>
<lang name="ml-IN">ഓഫ്</lang>
<lang name="mn-MN">Idəvxgüĭ</lang>
<lang name="mr-IN">बंद</lang>
<lang name="ms-MY">Mati</lang>
<lang name="mt-MT">Mitfi</lang>
<lang name="nb-NO">Av</lang>
<lang name="ne-NP">निभाउनुहोस्</lang>
<lang name="nl-NL">Uit</lang>
<lang name="nn-NO">Av</lang>
<lang name="nso-ZA">Timilwe</lang>
<lang name="or-IN">ଅଫ୍</lang>
<lang name="pa-ARAB-PK">بند</lang>
<lang name="pa-IN">ਬੰਦ ਕਰੋ</lang>
<lang name="pl-PL">Wyłączone</lang>
<lang name="prs-AF">خاموش</lang>
<lang name="pt-BR">Desligado</lang>
<lang name="pt-PT">Desativado</lang>
<lang name="qps-PLOC">[3Hcgw][Ǿƒƒ ]</lang>
<lang name="qps-PLOCM">‏‏أبع[Off]לף</lang>
<lang name="qut-GT">Q'atetalik</lang>
<lang name="quz-PE">Tukuchisqa</lang>
<lang name="ro-RO">Dezactivat</lang>
<lang name="ru-RU">Откл.</lang>
<lang name="rw-RW">Irafunze</lang>
<lang name="sd-ARAB-PK">بند کوليو</lang>
<lang name="si-LK">අක්‍රීය</lang>
<lang name="sk-SK">Vypnuté</lang>
<lang name="sl-SI">Izklopljeno</lang>
<lang name="sq-AL">Joaktiv</lang>
<lang name="sr-CYRL-BA">Искључено</lang>
<lang name="sr-CYRL-CS">Искључено</lang>
<lang name="sr-LATN-CS">Isključeno</lang>
<lang name="sv-SE">Av</lang>
<lang name="sw-KE">Zima</lang>
<lang name="ta-IN">அணை</lang>
<lang name="te-IN">ఆఫ్ చేయి</lang>
<lang name="tg-CYRL-TJ">Хомӯш</lang>
<lang name="th-TH">ปิด</lang>
<lang name="ti-ET">ኣጥፍእ</lang>
<lang name="tk-TM">Öçürilen</lang>
<lang name="tn-ZA">Timilwe</lang>
<lang name="tr-TR">Kapalı</lang>
<lang name="tt-RU">Сүндерелгән</lang>
<lang name="ug-CN">يېپىق</lang>
<lang name="uk-UA">Вимк.</lang>
<lang name="ur-PK">آف</lang>
<lang name="uz-LATN-UZ">Och</lang>
<lang name="vi-VN">Tắt</lang>
<lang name="wo-SN">Fay</lang>
<lang name="xh-ZA">Cimile</lang>
<lang name="yo-NG">Pa</lang>
<lang name="zh-HK">關閉</lang>
<lang name="zh-TW">關閉</lang>
<lang name="zu-ZA">Cishile</lang>
</resource>
<resource id="ms-resource://Microsoft.WinJS.1.0/ui/on">
<lang name="zh-CN"></lang>
<lang name="en-US">On</lang>
<lang name="af-ZA">Aan</lang>
<lang name="am-ET">አብራ</lang>
<lang name="ar-SA">تشغيل</lang>
<lang name="as-IN">অন</lang>
<lang name="az-LATN-AZ">Aktiv</lang>
<lang name="be-BY">Укл.</lang>
<lang name="bg-BG">Включено</lang>
<lang name="bn-BD">চালু</lang>
<lang name="bn-IN">চালু</lang>
<lang name="bs-LATN-BA">Uključeno</lang>
<lang name="ca-ES">Activa</lang>
<lang name="ca-ES-VALENCIA">Activa</lang>
<lang name="chr-CHER-US">ᎠᏍᏚᎢᏍᏗ</lang>
<lang name="cs-CZ">Zapnuto</lang>
<lang name="cy-GB">Ar waith</lang>
<lang name="da-DK">Til</lang>
<lang name="de-DE">Ein</lang>
<lang name="el-GR">Ενεργό</lang>
<lang name="en-GB">On</lang>
<lang name="es-ES">Activado</lang>
<lang name="et-EE">Sees</lang>
<lang name="eu-ES">Aktibatuta</lang>
<lang name="fa-IR">روشن</lang>
<lang name="fi-FI">Käytössä</lang>
<lang name="fil-PH">Naka-on</lang>
<lang name="fr-FR">Actif</lang>
<lang name="ga-IE">Air</lang>
<lang name="gd-GB">Air</lang>
<lang name="gl-ES">Activado</lang>
<lang name="gu-IN">ચાલુ</lang>
<lang name="ha-LATN-NG">Kunna</lang>
<lang name="he-IL">פעיל</lang>
<lang name="hi-IN">चालू</lang>
<lang name="hr-HR">Uključeno</lang>
<lang name="hu-HU">Bekapcsolva</lang>
<lang name="hy-AM">Միաց</lang>
<lang name="id-ID">Aktif</lang>
<lang name="ig-NG">Gbanye</lang>
<lang name="is-IS">Virkt</lang>
<lang name="it-IT">Attivato</lang>
<lang name="iu-LATN-CA">Ikumajuq</lang>
<lang name="ja-JP">オン</lang>
<lang name="ka-GE">ჩართვა</lang>
<lang name="kk-KZ">Қосылған</lang>
<lang name="km-KH">បើក</lang>
<lang name="kn-IN">ಆನ್</lang>
<lang name="ko-KR">설정</lang>
<lang name="kok-IN">ऑन करचें</lang>
<lang name="ku-ARAB-IQ">هەڵکراو</lang>
<lang name="ky-KG">Күйгүзүлгөн</lang>
<lang name="lb-LU">Un</lang>
<lang name="lt-LT">Įjungta</lang>
<lang name="lv-LV">Ieslēgts</lang>
<lang name="mi-NZ">Kā ana</lang>
<lang name="mk-MK">Вклученo</lang>
<lang name="ml-IN">ഓൺ</lang>
<lang name="mn-MN">Идэвхтэй</lang>
<lang name="mr-IN">चालू</lang>
<lang name="ms-MY">Hidup</lang>
<lang name="mt-MT">Mixgħul</lang>
<lang name="nb-NO"></lang>
<lang name="ne-NP">खोल्नुहोस्</lang>
<lang name="nl-NL">Aan</lang>
<lang name="nn-NO"></lang>
<lang name="nso-ZA">Goteditšwe</lang>
<lang name="or-IN">ଅନ୍</lang>
<lang name="pa-ARAB-PK">چالُو</lang>
<lang name="pa-IN">ਚਾਲੂ ਕਰੋ</lang>
<lang name="pl-PL">Włączone</lang>
<lang name="prs-AF">روشن</lang>
<lang name="pt-BR">Ligado</lang>
<lang name="pt-PT">Ativado</lang>
<lang name="qps-PLOC">[Aj8Pp][Őņ ]</lang>
<lang name="qps-PLOCM">‏‏أبع[On]לף</lang>
<lang name="qut-GT">Tzijtalik</lang>
<lang name="quz-PE">Kawsarichisqa</lang>
<lang name="ro-RO">Activat</lang>
<lang name="ru-RU">Вкл.</lang>
<lang name="rw-RW">Irafunguye</lang>
<lang name="sd-ARAB-PK">شروع ڪريو</lang>
<lang name="si-LK">සක්‍රීය</lang>
<lang name="sk-SK">Zapnuté</lang>
<lang name="sl-SI">Vklopljeno</lang>
<lang name="sq-AL">Aktiv</lang>
<lang name="sr-CYRL-BA">Укључено</lang>
<lang name="sr-CYRL-CS">Укључено</lang>
<lang name="sr-LATN-CS">Uključeno</lang>
<lang name="sv-SE"></lang>
<lang name="sw-KE">Washa</lang>
<lang name="ta-IN">இயக்கு</lang>
<lang name="te-IN">ఆన్ చేయి</lang>
<lang name="tg-CYRL-TJ">Фаъол</lang>
<lang name="th-TH">เปิด</lang>
<lang name="ti-ET">ወልዕ</lang>
<lang name="tk-TM">Açyk</lang>
<lang name="tn-ZA">Tshubilwe</lang>
<lang name="tr-TR">ık</lang>
<lang name="tt-RU">Кабызылган</lang>
<lang name="ug-CN">ئوچۇق</lang>
<lang name="uk-UA">Увімк.</lang>
<lang name="ur-PK">آن</lang>
<lang name="uz-LATN-UZ">Yoq</lang>
<lang name="vi-VN">Bật</lang>
<lang name="wo-SN">Taal</lang>
<lang name="xh-ZA">Layitile</lang>
<lang name="yo-NG">Tàn</lang>
<lang name="zh-HK">開啟</lang>
<lang name="zh-TW">開啟</lang>
<lang name="zu-ZA">Vuliwe</lang>
</resource>
<resource id="license">
<lang name="zh-CN">license_cn.html</lang>
<lang name="en-US">license_en.html</lang>
</resource>
<resource id="ms-resource://Microsoft.WinJS.1.0/ui/off">
<lang name="zh-CN"></lang>
<lang name="en-US">Off</lang>
<lang name="af-ZA">Af</lang>
<lang name="am-ET">አጥፋ</lang>
<lang name="ar-SA">إيقاف التشغيل</lang>
<lang name="as-IN">অফ</lang>
<lang name="az-LATN-AZ">Qeyri-aktiv</lang>
<lang name="be-BY">Выкл.</lang>
<lang name="bg-BG">Изключено</lang>
<lang name="bn-BD">বন্ধ</lang>
<lang name="bn-IN">বন্ধ</lang>
<lang name="bs-LATN-BA">Isključeno</lang>
<lang name="ca-ES">Inactiva</lang>
<lang name="ca-ES-VALENCIA">Inactiva</lang>
<lang name="chr-CHER-US">ᎠᏍᏚᏗ</lang>
<lang name="cs-CZ">Vypnuto</lang>
<lang name="cy-GB">Diffodd</lang>
<lang name="da-DK">Fra</lang>
<lang name="de-DE">Aus</lang>
<lang name="el-GR">Ανενεργό</lang>
<lang name="en-GB">Off</lang>
<lang name="es-ES">Desactivado</lang>
<lang name="et-EE">Väljas</lang>
<lang name="eu-ES">Desaktibatuta</lang>
<lang name="fa-IR">خاموش</lang>
<lang name="fi-FI">Ei käytössä</lang>
<lang name="fil-PH">Naka-off</lang>
<lang name="fr-FR">Inactif</lang>
<lang name="ga-IE">As</lang>
<lang name="gd-GB">Dheth</lang>
<lang name="gl-ES">Desactivado</lang>
<lang name="gu-IN">બંધ</lang>
<lang name="ha-LATN-NG">Kashe</lang>
<lang name="he-IL">לא פעיל</lang>
<lang name="hi-IN">बंद</lang>
<lang name="hr-HR">Isključeno</lang>
<lang name="hu-HU">Kikapcsolva</lang>
<lang name="hy-AM">Անջատ</lang>
<lang name="id-ID">Nonaktif</lang>
<lang name="ig-NG">Gbanyọ</lang>
<lang name="is-IS">Óvirkt</lang>
<lang name="it-IT">Disattivato</lang>
<lang name="iu-LATN-CA">Qaminngajuq</lang>
<lang name="ja-JP">オフ</lang>
<lang name="ka-GE">გამორთვა</lang>
<lang name="kk-KZ">Өшірілген</lang>
<lang name="km-KH">បិទ</lang>
<lang name="kn-IN">ಆಫ್</lang>
<lang name="ko-KR">해제</lang>
<lang name="kok-IN">ऑफ करचें</lang>
<lang name="ku-ARAB-IQ">کوژاوە</lang>
<lang name="ky-KG">Өчүрулгөн</lang>
<lang name="lb-LU">Aus</lang>
<lang name="lt-LT">Išjungta</lang>
<lang name="lv-LV">Izslēgts</lang>
<lang name="mi-NZ">Weto ana</lang>
<lang name="mk-MK">Исклучено</lang>
<lang name="ml-IN">ഓഫ്</lang>
<lang name="mn-MN">Idəvxgüĭ</lang>
<lang name="mr-IN">बंद</lang>
<lang name="ms-MY">Mati</lang>
<lang name="mt-MT">Mitfi</lang>
<lang name="nb-NO">Av</lang>
<lang name="ne-NP">निभाउनुहोस्</lang>
<lang name="nl-NL">Uit</lang>
<lang name="nn-NO">Av</lang>
<lang name="nso-ZA">Timilwe</lang>
<lang name="or-IN">ଅଫ୍</lang>
<lang name="pa-ARAB-PK">بند</lang>
<lang name="pa-IN">ਬੰਦ ਕਰੋ</lang>
<lang name="pl-PL">Wyłączone</lang>
<lang name="prs-AF">خاموش</lang>
<lang name="pt-BR">Desligado</lang>
<lang name="pt-PT">Desativado</lang>
<lang name="qps-PLOC">[3Hcgw][Ǿƒƒ ]</lang>
<lang name="qps-PLOCM">‏‏أبع[Off]לף</lang>
<lang name="qut-GT">Q'atetalik</lang>
<lang name="quz-PE">Tukuchisqa</lang>
<lang name="ro-RO">Dezactivat</lang>
<lang name="ru-RU">Откл.</lang>
<lang name="rw-RW">Irafunze</lang>
<lang name="sd-ARAB-PK">بند کوليو</lang>
<lang name="si-LK">අක්‍රීය</lang>
<lang name="sk-SK">Vypnuté</lang>
<lang name="sl-SI">Izklopljeno</lang>
<lang name="sq-AL">Joaktiv</lang>
<lang name="sr-CYRL-BA">Искључено</lang>
<lang name="sr-CYRL-CS">Искључено</lang>
<lang name="sr-LATN-CS">Isključeno</lang>
<lang name="sv-SE">Av</lang>
<lang name="sw-KE">Zima</lang>
<lang name="ta-IN">அணை</lang>
<lang name="te-IN">ఆఫ్ చేయి</lang>
<lang name="tg-CYRL-TJ">Хомӯш</lang>
<lang name="th-TH">ปิด</lang>
<lang name="ti-ET">ኣጥፍእ</lang>
<lang name="tk-TM">Öçürilen</lang>
<lang name="tn-ZA">Timilwe</lang>
<lang name="tr-TR">Kapalı</lang>
<lang name="tt-RU">Сүндерелгән</lang>
<lang name="ug-CN">يېپىق</lang>
<lang name="uk-UA">Вимк.</lang>
<lang name="ur-PK">آف</lang>
<lang name="uz-LATN-UZ">Och</lang>
<lang name="vi-VN">Tắt</lang>
<lang name="wo-SN">Fay</lang>
<lang name="xh-ZA">Cimile</lang>
<lang name="yo-NG">Pa</lang>
<lang name="zh-HK">關閉</lang>
<lang name="zh-TW">關閉</lang>
<lang name="zu-ZA">Cishile</lang>
</resource>
<resource id="ms-resource://Microsoft.WinJS.1.0/ui/on">
<lang name="zh-CN"></lang>
<lang name="en-US">On</lang>
<lang name="af-ZA">Aan</lang>
<lang name="am-ET">አብራ</lang>
<lang name="ar-SA">تشغيل</lang>
<lang name="as-IN">অন</lang>
<lang name="az-LATN-AZ">Aktiv</lang>
<lang name="be-BY">Укл.</lang>
<lang name="bg-BG">Включено</lang>
<lang name="bn-BD">চালু</lang>
<lang name="bn-IN">চালু</lang>
<lang name="bs-LATN-BA">Uključeno</lang>
<lang name="ca-ES">Activa</lang>
<lang name="ca-ES-VALENCIA">Activa</lang>
<lang name="chr-CHER-US">ᎠᏍᏚᎢᏍᏗ</lang>
<lang name="cs-CZ">Zapnuto</lang>
<lang name="cy-GB">Ar waith</lang>
<lang name="da-DK">Til</lang>
<lang name="de-DE">Ein</lang>
<lang name="el-GR">Ενεργό</lang>
<lang name="en-GB">On</lang>
<lang name="es-ES">Activado</lang>
<lang name="et-EE">Sees</lang>
<lang name="eu-ES">Aktibatuta</lang>
<lang name="fa-IR">روشن</lang>
<lang name="fi-FI">Käytössä</lang>
<lang name="fil-PH">Naka-on</lang>
<lang name="fr-FR">Actif</lang>
<lang name="ga-IE">Air</lang>
<lang name="gd-GB">Air</lang>
<lang name="gl-ES">Activado</lang>
<lang name="gu-IN">ચાલુ</lang>
<lang name="ha-LATN-NG">Kunna</lang>
<lang name="he-IL">פעיל</lang>
<lang name="hi-IN">चालू</lang>
<lang name="hr-HR">Uključeno</lang>
<lang name="hu-HU">Bekapcsolva</lang>
<lang name="hy-AM">Միաց</lang>
<lang name="id-ID">Aktif</lang>
<lang name="ig-NG">Gbanye</lang>
<lang name="is-IS">Virkt</lang>
<lang name="it-IT">Attivato</lang>
<lang name="iu-LATN-CA">Ikumajuq</lang>
<lang name="ja-JP">オン</lang>
<lang name="ka-GE">ჩართვა</lang>
<lang name="kk-KZ">Қосылған</lang>
<lang name="km-KH">បើក</lang>
<lang name="kn-IN">ಆನ್</lang>
<lang name="ko-KR">설정</lang>
<lang name="kok-IN">ऑन करचें</lang>
<lang name="ku-ARAB-IQ">هەڵکراو</lang>
<lang name="ky-KG">Күйгүзүлгөн</lang>
<lang name="lb-LU">Un</lang>
<lang name="lt-LT">Įjungta</lang>
<lang name="lv-LV">Ieslēgts</lang>
<lang name="mi-NZ">Kā ana</lang>
<lang name="mk-MK">Вклученo</lang>
<lang name="ml-IN">ഓൺ</lang>
<lang name="mn-MN">Идэвхтэй</lang>
<lang name="mr-IN">चालू</lang>
<lang name="ms-MY">Hidup</lang>
<lang name="mt-MT">Mixgħul</lang>
<lang name="nb-NO"></lang>
<lang name="ne-NP">खोल्नुहोस्</lang>
<lang name="nl-NL">Aan</lang>
<lang name="nn-NO"></lang>
<lang name="nso-ZA">Goteditšwe</lang>
<lang name="or-IN">ଅନ୍</lang>
<lang name="pa-ARAB-PK">چالُو</lang>
<lang name="pa-IN">ਚਾਲੂ ਕਰੋ</lang>
<lang name="pl-PL">Włączone</lang>
<lang name="prs-AF">روشن</lang>
<lang name="pt-BR">Ligado</lang>
<lang name="pt-PT">Ativado</lang>
<lang name="qps-PLOC">[Aj8Pp][Őņ ]</lang>
<lang name="qps-PLOCM">‏‏أبع[On]לף</lang>
<lang name="qut-GT">Tzijtalik</lang>
<lang name="quz-PE">Kawsarichisqa</lang>
<lang name="ro-RO">Activat</lang>
<lang name="ru-RU">Вкл.</lang>
<lang name="rw-RW">Irafunguye</lang>
<lang name="sd-ARAB-PK">شروع ڪريو</lang>
<lang name="si-LK">සක්‍රීය</lang>
<lang name="sk-SK">Zapnuté</lang>
<lang name="sl-SI">Vklopljeno</lang>
<lang name="sq-AL">Aktiv</lang>
<lang name="sr-CYRL-BA">Укључено</lang>
<lang name="sr-CYRL-CS">Укључено</lang>
<lang name="sr-LATN-CS">Uključeno</lang>
<lang name="sv-SE"></lang>
<lang name="sw-KE">Washa</lang>
<lang name="ta-IN">இயக்கு</lang>
<lang name="te-IN">ఆన్ చేయి</lang>
<lang name="tg-CYRL-TJ">Фаъол</lang>
<lang name="th-TH">เปิด</lang>
<lang name="ti-ET">ወልዕ</lang>
<lang name="tk-TM">Açyk</lang>
<lang name="tn-ZA">Tshubilwe</lang>
<lang name="tr-TR">ık</lang>
<lang name="tt-RU">Кабызылган</lang>
<lang name="ug-CN">ئوچۇق</lang>
<lang name="uk-UA">Увімк.</lang>
<lang name="ur-PK">آن</lang>
<lang name="uz-LATN-UZ">Yoq</lang>
<lang name="vi-VN">Bật</lang>
<lang name="wo-SN">Taal</lang>
<lang name="xh-ZA">Layitile</lang>
<lang name="yo-NG">Tàn</lang>
<lang name="zh-HK">開啟</lang>
<lang name="zh-TW">開啟</lang>
<lang name="zu-ZA">Vuliwe</lang>
</resource>
<resource id="license">
<lang name="zh-CN">license_cn.html</lang>
<lang name="en-US">license_en.html</lang>
</resource>
<resource id="MANAGER_APPTITLE">
<lang name="zh-CN">Package Manager</lang>
<lang name="en-US">Package Manager</lang>
</resource>
<resource id="MANAGER_MANAGE">
<lang name="zh-CN">管理</lang>
<lang name="en-US">Manage</lang>
</resource>
<resource id="MANAGER_APP_TITLE">
<lang name="zh-CN">应用</lang>
<lang name="en-US">Application</lang>
</resource>
<resource id="MANAGER_APP_DESCRIPTION">
<lang name="zh-CN">在这里,可以对安装的 Windows 商店应用进行管理。</lang>
<lang name="en-US">Here you can manage the installed Windows Store apps.</lang>
</resource>
<resource id="MANAGER_APP_INSTALLEDAPPS">
<lang name="zh-CN">安装的应用</lang>
<lang name="en-US">Installed Apps</lang>
</resource>
<resource id="MANAGER_APP_INSTALLEDAPPS_LOADING">
<lang name="zh-CN">正在加载应用...</lang>
<lang name="en-US">Loading apps...</lang>
</resource>
<resource id="MANAGER_APP_INSTALLEDAPPS_SUCCEED">
<lang name="zh-CN">已经加载了应用。</lang>
<lang name="en-US">Loaded apps.</lang>
</resource>
<resource id="MANAGER_APP_INSTALLEDAPPS_FAILED">
<lang name="zh-CN">加载时发生错误: {0}</lang>
<lang name="en-US">Error loading apps: {0}</lang>
</resource>
<resource id="MANAGER_APP_REFRESH">
<lang name="zh-CN">刷新</lang>
<lang name="en-US">Refresh</lang>
</resource>
<resource id="MANAGER_APP_ADVANCEOPTIONS">
<lang name="zh-CN">高级选项</lang>
<lang name="en-US">Advanced Options</lang>
</resource>
<resource id="MANAGER_APP_UNINSTALL">
<lang name="zh-CN">卸载</lang>
<lang name="en-US">Uninstall</lang>
</resource>
<resource id="MANAGER_APP_LAUNCH">
<lang name="zh-CN">启动</lang>
<lang name="en-US">Launch</lang>
</resource>
<resource id="MANAGER_APP_CREATESHORTCUT">
<lang name="zh-CN">创建桌面快捷方式</lang>
<lang name="en-US">创建桌面快捷方式</lang>
</resource>
<resource id="MANAGER_MANAGE_FINDAPPS">
<lang name="zh-CN">找到 {0} 个应用</lang>
<lang name="en-US">Found {0} apps.</lang>
</resource>
<resource id="MANAGER_MANAGE_LISTEMPTY">
<lang name="zh-CN">还没有内容...</lang>
<lang name="en-US">No content...</lang>
</resource>
<resource id="MANAGER_MANAGE_SEARCHPLACEHOLDER">
<lang name="zh-CN">搜索此列表</lang>
<lang name="en-US">Search this list</lang>
</resource>
<resource id="MANAGER_APP_SHOWSYSTEMAPP">
<lang name="zh-CN">显示系统应用</lang>
<lang name="en-US">Show system apps</lang>
</resource>
<resource id="MANAGER_APP_SHOWFRAMEWORK">
<lang name="zh-CN">显示依赖项</lang>
<lang name="en-US">Show dependencies</lang>
</resource>
<resource id="MANAGER_APP_IDENTITY">
<lang name="zh-CN">标识</lang>
<lang name="en-US">Identity</lang>
</resource>
<resource id="MANAGER_APP_IDENTITY_NAME">
<lang name="zh-CN">名称</lang>
<lang name="en-US">Name</lang>
</resource>
<resource id="MANAGER_APP_IDENTITY_PUBLISHER">
<lang name="zh-CN">发布者</lang>
<lang name="en-US">Publisher</lang>
</resource>
<resource id="MANAGER_APP_IDENTITY_PUBLISHERID">
<lang name="zh-CN">发布者 ID</lang>
<lang name="en-US">Publisher ID</lang>
</resource>
<resource id="MANAGER_APP_IDENTITY_FAMILYNAME">
<lang name="zh-CN">系列名</lang>
<lang name="en-US">Family Name</lang>
</resource>
<resource id="MANAGER_APP_IDENTITY_FULLNAME">
<lang name="zh-CN">全名</lang>
<lang name="en-US">Full Name</lang>
</resource>
<resource id="MANAGER_APP_IDENTITY_ARCHITECTURE">
<lang name="zh-CN">支持的处理器架构</lang>
<lang name="en-US">Supported processor architectures</lang>
</resource>
<resource id="MANAGER_APP_HASAPPS">
<lang name="zh-CN">具有的应用</lang>
<lang name="en-US">Has Apps</lang>
</resource>
<resource id="MANAGER_APP_HASAPPS_DESC">
<lang name="zh-CN">下面是包具有的应用。现在可以直接在这里启动程序,或者创建桌面快捷方式。</lang>
<lang name="en-US">Below are the apps that are included in this package. You can launch the apps directly from here, or create desktop shortcuts.</lang>
</resource>
<resource id="MANAGER_APP_UNINSTALL_DESC">
<lang name="zh-CN">卸载此应用及其设置。</lang>
<lang name="en-US">Uninstall this app and its settings.</lang>
</resource>
<resource id="MANAGER_APP_UNINSTALL_DESC">
<lang name="zh-CN">将从这台电脑中卸载此应用及其相关信息。</lang>
<lang name="en-US">This app and its related information will be uninstalled from this computer.</lang>
</resource>
<resource id="MANAGER_APP_UNINSTALL_ING">
<lang name="zh-CN">正在卸载...</lang>
<lang name="en-US">Uninstalling...</lang>
</resource>
<resource id="MANAGER_APP_UNINSTALL_PROGRESSING">
<lang name="zh-CN">正在卸载... {0}%</lang>
<lang name="en-US">Uninstalling... {0}%</lang>
</resource>
<resource id="MANAGER_APP_UNINSTALL_SUCCEED">
<lang name="zh-CN">已成功卸载。</lang>
<lang name="en-US">Uninstall succeeded.</lang>
</resource>
</resources>