mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
Update manager and add features for App Installer.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
90
Launch/Launch.csproj
Normal 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
68
Launch/Program.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Launch/Properties/AssemblyInfo.cs
Normal file
36
Launch/Properties/AssemblyInfo.cs
Normal 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
71
Launch/Properties/Resources.Designer.cs
generated
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
Launch/Properties/Resources.resx
Normal file
117
Launch/Properties/Resources.resx
Normal 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
30
Launch/Properties/Settings.Designer.cs
generated
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Launch/Properties/Settings.settings
Normal file
7
Launch/Properties/Settings.settings
Normal 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
75
Launch/app.manifest
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Manager
|
||||
[STAThread]
|
||||
static void Main ()
|
||||
{
|
||||
AppxPackage.PackageReader.AddApplicationItem ("SmallLogo");
|
||||
DataUtils.BrowserEmulation.SetWebBrowserEmulation ();
|
||||
Application.EnableVisualStyles ();
|
||||
Application.SetCompatibleTextRenderingDefault (false);
|
||||
|
||||
11
Manager/ShortcutCreateForm.cs
Normal file
11
Manager/ShortcutCreateForm.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Manager
|
||||
{
|
||||
class ShortcutCreateForm
|
||||
{
|
||||
}
|
||||
}
|
||||
BIN
PriFormat.zip
BIN
PriFormat.zip
Binary file not shown.
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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;
|
||||
|
||||
29
shared/html/css/statusbar.css
Normal file
29
shared/html/css/statusbar.css
Normal 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);
|
||||
}
|
||||
@@ -312,9 +312,15 @@
|
||||
function hideTouchHide() {
|
||||
touchHide.style.display = "none";
|
||||
}
|
||||
var timerHide = null;
|
||||
this.show = function() {
|
||||
try {
|
||||
if (!_enable) return;
|
||||
if (timerHide) {
|
||||
clearTimeout(timerHide);
|
||||
timerHide = null;
|
||||
}
|
||||
this.element.style.display = "";
|
||||
if (!this.element.classList.contains("show"))
|
||||
this.element.classList.add("show");
|
||||
waitTimer(500);
|
||||
@@ -323,8 +329,16 @@
|
||||
};
|
||||
this.hide = function() {
|
||||
try {
|
||||
if (timerHide) {
|
||||
clearTimeout(timerHide);
|
||||
timerHide = null;
|
||||
}
|
||||
if (this.element.classList.contains("show"))
|
||||
this.element.classList.remove("show");
|
||||
timerHide = setTimeout(function() {
|
||||
timerHide = null;
|
||||
self.element.style.display = "none";
|
||||
}, 500);
|
||||
waitTimer(500);
|
||||
hideTouchHide();
|
||||
} catch (e) {}
|
||||
|
||||
@@ -102,4 +102,20 @@
|
||||
get: function() { return ext.System.UI.SplashImage; },
|
||||
});
|
||||
} catch (e) {}
|
||||
// 下面是有关 String 方法的补充
|
||||
if (typeof String.prototype.trim !== "function") {
|
||||
String.prototype.trim = function() {
|
||||
return Bridge.String.trim(this);
|
||||
};
|
||||
}
|
||||
if (typeof String.prototype.toLowerCase !== "function") {
|
||||
String.prototype.toLowerCase = function() {
|
||||
return Bridge.String.tolower(this);
|
||||
};
|
||||
}
|
||||
if (typeof String.prototype.toUpperCase !== "function") {
|
||||
String.prototype.toUpperCase = function() {
|
||||
return Bridge.String.toupper(this);
|
||||
};
|
||||
}
|
||||
})(this);
|
||||
@@ -13,6 +13,7 @@
|
||||
var childAnimeDuration = 120;
|
||||
var parentAnimeDuration = 400;
|
||||
|
||||
|
||||
function showItemAmine(node) {
|
||||
return Windows.UI.Animation.runAsync(node, [
|
||||
Windows.UI.Animation.Keyframes.Scale.up,
|
||||
@@ -27,6 +28,23 @@
|
||||
], childAnimeDuration);
|
||||
}
|
||||
|
||||
function noAnime(node) {
|
||||
return Promise.resolve(node);
|
||||
}
|
||||
|
||||
function runShowAnime(node, enable) {
|
||||
if (enable === void 0) enable = true;
|
||||
if (!enable) return noAnime(node);
|
||||
return showItemAmine(node);
|
||||
}
|
||||
|
||||
function runHideAnime(node, enable) {
|
||||
if (enable === void 0) enable = true;
|
||||
if (!enable) return noAnime(node);
|
||||
return hideItemAmine(node);
|
||||
}
|
||||
|
||||
|
||||
function updateItemAmine(node, updateCallback) {
|
||||
return Windows.UI.Animation.runAsync(node, [
|
||||
Windows.UI.Animation.Keyframes.Opacity.hidden,
|
||||
@@ -53,6 +71,43 @@
|
||||
function PMDataSource() {
|
||||
var _list = [];
|
||||
var _listeners = [];
|
||||
|
||||
var _keySelector = null;
|
||||
var _autoKeySeed = 1;
|
||||
this.setKeySelector = function(fn) {
|
||||
_keySelector = (typeof fn === "function") ? fn : null;
|
||||
};
|
||||
|
||||
function getKey(item) {
|
||||
if (!item) return null;
|
||||
|
||||
// 用户提供
|
||||
if (_keySelector) {
|
||||
return _keySelector(item);
|
||||
}
|
||||
|
||||
// 自动注入(对象)
|
||||
if (typeof item === "object") {
|
||||
if (item.__pm_key !== void 0) {
|
||||
return item.__pm_key;
|
||||
}
|
||||
|
||||
try {
|
||||
Object.defineProperty(item, "__pm_key", {
|
||||
value: "pm_" + (_autoKeySeed++),
|
||||
enumerable: false
|
||||
});
|
||||
} catch (e) {
|
||||
// IE10 兜底
|
||||
item.__pm_key = "pm_" + (_autoKeySeed++);
|
||||
}
|
||||
return item.__pm_key;
|
||||
}
|
||||
|
||||
// 原始类型兜底
|
||||
return typeof item + ":" + item;
|
||||
}
|
||||
|
||||
this.subscribe = function(fn) {
|
||||
if (typeof fn === "function") {
|
||||
_listeners.push(fn);
|
||||
@@ -64,26 +119,47 @@
|
||||
_listeners[i](evt);
|
||||
}
|
||||
}
|
||||
this.indexOf = function(item) {
|
||||
var key = getKey(item);
|
||||
for (var i = 0; i < _list.length; i++) {
|
||||
if (getKey(_list[i]) === key) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
this.add = function(item) {
|
||||
_list.push(item);
|
||||
emit(new PMChangeEvent(
|
||||
DataView.ChangeType.add, [item], { index: _list.length - 1 }
|
||||
DataView.ChangeType.add, [{ item: item, index: _list.length - 1, key: getKey(item) }]
|
||||
));
|
||||
};
|
||||
this.removeAt = function(index) {
|
||||
if (index < 0 || index >= _list.length) return;
|
||||
var item = _list.splice(index, 1)[0];
|
||||
emit(new PMChangeEvent(
|
||||
DataView.ChangeType.remove, [item], { index: index }
|
||||
DataView.ChangeType.remove, [{ item: item, index: index, key: getKey(item) }]
|
||||
));
|
||||
};
|
||||
this.remove = function(item) {
|
||||
var index = this.indexOf(item);
|
||||
if (index >= 0) {
|
||||
this.removeAt(index);
|
||||
}
|
||||
};
|
||||
this.changeAt = function(index, newItem) {
|
||||
if (index < 0 || index >= _list.length) return;
|
||||
_list[index] = newItem;
|
||||
emit(new PMChangeEvent(
|
||||
DataView.ChangeType.change, [newItem], { index: index }
|
||||
DataView.ChangeType.change, [{ item: newItem, index: index, key: getKey(newItem) }]
|
||||
));
|
||||
};
|
||||
this.change = function(oldItem, newItem) {
|
||||
var index = this.indexOf(oldItem);
|
||||
if (index >= 0) {
|
||||
this.changeAt(index, newItem);
|
||||
}
|
||||
};
|
||||
this.clear = function() {
|
||||
_list.length = 0;
|
||||
emit(new PMChangeEvent(
|
||||
@@ -224,7 +300,6 @@
|
||||
var changed = [];
|
||||
var removed = [];
|
||||
|
||||
// 1️⃣ 找 remove
|
||||
for (i = oldList.length - 1; i >= 0; i--) {
|
||||
var oldItem = oldList[i];
|
||||
var oldKey = getKey(oldItem);
|
||||
@@ -238,7 +313,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 2️⃣ 找 add / change
|
||||
for (i = 0; i < newList.length; i++) {
|
||||
var newItem = newList[i];
|
||||
var newKey = getKey(newItem);
|
||||
@@ -263,7 +337,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 3️⃣ 执行 remove(从后往前)
|
||||
if (removed.length > 0) {
|
||||
for (i = 0; i < removed.length; i++) {
|
||||
_list.splice(removed[i].index, 1);
|
||||
@@ -274,7 +347,6 @@
|
||||
));
|
||||
}
|
||||
|
||||
// 4️⃣ 执行 add / change(重建顺序)
|
||||
_list = newList.slice(0);
|
||||
|
||||
if (added.length > 0) {
|
||||
@@ -291,25 +363,50 @@
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
this._getKey = getKey;
|
||||
}
|
||||
var MAX_ANIMATE_COUNT = 100;
|
||||
|
||||
function PMDataListView(container, templateFn) {
|
||||
this.container = container;
|
||||
this.templateFn = templateFn;
|
||||
this.listViewControl = this;
|
||||
this._emptyView = null;
|
||||
// === 新增 ===
|
||||
this._filter = null;
|
||||
|
||||
this._searchHandler = null;
|
||||
this._searchText = null;
|
||||
this._searchSuggestProvider = null;
|
||||
|
||||
this.onSearchSuggest = null; // function(text, list)
|
||||
this._isSearching = false;
|
||||
this.onsearchstart = null;
|
||||
this.onsearchend = null;
|
||||
}
|
||||
PMDataListView.prototype.bind = function(ds) {
|
||||
var self = this;
|
||||
var items = ds.get();
|
||||
this._ds = ds;
|
||||
|
||||
self.container.innerHTML = "";
|
||||
|
||||
var items = ds.get();
|
||||
|
||||
// 动画队列,保证异步操作不会乱序
|
||||
var queue = Promise.resolve();
|
||||
|
||||
function renderItem(data, index) {
|
||||
var el = self.templateFn(data, index);
|
||||
|
||||
var key = ds && ds._getKey ? ds._getKey(data) : null;
|
||||
|
||||
el.__pm_item = data;
|
||||
el.__pm_key = key;
|
||||
|
||||
if (key != null) {
|
||||
el.setAttribute("data-pm-key", key);
|
||||
}
|
||||
|
||||
el.addEventListener("click", function() {
|
||||
self._toggleSelect(el);
|
||||
});
|
||||
@@ -317,10 +414,13 @@
|
||||
return el;
|
||||
}
|
||||
|
||||
|
||||
// 初始化渲染
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
self.container.appendChild(renderItem(items[i], i));
|
||||
}
|
||||
// 初始化 emptyView 状态
|
||||
self._updateEmptyView();
|
||||
|
||||
ds.subscribe(function(evt) {
|
||||
|
||||
@@ -337,37 +437,58 @@
|
||||
var nodes = [];
|
||||
for (var i = 0; i < datas.length; i++) {
|
||||
var n = renderItem(datas[i].item, datas[i].index);
|
||||
n.style.display = "none";
|
||||
nodes.push(n);
|
||||
self.container.appendChild(n);
|
||||
}
|
||||
|
||||
// 如果数量>=20,动画并行,否则串行
|
||||
if (datas.length >= 20) {
|
||||
var enableAnime = datas.length <= MAX_ANIMATE_COUNT;
|
||||
if (!enableAnime) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
// 如果数量>=20,动画串行,否则并行
|
||||
if (datas.length <= 20) {
|
||||
var promises = [];
|
||||
for (var j = 0; j < nodes.length; j++) {
|
||||
promises.push(showItemAmine(nodes[j]));
|
||||
promises.push((function(node) {
|
||||
node.style.display = "";
|
||||
return showItemAmine(node);
|
||||
})(nodes[j]));
|
||||
}
|
||||
return Promise.all(promises);
|
||||
} else {
|
||||
// 串行
|
||||
var p = Promise.resolve();
|
||||
var group = [];
|
||||
for (var k = 0; k < nodes.length; k++) {
|
||||
(function(node) {
|
||||
p = p.then(function() {
|
||||
group.push((function(node) {
|
||||
node.style.display = "";
|
||||
return showItemAmine(node);
|
||||
});
|
||||
})(nodes[k]);
|
||||
})
|
||||
(nodes[k]));
|
||||
if (group.length === 20 || k === nodes.length - 1) {
|
||||
(function(g) {
|
||||
p = p.then(function() {
|
||||
return Promise.join(g);
|
||||
});
|
||||
})(group);
|
||||
group = [];
|
||||
}
|
||||
}
|
||||
(function(g) {
|
||||
p = p.then(function() {
|
||||
return Promise.join(g);
|
||||
});
|
||||
})(group);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
case DataView.ChangeType.remove:
|
||||
{
|
||||
var node = self.container.children[evt.detail.index];
|
||||
var info = evt.datas[0];
|
||||
var node = self._findNodeByKey(info.key);
|
||||
if (!node) return;
|
||||
|
||||
// 隐藏动画完成后再移除
|
||||
return hideItemAmine(node).then(function() {
|
||||
self.container.removeChild(node);
|
||||
});
|
||||
@@ -375,29 +496,30 @@
|
||||
|
||||
case DataView.ChangeType.change:
|
||||
{
|
||||
var oldNode = self.container.children[evt.detail.index];
|
||||
var info = evt.datas[0];
|
||||
var oldNode = self._findNodeByKey(info.key);
|
||||
if (!oldNode) return;
|
||||
|
||||
// 先淡出旧节点
|
||||
return hideItemAmine(oldNode).then(function() {
|
||||
// 替换节点
|
||||
var newNode = renderItem(evt.datas[0], evt.detail.index);
|
||||
var newNode = renderItem(info.item);
|
||||
self.container.replaceChild(newNode, oldNode);
|
||||
|
||||
// 再淡入新节点
|
||||
return showItemAmine(newNode);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
case DataView.ChangeType.clear:
|
||||
self.container.innerHTML = "";
|
||||
return Promise.resolve();
|
||||
|
||||
case DataView.ChangeType.move:
|
||||
{
|
||||
var node = self.container.children[evt.detail.from];
|
||||
var info = evt.datas[0];
|
||||
var node = self._findNodeByKey(info.key);
|
||||
if (!node) return;
|
||||
|
||||
var ref = self.container.children[evt.detail.to] || null;
|
||||
if (node) self.container.insertBefore(node, ref);
|
||||
self.container.insertBefore(node, ref);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@@ -410,9 +532,22 @@
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
promises.push(self._refreshVisibility());
|
||||
return Promise.join(promises);
|
||||
});
|
||||
});
|
||||
};
|
||||
PMDataListView.prototype._findNodeByKey = function(key) {
|
||||
if (key == null) return null;
|
||||
|
||||
var children = this.container.children;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
if (children[i].__pm_key === key) {
|
||||
return children[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
PMDataListView.prototype._toggleSelect = function(ele) {
|
||||
// 如果选择模式为 none,则不处理
|
||||
@@ -472,7 +607,202 @@
|
||||
return Array.prototype.slice.call(this.container.querySelectorAll(".selected"));
|
||||
}
|
||||
});
|
||||
PMDataListView.prototype._updateEmptyView = function() {
|
||||
if (!this._emptyView) return;
|
||||
|
||||
// container 中是否还有 item
|
||||
var hasItem = this.container.children.length > 0;
|
||||
|
||||
if (hasItem) {
|
||||
if (this._emptyView.parentNode) {
|
||||
this._emptyView.style.display = "none";
|
||||
}
|
||||
} else {
|
||||
if (!this._emptyView.parentNode) {
|
||||
this.container.appendChild(this._emptyView);
|
||||
}
|
||||
this._emptyView.style.display = "";
|
||||
}
|
||||
};
|
||||
Object.defineProperty(PMDataListView.prototype, "emptyView", {
|
||||
get: function() {
|
||||
return this._emptyView;
|
||||
},
|
||||
set: function(value) {
|
||||
// 只接受 HTMLElement 或 null / undefined
|
||||
if (value !== null && value !== void 0 && !(value instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 移除旧的
|
||||
if (this._emptyView && this._emptyView.parentNode) {
|
||||
this._emptyView.parentNode.removeChild(this._emptyView);
|
||||
}
|
||||
|
||||
this._emptyView = value || null;
|
||||
|
||||
// 设置后立刻刷新一次
|
||||
this._updateEmptyView();
|
||||
}
|
||||
});
|
||||
PMDataListView.prototype._isItemVisible = function(item) {
|
||||
// 1️⃣ filter
|
||||
if (this._filter) {
|
||||
if (!this._filter(item)) return false;
|
||||
}
|
||||
|
||||
// 2️⃣ search(自动启用 / 禁用)
|
||||
var handler = this._searchHandler;
|
||||
var text = this._searchText;
|
||||
|
||||
if (typeof handler === "function") {
|
||||
if (text != null) {
|
||||
text = ("" + text).replace(/^\s+|\s+$/g, "");
|
||||
}
|
||||
|
||||
if (text && text.length > 0) {
|
||||
if (!handler(text, item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
PMDataListView.prototype._refreshVisibility = function() {
|
||||
var self = this;
|
||||
var children = self.container.children;
|
||||
var animes = [];
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
(function(node) {
|
||||
var item = node.__pm_item;
|
||||
if (!item) return;
|
||||
|
||||
var visible = self._isItemVisible(item);
|
||||
|
||||
var enableAnime = animes.length < MAX_ANIMATE_COUNT;
|
||||
if (visible) {
|
||||
if (node.style.display === "none") {
|
||||
node.style.display = "";
|
||||
animes.push(runShowAnime(node, enableAnime));
|
||||
}
|
||||
} else {
|
||||
if (node.style.display !== "none") {
|
||||
// 移除选择状态
|
||||
node.classList.remove("selected");
|
||||
animes.push(runHideAnime(node, enableAnime).then(function() {
|
||||
node.style.display = "none";
|
||||
}));
|
||||
}
|
||||
}
|
||||
})(children[i]);
|
||||
}
|
||||
return Promise.join(animes);
|
||||
};
|
||||
Object.defineProperty(PMDataListView.prototype, "filter", {
|
||||
get: function() {
|
||||
return this._filter;
|
||||
},
|
||||
set: function(fn) {
|
||||
this._filter = (typeof fn === "function") ? fn : null;
|
||||
this._refreshVisibility();
|
||||
}
|
||||
});
|
||||
Object.defineProperty(PMDataListView.prototype, "searchHandler", {
|
||||
get: function() {
|
||||
return this._searchHandler;
|
||||
},
|
||||
set: function(fn) {
|
||||
this._searchHandler = (typeof fn === "function") ? fn : null;
|
||||
this._refreshVisibility();
|
||||
}
|
||||
});
|
||||
Object.defineProperty(PMDataListView.prototype, "searchText", {
|
||||
get: function() {
|
||||
return this._searchText;
|
||||
},
|
||||
set: function(text) {
|
||||
var oldText = this._searchText;
|
||||
|
||||
this._searchText = text;
|
||||
|
||||
var oldActive = !!(oldText && oldText.trim());
|
||||
var newActive = !!(text && ("" + text).trim());
|
||||
|
||||
//if (!oldActive && newActive) {
|
||||
this._isSearching = true;
|
||||
this._emitSearchEvent("searchstart");
|
||||
//}
|
||||
|
||||
var handler = this._searchHandler;
|
||||
var provider = this._searchSuggestProvider;
|
||||
var cb = this.onSearchSuggest;
|
||||
|
||||
var t = text;
|
||||
if (t != null) {
|
||||
t = ("" + t).replace(/^\s+|\s+$/g, "");
|
||||
}
|
||||
|
||||
// 搜索建议
|
||||
if (
|
||||
typeof handler === "function" &&
|
||||
t &&
|
||||
t.length > 0 &&
|
||||
typeof provider === "function" &&
|
||||
typeof cb === "function"
|
||||
) {
|
||||
var list = provider(t);
|
||||
if (list && list.length) {
|
||||
cb(t, list.slice(0, 10));
|
||||
}
|
||||
}
|
||||
var self = this;
|
||||
var func = function() {
|
||||
//if (oldActive && !newActive) {
|
||||
self._isSearching = false;
|
||||
self._emitSearchEvent("searchend");
|
||||
//}
|
||||
};
|
||||
this._refreshVisibility().done(func, func);
|
||||
}
|
||||
});
|
||||
Object.defineProperty(PMDataListView.prototype, "searchSuggestProvider", {
|
||||
get: function() {
|
||||
return this._searchSuggestProvider;
|
||||
},
|
||||
set: function(fn) {
|
||||
this._searchSuggestProvider = (typeof fn === "function") ? fn : null;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(PMDataListView.prototype, "findItemLength", {
|
||||
get: function() {
|
||||
var count = 0;
|
||||
var children = this.container.children;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var item = children[i].__pm_item;
|
||||
if (this._isItemVisible(item)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
});
|
||||
PMDataListView.prototype._emitSearchEvent = function(type) {
|
||||
if (typeof this["on" + type] === "function") {
|
||||
try {
|
||||
this["on" + type].call(this);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
try {
|
||||
var ev = document.createEvent("Event");
|
||||
ev.initEvent(type, true, true);
|
||||
this.container.dispatchEvent(ev);
|
||||
} catch (e) {}
|
||||
};
|
||||
PMDataListView.prototype.refresh = function() {
|
||||
this._refreshVisibility();
|
||||
};
|
||||
global.DataView.ChangeEvent = PMChangeEvent;
|
||||
global.DataView.DataSource = PMDataSource;
|
||||
global.DataView.ListView = PMDataListView;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(function(global) {
|
||||
"use strict";
|
||||
var pkg_ns = external.Package;
|
||||
var strres = external.StringResources;
|
||||
|
||||
function archsToStr(archs) {
|
||||
var arr = [];
|
||||
@@ -28,9 +29,23 @@
|
||||
}
|
||||
return arr.join(", ");
|
||||
}
|
||||
var showAppDetailTimer = null;
|
||||
|
||||
function updateAppDataSource(page, result, bar) {
|
||||
try {
|
||||
var json = result.json;
|
||||
console.log(json);
|
||||
page.appDataSource.updateList(json.applications);
|
||||
} catch (e) {}
|
||||
showAppDetailTimer = setTimeout(function() {
|
||||
showAppDetailTimer = null;
|
||||
bar.hide();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
function setAppInfoPageContent(info) {
|
||||
var page = document.getElementById("page-appinfo");
|
||||
page.data = info;
|
||||
page.querySelector(".display-name").textContent = info.Properties.DisplayName;
|
||||
page.querySelector(".publisher-display-name").textContent = info.Properties.Publisher;
|
||||
page.querySelector(".version").textContent = info.Identity.Version.Expression;
|
||||
@@ -42,9 +57,72 @@
|
||||
page.querySelector(".identity .full-name").textContent = info.Identity.FullName;
|
||||
page.querySelector(".identity .architecture").textContent = archsToStr(info.Identity.ProcessArchitecture);
|
||||
var il = info.InstallLocation;
|
||||
var pkg = pkg_ns.fromInstallLocation(il);
|
||||
var json = pkg.jsonText;
|
||||
console.log(JSON.parse(json));
|
||||
try { page.appDataSource.clear(); } catch (e) {}
|
||||
var appLoading = page.querySelector("#appinfo-loading");
|
||||
appLoading.classList.remove("noloading");
|
||||
if (showAppDetailTimer) clearTimeout(showAppDetailTimer);
|
||||
if (typeof appLoading.bar === "undefined") {
|
||||
appLoading.bar = new TransitionPanel(appLoading, {
|
||||
axis: 'y',
|
||||
duration: 500,
|
||||
});
|
||||
}
|
||||
appLoading.bar.show();
|
||||
var appLoadingStatus = page.querySelector(".title");
|
||||
appLoadingStatus.textContent = strres.get("MANAGER_APP_INSTALLEDAPPS_LOADING");
|
||||
return Package.reader.readFromInstallLocation(il, true).then(
|
||||
function(result) {
|
||||
try {
|
||||
var displayNameNode = page.querySelector(".display-name");
|
||||
displayNameNode.textContent = displayNameNode.textContent || result.json.properties.display_name;
|
||||
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
|
||||
displayNameNode.textContent = "";
|
||||
}
|
||||
if (result.json.applications.length === 1) {
|
||||
displayNameNode.textContent = displayNameNode.textContent || result.json.applications[0].DisplayName || result.json.applications[0].ShortName;
|
||||
}
|
||||
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
|
||||
displayNameNode.textContent = "";
|
||||
}
|
||||
if (result.json.applications.length === 1) {
|
||||
displayNameNode.textContent = displayNameNode.textContent || result.json.applications[0].ShortName;
|
||||
}
|
||||
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
|
||||
displayNameNode.textContent = "";
|
||||
}
|
||||
displayNameNode.textContent = displayNameNode.textContent || info.Identity.FamilyName;
|
||||
} catch (e) {}
|
||||
appLoadingStatus.textContent = strres.get("MANAGER_APP_INSTALLEDAPPS_SUCCEED");
|
||||
appLoading.classList.add("noloading");
|
||||
updateAppDataSource(page, result, appLoading.bar);
|
||||
},
|
||||
function(result) {
|
||||
try {
|
||||
var displayNameNode = page.querySelector(".display-name");
|
||||
displayNameNode.textContent = displayNameNode.textContent || result.json.properties.display_name;
|
||||
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
|
||||
displayNameNode.textContent = "";
|
||||
}
|
||||
if (result.json.applications.length === 1) {
|
||||
displayNameNode.textContent = displayNameNode.textContent || result.json.applications[0].DisplayName || result.json.applications[0].ShortName;
|
||||
}
|
||||
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
|
||||
displayNameNode.textContent = "";
|
||||
}
|
||||
if (result.json.applications.length === 1) {
|
||||
displayNameNode.textContent = displayNameNode.textContent || result.json.applications[0].ShortName;
|
||||
}
|
||||
if ((displayNameNode.textContent || "").indexOf("ms-resource:") === 0) {
|
||||
displayNameNode.textContent = "";
|
||||
}
|
||||
displayNameNode.textContent = displayNameNode.textContent || info.Identity.FamilyName;
|
||||
} catch (e) {}
|
||||
var msg = result.message;
|
||||
appLoadingStatus.textContent = external.String.format(strres.get("MANAGER_APP_INSTALLEDAPPS_FAILED"), msg);
|
||||
appLoading.classList.add("noloading");
|
||||
updateAppDataSource(page, result, appLoading.bar);
|
||||
}
|
||||
);
|
||||
}
|
||||
global.setAppInfoPageContent = setAppInfoPageContent;
|
||||
})(this);
|
||||
@@ -1,369 +1,5 @@
|
||||
(function(global) {
|
||||
function _createImage(src, onload, onerror) {
|
||||
var img = new Image();
|
||||
|
||||
img.onload = function() {
|
||||
onload(img);
|
||||
};
|
||||
|
||||
img.onerror = function() {
|
||||
onerror && onerror();
|
||||
};
|
||||
|
||||
img.src = src;
|
||||
}
|
||||
|
||||
function getSolidOpaqueBackgroundColor(source, callback) {
|
||||
|
||||
function processImage(img) {
|
||||
if (!img || !img.complete) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
var canvas = document.createElement("canvas");
|
||||
var ctx = canvas.getContext("2d");
|
||||
|
||||
canvas.width = img.naturalWidth || img.width;
|
||||
canvas.height = img.naturalHeight || img.height;
|
||||
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
try {
|
||||
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
} catch (e) {
|
||||
// 跨域导致的安全异常
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
var data = imageData.data;
|
||||
var w = canvas.width;
|
||||
var h = canvas.height;
|
||||
|
||||
var colors = {};
|
||||
var total = 0;
|
||||
|
||||
function pushColor(r, g, b, a) {
|
||||
if (a !== 255) return;
|
||||
var key = r + "," + g + "," + b;
|
||||
colors[key] = (colors[key] || 0) + 1;
|
||||
total++;
|
||||
}
|
||||
|
||||
// top + bottom
|
||||
for (var x = 0; x < w; x++) {
|
||||
var topIndex = (0 * w + x) * 4;
|
||||
var botIndex = ((h - 1) * w + x) * 4;
|
||||
pushColor(data[topIndex], data[topIndex + 1], data[topIndex + 2], data[topIndex + 3]);
|
||||
pushColor(data[botIndex], data[botIndex + 1], data[botIndex + 2], data[botIndex + 3]);
|
||||
}
|
||||
|
||||
// left + right
|
||||
for (var y = 1; y < h - 1; y++) {
|
||||
var leftIndex = (y * w + 0) * 4;
|
||||
var rightIndex = (y * w + (w - 1)) * 4;
|
||||
pushColor(data[leftIndex], data[leftIndex + 1], data[leftIndex + 2], data[leftIndex + 3]);
|
||||
pushColor(data[rightIndex], data[rightIndex + 1], data[rightIndex + 2], data[rightIndex + 3]);
|
||||
}
|
||||
|
||||
if (total === 0) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
var bestKey = null;
|
||||
var bestCount = 0;
|
||||
|
||||
for (var key in colors) {
|
||||
if (colors.hasOwnProperty(key)) {
|
||||
if (colors[key] > bestCount) {
|
||||
bestCount = colors[key];
|
||||
bestKey = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 95% 纯色阈值
|
||||
if (bestCount / total < 0.95) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(bestKey);
|
||||
}
|
||||
|
||||
// 如果传入的是 img 元素
|
||||
if (source && source.tagName && source.tagName.toLowerCase() === "img") {
|
||||
processImage(source);
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果传入的是 data url 或普通 url
|
||||
if (typeof source === "string") {
|
||||
_createImage(source, processImage, function() {
|
||||
callback(null);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null);
|
||||
}
|
||||
|
||||
function getHamonyColor(source, callback) {
|
||||
|
||||
function _createImage(src, onload, onerror) {
|
||||
var img = new Image();
|
||||
img.onload = function() { onload(img); };
|
||||
img.onerror = function() { onerror && onerror(); };
|
||||
img.src = src;
|
||||
}
|
||||
|
||||
function _toKey(r, g, b) {
|
||||
return r + "," + g + "," + b;
|
||||
}
|
||||
|
||||
function _rgbToHsl(r, g, b) {
|
||||
r /= 255;
|
||||
g /= 255;
|
||||
b /= 255;
|
||||
var max = Math.max(r, g, b);
|
||||
var min = Math.min(r, g, b);
|
||||
var h, s, l = (max + min) / 2;
|
||||
|
||||
if (max === min) {
|
||||
h = s = 0;
|
||||
} else {
|
||||
var d = max - min;
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
switch (max) {
|
||||
case r:
|
||||
h = (g - b) / d + (g < b ? 6 : 0);
|
||||
break;
|
||||
case g:
|
||||
h = (b - r) / d + 2;
|
||||
break;
|
||||
case b:
|
||||
h = (r - g) / d + 4;
|
||||
break;
|
||||
}
|
||||
h /= 6;
|
||||
}
|
||||
return { h: h, s: s, l: l };
|
||||
}
|
||||
|
||||
function _hslToRgb(h, s, l) {
|
||||
var r, g, b;
|
||||
|
||||
function hue2rgb(p, q, t) {
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2) return q;
|
||||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||
return p;
|
||||
}
|
||||
|
||||
if (s === 0) {
|
||||
r = g = b = l;
|
||||
} else {
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
var p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1 / 3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1 / 3);
|
||||
}
|
||||
|
||||
return {
|
||||
r: Math.round(r * 255),
|
||||
g: Math.round(g * 255),
|
||||
b: Math.round(b * 255)
|
||||
};
|
||||
}
|
||||
|
||||
function _lum(r, g, b) {
|
||||
function f(x) {
|
||||
x = x / 255;
|
||||
return x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
|
||||
}
|
||||
return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
|
||||
}
|
||||
|
||||
function _contrast(a, b) {
|
||||
var L1 = _lum(a.r, a.g, a.b);
|
||||
var L2 = _lum(b.r, b.g, b.b);
|
||||
var lighter = Math.max(L1, L2);
|
||||
var darker = Math.min(L1, L2);
|
||||
return (lighter + 0.05) / (darker + 0.05);
|
||||
}
|
||||
|
||||
function _tryPureBackground(data, w, h) {
|
||||
var edgeColors = {};
|
||||
var edgeTotal = 0;
|
||||
|
||||
function push(r, g, b, a) {
|
||||
if (a !== 255) return;
|
||||
var k = _toKey(r, g, b);
|
||||
edgeColors[k] = (edgeColors[k] || 0) + 1;
|
||||
edgeTotal++;
|
||||
}
|
||||
|
||||
for (var x = 0; x < w; x++) {
|
||||
var top = (0 * w + x) * 4;
|
||||
var bot = ((h - 1) * w + x) * 4;
|
||||
push(data[top], data[top + 1], data[top + 2], data[top + 3]);
|
||||
push(data[bot], data[bot + 1], data[bot + 2], data[bot + 3]);
|
||||
}
|
||||
for (var y = 1; y < h - 1; y++) {
|
||||
var left = (y * w + 0) * 4;
|
||||
var right = (y * w + (w - 1)) * 4;
|
||||
push(data[left], data[left + 1], data[left + 2], data[left + 3]);
|
||||
push(data[right], data[right + 1], data[right + 2], data[right + 3]);
|
||||
}
|
||||
|
||||
if (edgeTotal === 0) return null;
|
||||
|
||||
var best = null,
|
||||
bestCount = 0;
|
||||
for (var k in edgeColors) {
|
||||
if (edgeColors.hasOwnProperty(k) && edgeColors[k] > bestCount) {
|
||||
bestCount = edgeColors[k];
|
||||
best = k;
|
||||
}
|
||||
}
|
||||
if (best && bestCount / edgeTotal >= 0.95) return best;
|
||||
return null;
|
||||
}
|
||||
|
||||
function _process(img) {
|
||||
if (!img || !img.complete) { callback(null); return; }
|
||||
|
||||
var canvas = document.createElement("canvas");
|
||||
var ctx = canvas.getContext("2d");
|
||||
canvas.width = img.naturalWidth || img.width;
|
||||
canvas.height = img.naturalHeight || img.height;
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
var imageData;
|
||||
try {
|
||||
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
} catch (e) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
|
||||
var data = imageData.data;
|
||||
var w = canvas.width,
|
||||
h = canvas.height;
|
||||
|
||||
// 1) 尝试纯色背景
|
||||
var pure = _tryPureBackground(data, w, h);
|
||||
if (pure) { callback(pure); return; }
|
||||
|
||||
// 2) 统计不透明像素(抽样)
|
||||
var sumR = 0,
|
||||
sumG = 0,
|
||||
sumB = 0,
|
||||
count = 0;
|
||||
var samples = 0;
|
||||
var step = 4; // 4x抽样,减少性能消耗
|
||||
for (var y = 0; y < h; y += step) {
|
||||
for (var x = 0; x < w; x += step) {
|
||||
var i = (y * w + x) * 4;
|
||||
var a = data[i + 3];
|
||||
if (a === 255) {
|
||||
sumR += data[i];
|
||||
sumG += data[i + 1];
|
||||
sumB += data[i + 2];
|
||||
count++;
|
||||
}
|
||||
samples++;
|
||||
}
|
||||
}
|
||||
if (count === 0) { callback(null); return; }
|
||||
|
||||
var avgR = sumR / count,
|
||||
avgG = sumG / count,
|
||||
avgB = sumB / count;
|
||||
|
||||
// 3) 生成候选色(借鉴流行配色)
|
||||
var base = _rgbToHsl(avgR, avgG, avgB);
|
||||
|
||||
function clamp(v, min, max) { return Math.max(min, Math.min(max, v)); }
|
||||
|
||||
var candidates = [];
|
||||
|
||||
// 中性色(低饱和)
|
||||
candidates.push(_hslToRgb(base.h, 0.05, 0.5));
|
||||
candidates.push(_hslToRgb(base.h, 0.1, 0.6));
|
||||
candidates.push(_hslToRgb(base.h, 0.1, 0.4));
|
||||
|
||||
// 平均色去饱和
|
||||
candidates.push(_hslToRgb(base.h, clamp(base.s * 0.4, 0.05, 0.2), clamp(base.l, 0.2, 0.8)));
|
||||
|
||||
// 互补色(活泼)
|
||||
candidates.push(_hslToRgb((base.h + 0.5) % 1, clamp(base.s * 0.6, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
|
||||
|
||||
// 类似色
|
||||
candidates.push(_hslToRgb((base.h + 0.083) % 1, clamp(base.s * 0.5, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
|
||||
candidates.push(_hslToRgb((base.h - 0.083 + 1) % 1, clamp(base.s * 0.5, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
|
||||
|
||||
// 三分色
|
||||
candidates.push(_hslToRgb((base.h + 0.333) % 1, clamp(base.s * 0.6, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
|
||||
candidates.push(_hslToRgb((base.h - 0.333 + 1) % 1, clamp(base.s * 0.6, 0.1, 0.8), clamp(base.l, 0.35, 0.7)));
|
||||
|
||||
// 4) 计算最小对比度(与所有不透明像素)
|
||||
function minContrastWithImage(bg) {
|
||||
var bgObj = { r: bg.r, g: bg.g, b: bg.b };
|
||||
var minC = Infinity;
|
||||
|
||||
for (var y = 0; y < h; y += step) {
|
||||
for (var x = 0; x < w; x += step) {
|
||||
var i = (y * w + x) * 4;
|
||||
if (data[i + 3] !== 255) continue;
|
||||
var px = { r: data[i], g: data[i + 1], b: data[i + 2] };
|
||||
var c = _contrast(bgObj, px);
|
||||
if (c < minC) minC = c;
|
||||
}
|
||||
}
|
||||
return minC;
|
||||
}
|
||||
|
||||
var best = null;
|
||||
for (var i = 0; i < candidates.length; i++) {
|
||||
var c = candidates[i];
|
||||
var minC = minContrastWithImage(c);
|
||||
if (minC >= 4.5) {
|
||||
best = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (best) {
|
||||
callback(_toKey(best.r, best.g, best.b));
|
||||
} else {
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
|
||||
if (source && source.tagName && source.tagName.toLowerCase() === "img") {
|
||||
_process(source);
|
||||
} else if (typeof source === "string") {
|
||||
_createImage(source, _process, function() { callback(null); });
|
||||
} else {
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
|
||||
function getSuitableBackgroundColor(source, callback) {
|
||||
getSolidOpaqueBackgroundColor(source, function(color) {
|
||||
if (color) {
|
||||
callback(color);
|
||||
} else {
|
||||
getHamonyColor(source, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
var strres = external.StringResources;
|
||||
|
||||
function createLocalizedCompare(locale) {
|
||||
return function(a, b) {
|
||||
@@ -383,9 +19,17 @@
|
||||
var mgr = Package.manager;
|
||||
var nstr = Bridge.NString;
|
||||
var datasrc = new DataView.DataSource();
|
||||
datasrc.setKeySelector(function(item) {
|
||||
if (item === null || item === void 0) return null;
|
||||
return Bridge.String.tolower(Bridge.String.trim(item.Identity.FullName));
|
||||
});
|
||||
var themeColor = Bridge.UI.themeColor;
|
||||
var loadingDisplay = document.getElementById("applist-loading");
|
||||
var loadingStatus = loadingDisplay.querySelector(".title");
|
||||
var emptyDisplay = document.createElement("div");
|
||||
var dataLengthDisplay = document.getElementById("applist-datalen");
|
||||
var appSearchList = document.getElementById("applist-search");
|
||||
emptyDisplay.textContent = strres.get("MANAGER_MANAGE_LISTEMPTY");
|
||||
var listView = new DataView.ListView(listContainer, function(item) {
|
||||
var appItem = appItemTemplate.cloneNode(true);
|
||||
appItem.id = "";
|
||||
@@ -407,17 +51,102 @@
|
||||
appItem.setAttribute("data-version", item.Identity.Version.Expression);
|
||||
appItem.setAttribute("data-users", item.Users);
|
||||
appItem.setAttribute("data-publisher-id", item.Identity.PublisherId);
|
||||
setTimeout(function(a, b) {
|
||||
getSolidOpaqueBackgroundColor(a, function(color) {
|
||||
try {
|
||||
var pipes = color.split(",");
|
||||
var colorobj = new Color(parseInt(pipes[0]), parseInt(pipes[1]), parseInt(pipes[2]));
|
||||
if (colorobj.hex == "#ffffff" || colorobj.hex == "#000000") throw "too white or black";
|
||||
var rgbstr = colorobj.RGB.toString();
|
||||
b.style.backgroundColor = rgbstr;
|
||||
} catch (e) {}
|
||||
});
|
||||
}, 0, item.Properties.LogoBase64, logoimg.parentElement);
|
||||
logoimg.parentElement.style.backgroundColor = item.BackgroundColor;
|
||||
if (item.BackgroundColor === "transparent") {
|
||||
logoimg.parentElement.style.backgroundColor = themeColor;
|
||||
}
|
||||
var uninstallButton = appItem.querySelector("div[role=control] .uninstall");
|
||||
Windows.UI.Event.Util.addEvent(uninstallButton, "click", function(e) {
|
||||
e.stopPropagation();
|
||||
this.disabled = true;
|
||||
var itemNode = this.parentNode.parentNode.parentNode;
|
||||
var flyout = document.getElementById("app-uninstall-flyout");
|
||||
if (typeof flyout.appDataSource !== "undefined") flyout.appDataSource.clear();
|
||||
if (typeof flyout.appDataSource !== "undefined") {
|
||||
Package.reader.readFromInstallLocation(this.parentNode.parentNode.parentNode.data.InstallLocation, true).then(function(result) {
|
||||
try {
|
||||
if (typeof result.json.applications === "undefined" || result.json.applications.length === 0) {
|
||||
result.json.applications = [{
|
||||
DisplayName: item.Properties.DisplayName || item.Identity.Name,
|
||||
SmallLogo_Base64: item.Properties.LogoBase64,
|
||||
}];
|
||||
}
|
||||
flyout.appDataSource.updateList(result.json.applications);
|
||||
|
||||
} catch (e) {}
|
||||
}, function(result) {
|
||||
try { flyout.appDataSource.updateList(result.json.applications); } catch (e) {}
|
||||
});
|
||||
}
|
||||
var self = this;
|
||||
var confirm = flyout.querySelector(".confirm");
|
||||
confirm.onclick = null;
|
||||
confirm.onclick = function() {
|
||||
self.disabled = true;
|
||||
flyout.winControl.hide();
|
||||
var fullName = itemNode.getAttribute("data-full-name");
|
||||
itemNode.classList.add("uninstalling");
|
||||
var progressPart = itemNode.querySelector("div[role=progress]");
|
||||
var statusDisplay = progressPart.querySelector(".status");
|
||||
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_ING");
|
||||
var progressDisplay = progressPart.querySelector(".progress");
|
||||
progressDisplay.removeAttribute("value");
|
||||
self.disabled = true;
|
||||
(function(itemNode, statusDisplay, progressDisplay, self) {
|
||||
mgr.remove(fullName).then(function(_s) {
|
||||
itemNode.classList.remove("uninstalling");
|
||||
itemNode.classList.add("uninstalled");
|
||||
if (_s.succeeded) {
|
||||
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_SUCCEED");
|
||||
datasrc.remove(itemNode.data);
|
||||
} else {
|
||||
statusDisplay.textContent = _s.message;
|
||||
setTimeout(function(iNode, uButton) {
|
||||
iNode.classList.remove("uninstalled");
|
||||
uButton.disabled = false;
|
||||
}, 5000, itemNode, self);
|
||||
}
|
||||
}, function(_f) {
|
||||
itemNode.classList.remove("uninstalling");
|
||||
itemNode.classList.add("uninstalled");
|
||||
try {
|
||||
if (_f.succeeded) {
|
||||
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_SUCCEED");
|
||||
datasrc.remove(itemNode.data);
|
||||
} else {
|
||||
statusDisplay.textContent = _f.message;
|
||||
setTimeout(function(iNode, uButton) {
|
||||
iNode.classList.remove("uninstalled");
|
||||
uButton.disabled = false;
|
||||
}, 5000, itemNode, self);
|
||||
}
|
||||
} catch (e) {
|
||||
statusDisplay.textContent = e.message;
|
||||
setTimeout(function(iNode, uButton) {
|
||||
iNode.classList.remove("uninstalled");
|
||||
uButton.disabled = false;
|
||||
}, 5000, itemNode, self);
|
||||
}
|
||||
self.disabled = false;
|
||||
}, function(_p) {
|
||||
statusDisplay.textContent = Bridge.String.format(
|
||||
strres.get("MANAGER_APP_UNINSTALL_PROGRESSING"),
|
||||
_p
|
||||
);
|
||||
progressDisplay.value = _p;
|
||||
});
|
||||
})(itemNode, statusDisplay, progressDisplay, self);
|
||||
};
|
||||
var winFlyout = flyout.winControl;
|
||||
if (winFlyout._beforehideHandler) {
|
||||
winFlyout.removeEventListener("beforehide", winFlyout._beforehideHandler);
|
||||
}
|
||||
winFlyout._beforehideHandler = function() {
|
||||
self.disabled = false;
|
||||
};
|
||||
winFlyout.addEventListener("beforehide", winFlyout._beforehideHandler);
|
||||
flyout.winControl.show(this);
|
||||
});
|
||||
Windows.UI.Event.Util.addEvent(appItem.querySelector("div[role=advance] a"), "click", function(e) {
|
||||
e.stopPropagation();
|
||||
try {
|
||||
@@ -428,93 +157,385 @@
|
||||
});
|
||||
listView.selectionMode = "single";
|
||||
listView.bind(datasrc);
|
||||
listView.emptyView = emptyDisplay;
|
||||
listView.searchHandler = function(text, item) {
|
||||
return ((item.Properties.DisplayName || item.Identity.Name || "") + (item.Properties.Publisher || "")).indexOf(text) >= 0;
|
||||
};
|
||||
appSearchList.control = new Search.Box(appSearchList, {
|
||||
placeholderText: strres.get("MANAGER_MANAGE_SEARCHPLACEHOLDER"),
|
||||
chooseSuggestionOnEnter: false
|
||||
});
|
||||
appSearchList.control.ontextchanged = function(ev) {
|
||||
console.log(ev.text);
|
||||
listView.searchText = ev.detail.text;
|
||||
};
|
||||
listView.onsearchend = function() {
|
||||
dataLengthDisplay.textContent = external.String.format(strres.get("MANAGER_MANAGE_FINDAPPS"), listView.findItemLength);
|
||||
};
|
||||
var timer = null;
|
||||
|
||||
function refreshAppList() {
|
||||
dataLengthDisplay.textContent = "";
|
||||
|
||||
function processData(manifest, dataitem) {
|
||||
//if (dataitem.Identity.FamilyName = "Microsoft.MicrosoftEdge.Stable_8wekyb3d8bbwe") debugger;
|
||||
dataitem.Properties.DisplayName = dataitem.Properties.DisplayName || manifest.properties.display_name || dataitem.Properties.DisplayName;
|
||||
if ((dataitem.Properties.DisplayName || "").indexOf("ms-resource:") === 0) {
|
||||
dataitem.Properties.DisplayName = "";
|
||||
}
|
||||
if (manifest.applications.length === 1) {
|
||||
dataitem.Properties.DisplayName = dataitem.Properties.DisplayName || manifest.applications[0].DisplayName || "";
|
||||
}
|
||||
if ((dataitem.Properties.DisplayName || "").indexOf("ms-resource:") === 0) {
|
||||
dataitem.Properties.DisplayName = "";
|
||||
}
|
||||
if (manifest.applications.length === 1) {
|
||||
dataitem.Properties.DisplayName = dataitem.Properties.DisplayName || manifest.applications[0].ShortName || "";
|
||||
}
|
||||
if ((dataitem.Properties.DisplayName || "").indexOf("ms-resource:") === 0) {
|
||||
dataitem.Properties.DisplayName = "";
|
||||
}
|
||||
dataitem.Properties.DisplayName = dataitem.Properties.DisplayName || dataitem.Identity.FamilyName;
|
||||
dataitem.Properties.Puvlisher = dataitem.Properties.Publisher || manifest.properties.publisher_display_name || dataitem.Properties.Publisher;
|
||||
dataitem.Properties.Framework = dataitem.Properties.Framework || manifest.properties.framework;
|
||||
dataitem.Properties.Logo = dataitem.Properties.Logo || manifest.properties.logo;
|
||||
dataitem.Properties.LogoBase64 = dataitem.Properties.LogoBase64 || manifest.properties.logo_base64;
|
||||
if (manifest.applications.length === 1) {
|
||||
dataitem.Properties.LogoBase64 = dataitem.Properties.LogoBase64 || manifest.applications[0].Square44x44Logo_Base64 || manifest.applications[0].SmallLogo_Base64;
|
||||
}
|
||||
dataitem.Properties.ResourcePackage = dataitem.Properties.ResourcePackage || manifest.properties.resource_package;
|
||||
dataitem.Properties.Description = dataitem.Properties.Description || manifest.properties.description;
|
||||
try {
|
||||
dataitem.BackgroundColor = manifest.applications[0].BackgroundColor || "transparent";
|
||||
} catch (e) {
|
||||
dataitem.BackgroundColor = "transparent";
|
||||
}
|
||||
return dataitem;
|
||||
}
|
||||
|
||||
function update(datas) {
|
||||
var newDatas = [];
|
||||
var promises = [];
|
||||
for (var i = 0; i < datas.length; i++) {
|
||||
var data = datas[i];
|
||||
if (data.Properties.Framework) continue; // 过滤依赖项
|
||||
var isfind = false; // 过滤系统应用
|
||||
for (var j = 0; data && data.Users && j < data.Users.length; j++) {
|
||||
if (Bridge.NString.equals(data.Users[j], "NT AUTHORITY\\SYSTEM")) {
|
||||
isfind = true;
|
||||
break;
|
||||
if (external.System.isWindows10) {
|
||||
if (data.Properties.DisplayName === null || data.Properties.DisplayName === "" || data.Properties.DisplayName === void 0 ||
|
||||
data.Properties.LogoBase64 === null || data.Properties.LogoBase64 === "" || data.Properties.LogoBase64 === void 0
|
||||
) {
|
||||
promises.push(function(item, arr) {
|
||||
return Package.reader.readFromInstallLocation(item.InstallLocation, true).then(function(result) {
|
||||
try {
|
||||
arr.push(processData(result.json, item));
|
||||
} catch (e) {
|
||||
item.BackgroundColor = "transparent";
|
||||
arr.push(item);
|
||||
}
|
||||
}, function(result) {
|
||||
try {
|
||||
arr.push(processData(result.json, item));
|
||||
} catch (e) {
|
||||
item.BackgroundColor = "transparent";
|
||||
arr.push(item);
|
||||
}
|
||||
});
|
||||
}(data, newDatas));
|
||||
} else {
|
||||
promises.push(function(item, arr) {
|
||||
return Package.reader.readFromInstallLocation(item.InstallLocation, false).then(function(result) {
|
||||
try {
|
||||
item.BackgroundColor = result.json.applications[0].BackgroundColor;
|
||||
arr.push(item);
|
||||
} catch (e) {
|
||||
item.BackgroundColor = "transparent";
|
||||
arr.push(item);
|
||||
}
|
||||
}, function(result) {
|
||||
try {
|
||||
item.BackgroundColor = result.json.applications[0].BackgroundColor;
|
||||
arr.push(item);
|
||||
} catch (e) {
|
||||
item.BackgroundColor = "transparent";
|
||||
arr.push(item);
|
||||
}
|
||||
});
|
||||
}(data, newDatas));
|
||||
}
|
||||
} else {
|
||||
promises.push(function(item, arr) {
|
||||
return Package.reader.readFromInstallLocation(item.InstallLocation, true).then(function(result) {
|
||||
try {
|
||||
arr.push(processData(result.json, item));
|
||||
} catch (e) {
|
||||
item.BackgroundColor = "transparent";
|
||||
arr.push(item);
|
||||
}
|
||||
}, function(result) {
|
||||
try {
|
||||
arr.push(processData(result.json, item));
|
||||
} catch (e) {
|
||||
item.BackgroundColor = "transparent";
|
||||
arr.push(item);
|
||||
}
|
||||
});
|
||||
}(data, newDatas));
|
||||
}
|
||||
}
|
||||
|
||||
function updateDatas() {
|
||||
datasrc.updateList(newDatas, function(item) {
|
||||
return item.Identity.FullName || "";
|
||||
});
|
||||
var compare = function(a, b) { return a - b; };
|
||||
try {
|
||||
compare = createLocalizedCompare(external.System.Locale.currentLocale);
|
||||
} catch (e) {
|
||||
try {
|
||||
compare = createLocalizedCompare(navigator.language);
|
||||
} catch (e) {
|
||||
compare = function(a, b) {
|
||||
if (a < b) return -1;
|
||||
if (a > b) return 1;
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
if (isfind) continue;
|
||||
newDatas.push(data);
|
||||
datasrc.sort(function(a, b) {
|
||||
return compare(a.Properties.DisplayName, b.Properties.DisplayName);
|
||||
});
|
||||
dataLengthDisplay.textContent = external.String.format(strres.get("MANAGER_MANAGE_FINDAPPS"), listView.findItemLength);
|
||||
}
|
||||
datasrc.updateList(newDatas, function(item) {
|
||||
return item.Identity.FullName || "";
|
||||
});
|
||||
var compare = function(a, b) { return a - b; };
|
||||
try {
|
||||
compare = createLocalizedCompare(external.System.Locale.currentLocale);
|
||||
} catch (e) {
|
||||
try {
|
||||
compare = createLocalizedCompare(navigator.language);
|
||||
} catch (e) {
|
||||
compare = function(a, b) {
|
||||
if (a < b) return -1;
|
||||
if (a > b) return 1;
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
datasrc.sort(function(a, b) {
|
||||
return compare(a.Properties.DisplayName, b.Properties.DisplayName);
|
||||
});
|
||||
return Promise.join(promises).then(updateDatas, updateDatas);
|
||||
}
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = null;
|
||||
loadingDisplay.style.display = "";
|
||||
loadingDisplay.classList.remove("noloading");
|
||||
loadingDisplay.bar.show();
|
||||
|
||||
function waitAndHide() {
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = null;
|
||||
timer = setTimeout(function() {
|
||||
loadingDisplay.style.display = "none";
|
||||
}, 10000);
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = null;
|
||||
timer = setTimeout(function(rs, rj) {
|
||||
//loadingDisplay.style.display = "none";
|
||||
loadingDisplay.bar.hide();
|
||||
rs();
|
||||
}, 5000, resolve, reject);
|
||||
});
|
||||
}
|
||||
loadingStatus.textContent = "正在加载数据...";
|
||||
loadingStatus.textContent = strres.get("MANAGER_APP_INSTALLEDAPPS_LOADING");
|
||||
return mgr.get().then(function(result) {
|
||||
loadingDisplay.classList.add("noloading");
|
||||
loadingStatus.textContent = "已经加载了所有数据";
|
||||
update(result.list);
|
||||
waitAndHide();
|
||||
return update(result.list).then(function() {
|
||||
loadingDisplay.classList.add("noloading");
|
||||
loadingStatus.textContent = strres.get("MANAGER_APP_INSTALLEDAPPS_SUCCEED");
|
||||
setTimeout(function(lv) {
|
||||
lv.refresh();
|
||||
}, 500, listView);
|
||||
}).then(waitAndHide);
|
||||
}, function(error) {
|
||||
loadingDisplay.classList.add("noloading");
|
||||
loadingStatus.textContent = "更新时出错: " + (error.result ? (error.result.message || error.result.ErrorCode || "获取失败") : (error.message || error.error || error));
|
||||
var errmsg = (error.result ? (error.result.message || error.result.ErrorCode || "获取失败") : (error.message || error.error || error));
|
||||
loadingStatus.textContent = external.String.format(strres.get("MANAGER_APP_INSTALLEDAPPS_FAILED"), errmsg);
|
||||
try { update(error.list); } catch (e) {}
|
||||
waitAndHide();
|
||||
})
|
||||
setTimeout(function(lv) {
|
||||
lv.refresh();
|
||||
}, 500, listView);
|
||||
return waitAndHide();
|
||||
});
|
||||
}
|
||||
var appbar = document.getElementById("appBar");
|
||||
var appbarControl = new AppBar.AppBar(appbar);
|
||||
var refreshButton = new AppBar.Command();
|
||||
refreshButton.icon = "";
|
||||
refreshButton.label = "刷新";
|
||||
refreshButton.label = strres.get("MANAGER_APP_REFRESH");
|
||||
global.refreshAppList2 = function refreshAppList2() {
|
||||
appbarControl.hide();
|
||||
refreshButton.disabled = true;
|
||||
refreshAppList().done(function() {
|
||||
return refreshAppList().then(function() {
|
||||
refreshButton.disabled = false;
|
||||
}, function(error) {
|
||||
refreshButton.disabled = false;
|
||||
});
|
||||
}
|
||||
var showSystemApps = document.getElementById("applist-showsystemapp");
|
||||
var showFrameworks = document.getElementById("applist-showframework");
|
||||
listView.filter = function(item) {
|
||||
try {
|
||||
if (!showFrameworks.checked && item.Properties.Framework) return false;
|
||||
if (!showSystemApps.checked && item.Users.indexOf("NT AUTHORITY\\SYSTEM") !== -1) return false;
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Windows.UI.Event.Util.addEvent(showSystemApps, "change", function() {
|
||||
listView.refresh();
|
||||
dataLengthDisplay.textContent = external.String.format(strres.get("MANAGER_MANAGE_FINDAPPS"), listView.findItemLength);
|
||||
});
|
||||
Windows.UI.Event.Util.addEvent(showFrameworks, "change", function() {
|
||||
listView.refresh();
|
||||
dataLengthDisplay.textContent = external.String.format(strres.get("MANAGER_MANAGE_FINDAPPS"), listView.findItemLength);
|
||||
});
|
||||
refreshButton.addEventListener("click", refreshAppList2);
|
||||
appbarControl.add(refreshButton);
|
||||
refreshAppList2();
|
||||
var appDetailPage = document.getElementById("page-appinfo");
|
||||
pagemgr.register("manager", document.getElementById("tag-manager"), document.getElementById("page-manager"));
|
||||
pagemgr.register("appinfo", document.getElementById("tag-appinfo"), document.getElementById("page-appinfo"), setAppInfoPageContent);
|
||||
var appinfoBackPage = document.getElementById("page-appinfo").querySelector(".win-backbutton");
|
||||
var appinfoBackPage = appDetailPage.querySelector(".win-backbutton");
|
||||
Windows.UI.Event.Util.addEvent(appinfoBackPage, "click", function(e) {
|
||||
pagemgr.back();
|
||||
});
|
||||
appDetailPage.appDataSource = new DataView.DataSource();
|
||||
var appListView = new DataView.ListView(appDetailPage.querySelector(".apps"), function(item) {
|
||||
var appItem = appItemTemplate.cloneNode(true);
|
||||
appItem.id = "";
|
||||
appItem.style.display = "";
|
||||
var logoimg = appItem.querySelector("img");
|
||||
logoimg.src = item.Square44x44Logo_Base64 || item.SmallLogo_Base64;
|
||||
if (logoimg.src == "" || logoimg.src == null || logoimg.src == void 0) logoimg.removeAttribute("src");
|
||||
logoimg.parentElement.style.backgroundColor = item.BackgroundColor;
|
||||
if (Bridge.NString.equals(item.BackgroundColor, "transparent")) logoimg.parentElement.style.backgroundColor = themeColor;
|
||||
var appName = appItem.querySelector(".displayName");
|
||||
appName.textContent = item.DisplayName || item.ShortName;
|
||||
var appPub = appItem.querySelector(".publisher");
|
||||
appPub.style.display = "none";
|
||||
appItem.querySelector("div[role=advance]").style.display = "none";
|
||||
var ctrls = appItem.querySelector("div[role=control]");
|
||||
ctrls.innerHTML = "";
|
||||
appItem.data = item;
|
||||
var launchButton = document.createElement("button");
|
||||
launchButton.textContent = strres.get("MANAGER_APP_LAUNCH");
|
||||
launchButton.setAttribute("data-app-user-model-id", item.AppUserModelID);
|
||||
var createShortcutButton = document.createElement("button");
|
||||
createShortcutButton.textContent = strres.get("MANAGER_APP_CREATESHORTCUT");
|
||||
createShortcutButton.style.marginRight = "10px";
|
||||
Windows.UI.Event.Util.addEvent(launchButton, "click", function(e) {
|
||||
e.stopPropagation();
|
||||
Package.manager.active(this.getAttribute("data-app-user-model-id"));
|
||||
});
|
||||
ctrls.appendChild(launchButton);
|
||||
ctrls.appendChild(createShortcutButton);
|
||||
return appItem;
|
||||
});
|
||||
appListView.selectionMode = "single";
|
||||
appListView.bind(appDetailPage.appDataSource);
|
||||
appListView.emptyView = emptyDisplay.cloneNode(true);
|
||||
var appDetailUninstall = appDetailPage.querySelector("#detail-uninstall-btn");
|
||||
var appDetailUninstallStatusBlock = appDetailPage.querySelector("#appinfo-uninstallstatus");
|
||||
var appDetailUninstallProgress = appDetailUninstallStatusBlock.querySelector(".progress");
|
||||
var appDetailUninstallProgressStatus = appDetailUninstallStatusBlock.querySelector(".status");
|
||||
appDetailUninstallStatusBlock.bar = new TransitionPanel(appDetailUninstallStatusBlock, {
|
||||
axis: 'y',
|
||||
duration: 500,
|
||||
});
|
||||
Windows.UI.Event.Util.addEvent(appDetailUninstall, "click", function(e) {
|
||||
e.stopPropagation();
|
||||
appinfoBackPage.disabled = true;
|
||||
appDetailUninstallProgress.removeAttribute("value");
|
||||
var item = appDetailPage.data;
|
||||
var flyout = document.getElementById("app-uninstall-flyout");
|
||||
if (typeof flyout.appDataSource !== "undefined") flyout.appDataSource.clear();
|
||||
if (typeof flyout.appDataSource !== "undefined") {
|
||||
flyout.appDataSource.updateList(appDetailPage.appDataSource.get());
|
||||
}
|
||||
var self = this;
|
||||
var confirm = flyout.querySelector(".confirm");
|
||||
confirm.onclick = null;
|
||||
confirm.onclick = function() {
|
||||
self.disabled = true;
|
||||
flyout.winControl.hide();
|
||||
var fullName = item.Identity.FullName;
|
||||
var progressPart = appDetailUninstallStatusBlock;
|
||||
var statusDisplay = appDetailUninstallProgressStatus;
|
||||
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_ING");
|
||||
var progressDisplay = appDetailUninstallProgress;
|
||||
progressDisplay.style.display = "";
|
||||
self.disabled = true;
|
||||
progressPart.bar.show();
|
||||
(function(statusDisplay, progressDisplay, self, item) {
|
||||
mgr.remove(fullName).then(function(_s) {
|
||||
if (_s.succeeded) {
|
||||
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_SUCCEED");
|
||||
datasrc.remove(item);
|
||||
appinfoBackPage.disabled = false;
|
||||
} else {
|
||||
statusDisplay.textContent = _s.message;
|
||||
}
|
||||
setTimeout(function(uButton, isSuccess) {
|
||||
appinfoBackPage.disabled = false;
|
||||
uButton.disabled = isSuccess;
|
||||
progressPart.bar.hide();
|
||||
}, 5000, self, _s.succeeded);
|
||||
progressDisplay.style.display = "none";
|
||||
}, function(_f) {
|
||||
try {
|
||||
if (_f.succeeded) {
|
||||
statusDisplay.textContent = strres.get("MANAGER_APP_UNINSTALL_SUCCEED");
|
||||
datasrc.remove(item);
|
||||
appinfoBackPage.disabled = false;
|
||||
} else {
|
||||
statusDisplay.textContent = _f.message;
|
||||
}
|
||||
setTimeout(function(uButton, isSuccess) {
|
||||
appinfoBackPage.disabled = false;
|
||||
uButton.disabled = isSuccess;
|
||||
progressPart.bar.hide();
|
||||
}, 5000, self, _f.succeeded);
|
||||
} catch (e) {
|
||||
statusDisplay.textContent = e.message;
|
||||
appinfoBackPage.disabled = false;
|
||||
setTimeout(function(uButton, isSuccess) {
|
||||
appinfoBackPage.disabled = false;
|
||||
uButton.disabled = isSuccess;
|
||||
progressPart.bar.hide();
|
||||
}, 5000, self, _f.succeeded);
|
||||
}
|
||||
self.disabled = false;
|
||||
progressDisplay.style.display = "none";
|
||||
}, function(_p) {
|
||||
statusDisplay.textContent = Bridge.String.format(
|
||||
strres.get("MANAGER_APP_UNINSTALL_PROGRESSING"),
|
||||
_p
|
||||
);
|
||||
progressDisplay.value = _p;
|
||||
});
|
||||
})(statusDisplay, progressDisplay, self, item);
|
||||
};
|
||||
var winFlyout = flyout.winControl;
|
||||
if (winFlyout._beforehideHandler) {
|
||||
winFlyout.removeEventListener("beforehide", winFlyout._beforehideHandler);
|
||||
}
|
||||
winFlyout._beforehideHandler = function() {
|
||||
self.disabled = false;
|
||||
};
|
||||
winFlyout.addEventListener("beforehide", winFlyout._beforehideHandler);
|
||||
flyout.winControl.show(this);
|
||||
});
|
||||
var uninstallFlyout = document.getElementById("app-uninstall-flyout");
|
||||
uninstallFlyout.appListView = new DataView.ListView(uninstallFlyout.querySelector(".applist"), function(item) {
|
||||
var appItem = appItemTemplate.cloneNode(true);
|
||||
appItem.id = "";
|
||||
appItem.style.display = "";
|
||||
var logoimg = appItem.querySelector("img");
|
||||
logoimg.src = item.Square44x44Logo_Base64 || item.SmallLogo_Base64;
|
||||
if (logoimg.src == "" || logoimg.src == null || logoimg.src == void 0) logoimg.removeAttribute("src");
|
||||
logoimg.parentElement.style.backgroundColor = item.BackgroundColor;
|
||||
if (Bridge.NString.equals(item.BackgroundColor, "transparent")) logoimg.parentElement.style.backgroundColor = themeColor;
|
||||
var appName = appItem.querySelector(".displayName");
|
||||
appName.style.wordBreak = "normal";
|
||||
appName.style.wordWrap = "normal";
|
||||
appName.textContent = item.DisplayName || item.ShortName;
|
||||
var appPub = appItem.querySelector(".publisher");
|
||||
appPub.style.display = "none";
|
||||
appItem.querySelector("div[role=advance]").style.display = "none";
|
||||
var ctrls = appItem.querySelector("div[role=control]");
|
||||
ctrls.innerHTML = "";
|
||||
appItem.data = item;
|
||||
return appItem;
|
||||
});
|
||||
uninstallFlyout.appDataSource = new DataView.DataSource();
|
||||
uninstallFlyout.appListView.bind(uninstallFlyout.appDataSource);
|
||||
pagemgr.addEventListener("load", function(e) {
|
||||
appbarControl.enabled = e == "manager";
|
||||
refreshButton.style.display = e == "manager" ? "" : "none";
|
||||
|
||||
@@ -16,7 +16,44 @@
|
||||
if (callback) callback(ret);
|
||||
}
|
||||
global.Package = {
|
||||
reader: function(pkgPath) { return external.Package.reader(pkgPath); },
|
||||
reader: {
|
||||
package: function(pkgPath) { return external.Package.Reader.package(pkgPath); },
|
||||
manifest: function(swManifestPath) { return external.Package.Reader.manifest(swManifestPath); },
|
||||
manifestFromInstallLocation: function(swInstallLocation) { return external.Package.Reader.fromInstallLocation(swInstallLocation); },
|
||||
readFromPackage: function(swPkgPath, bUsePri) {
|
||||
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
|
||||
return new Promise(function(resolve, reject) {
|
||||
external.Package.Reader.readFromPackageAsync(swPkgPath, bUsePri, function(result) {
|
||||
parseJsonCallback(result, resolve);
|
||||
}, function(error) {
|
||||
parseJsonCallback(error, reject);
|
||||
});
|
||||
});
|
||||
},
|
||||
readFromManifest: function(swManifestPath, bUsePri) {
|
||||
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
|
||||
return new Promise(function(resolve, reject) {
|
||||
external.Package.Reader.readFromManifestAsync(swManifestPath, bUsePri, function(result) {
|
||||
parseJsonCallback(result, resolve);
|
||||
}, function(error) {
|
||||
parseJsonCallback(error, reject);
|
||||
});
|
||||
});
|
||||
},
|
||||
readFromInstallLocation: function(swInstallLocation, bUsePri) {
|
||||
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
|
||||
return new Promise(function(resolve, reject) {
|
||||
external.Package.Reader.readFromInstallLocationAsync(swInstallLocation, bUsePri, function(result) {
|
||||
parseJsonCallback(result, resolve);
|
||||
}, function(error) {
|
||||
parseJsonCallback(error, reject);
|
||||
});
|
||||
});
|
||||
},
|
||||
cancelAll: function() { external.Package.Reader.cancelAll(); },
|
||||
addApplicationReadItem: function(swItemName) { return external.Package.Reader.addApplicationItem(swItemName); },
|
||||
removeApplicationReadItem: function(swItemName) { return external.Package.Reader.removeApplicationItem(swItemName); }
|
||||
},
|
||||
manager: {
|
||||
add: function(swPkgPath, uOptions) {
|
||||
return new Promise(function(resolve, reject, progress) {
|
||||
@@ -129,38 +166,8 @@
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
manifest: function(swManifestPath) { return external.Package.manifest(swManifestPath); },
|
||||
manifestFromInstallLocation: function(swInstallLocation) { return external.Package.fromInstallLocation(swInstallLocation); },
|
||||
readFromPackage: function(swPkgPath, bUsePri) {
|
||||
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
|
||||
return new Promise(function(resolve, reject) {
|
||||
external.Package.readFromPackageAsync(swPkgPath, bUsePri, function(result) {
|
||||
parseJsonCallback(result, resolve);
|
||||
}, function(error) {
|
||||
parseJsonCallback(error, reject);
|
||||
});
|
||||
});
|
||||
},
|
||||
readFromManifest: function(swPkgPath, bUsePri) {
|
||||
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
|
||||
return new Promise(function(resolve, reject) {
|
||||
external.Package.readFromManifestAsync(swPkgPath, bUsePri, function(result) {
|
||||
parseJsonCallback(result, resolve);
|
||||
}, function(error) {
|
||||
parseJsonCallback(error, reject);
|
||||
});
|
||||
});
|
||||
},
|
||||
readFromInstallLocation: function(swPkgPath, bUsePri) {
|
||||
if (bUsePri === null || bUsePri === void 0) bUsePri = false;
|
||||
return new Promise(function(resolve, reject) {
|
||||
external.Package.readFromInstallLocationAsync(swPkgPath, bUsePri, function(result) {
|
||||
parseJsonCallback(result, resolve);
|
||||
}, function(error) {
|
||||
parseJsonCallback(error, reject);
|
||||
});
|
||||
});
|
||||
cancelAll: function() { mgr.cancelAll(); },
|
||||
active: function(swAppUserModelID, swArgs) { return mgr.activeApp(swAppUserModelID, swArgs || null); }
|
||||
},
|
||||
};
|
||||
})(this);
|
||||
@@ -13,7 +13,11 @@
|
||||
var byName = el.getAttribute('data-res-byname');
|
||||
var byId = el.getAttribute('data-res-byid');
|
||||
var fromFile = el.getAttribute('data-res-fromfile');
|
||||
if ((byName && !Bridge.NString.empty(byName)) || (byId && parseInt(byId, 10) > 0) || (fromFile && !Bridge.NString.empty(fromFile))) {
|
||||
var byXml = el.getAttribute('data-res-resxml');
|
||||
if ((byName && !Bridge.NString.empty(byName)) ||
|
||||
(byId && parseInt(byId, 10) > 0) ||
|
||||
(fromFile && !Bridge.NString.empty(fromFile)) ||
|
||||
(byXml && !Bridge.NString.empty(byXml))) {
|
||||
result.push(el);
|
||||
}
|
||||
}
|
||||
@@ -47,6 +51,16 @@
|
||||
} catch (e) {
|
||||
nodes[i].textContent = "";
|
||||
}
|
||||
} else if (nodes[i].hasAttribute('data-res-resxml')) {
|
||||
try {
|
||||
var obj = nodes[i].getAttribute('data-res-resxml');
|
||||
var strres = external.StringResources;
|
||||
if (strres && strres.isValid) {
|
||||
nodes[i].textContent = strres.get(obj);
|
||||
}
|
||||
} catch (e) {
|
||||
nodes[i].textContent = "";
|
||||
}
|
||||
} else {
|
||||
nodes[i].textContent = "";
|
||||
}
|
||||
|
||||
720
shared/html/js/search.js
Normal file
720
shared/html/js/search.js
Normal 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
184
shared/html/js/statusbar.js
Normal 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);
|
||||
@@ -33,6 +33,9 @@
|
||||
<script type="text/javascript" src="js/datasrc.js"></script>
|
||||
<script type="text/javascript" src="js/appbar.js"></script>
|
||||
<script type="text/javascript" src="js/pagemgr.js"></script>
|
||||
<script type="text/javascript" src="js/search.js"></script>
|
||||
<link rel="stylesheet" href="css/statusbar.css">
|
||||
<script type="text/javascript" src="js/statusbar.js"></script>
|
||||
<script type="text/javascript" src="js/manager/pages.js"></script>
|
||||
<script type="text/javascript" src="js/mgrinit.js"></script>
|
||||
</head>
|
||||
@@ -42,15 +45,39 @@
|
||||
<div class="page full guide fold">
|
||||
<main class="main padding">
|
||||
<div id="page-manager" style="display: none;" class="ispage">
|
||||
<h2>应用</h2>
|
||||
<p>在这里,可以对安装的 Windows 商店应用进行管理。</p>
|
||||
<h3>安装的应用</h3>
|
||||
<h2 data-res-resxml="MANAGER_APP_TITLE"></h2>
|
||||
<p data-res-resxml="MANAGER_APP_DESCRIPTION"></p>
|
||||
<h3 data-res-resxml="MANAGER_APP_INSTALLEDAPPS"></h3>
|
||||
<br>
|
||||
<div class="app-loading" id="applist-loading" style="display: none;">
|
||||
<progress class="win-ring"></progress>
|
||||
<span class="win-label title">正在加载应用...</span>
|
||||
<br>
|
||||
<div class="win-searchbox win-disposable" id="applist-search" role="group" aria-label="搜索框"></div>
|
||||
<div class="applist-options">
|
||||
<div class="item">
|
||||
<input type="checkbox" id="applist-showsystemapp">
|
||||
<label for="applist-showsystemapp" data-res-resxml="MANAGER_APP_SHOWSYSTEMAPP"></label>
|
||||
</div>
|
||||
<div class="item">
|
||||
<input type="checkbox" id="applist-showframework">
|
||||
<label for="applist-showframework" data-res-resxml="MANAGER_APP_SHOWFRAMEWORK"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-loading" id="applist-loading" style="display: none;">
|
||||
<br>
|
||||
<div class="container">
|
||||
<progress class="win-ring"></progress>
|
||||
<span class="win-label title" data-res-resxml="MANAGER_APP_INSTALLEDAPPS_LOADING"></span>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
<p id="applist-datalen"></p>
|
||||
<script>
|
||||
(function(global) {
|
||||
var appLoading = document.getElementById("applist-loading");
|
||||
appLoading.bar = new TransitionPanel(appLoading, {
|
||||
axis: 'y',
|
||||
duration: 500,
|
||||
});
|
||||
})(this);
|
||||
</script>
|
||||
<div class="appitem" id="appitem-template" style="display: none;">
|
||||
<div role="img" style="pointer-events: none;">
|
||||
<img width="" height="" src="images/applogo.default.png" />
|
||||
@@ -58,14 +85,18 @@
|
||||
<div role="divide" style="pointer-events: none;"></div>
|
||||
<div role="excepticon">
|
||||
<div role="title" class="win-type-x-small" style="pointer-events: none;">
|
||||
<span class="displayName">App Name</span><br>
|
||||
<span class="publisher">Publisher</span>
|
||||
<span class="displayName"></span><br>
|
||||
<span class="publisher"></span>
|
||||
</div>
|
||||
<div role="advance">
|
||||
<a>高级选项</a>
|
||||
<a data-res-resxml="MANAGER_APP_ADVANCEOPTIONS"></a>
|
||||
</div>
|
||||
<div role="progress">
|
||||
<span class="status" data-res-resxml="MANAGER_APP_UNINSTALL_ING"></span><br>
|
||||
<progress class="win-progress progress" min="0" max="100"></progress>
|
||||
</div>
|
||||
<div role="control">
|
||||
<button name="uninstall">卸载</button>
|
||||
<button class="uninstall" name="uninstall" data-res-resxml="MANAGER_APP_UNINSTALL"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -73,7 +104,7 @@
|
||||
</div>
|
||||
<div class="bottom-compensate"></div>
|
||||
</div>
|
||||
<div id="page-appinfo" class="ispage app-detailpage">
|
||||
<div id="page-appinfo" class="ispage app-detailpage" style="display: none;">
|
||||
<header>
|
||||
<button class="win-backbutton"></button>
|
||||
<h2 class="display-name">App DisplayName</h2>
|
||||
@@ -81,18 +112,37 @@
|
||||
<span class="publisher-display-name">App PublisherDisplayName</span><br>
|
||||
<span class="version">App Version</span><br>
|
||||
<span class="description">App Description</span>
|
||||
<p><strong>应用身份</strong></p>
|
||||
<p><strong data-res-resxml="MANAGER_APP_IDENTITY"></strong></p>
|
||||
<div class="identity win-type-body" style="width: 100%; max-width: 100%; box-sizing: border-box; -ms-user-select: element;">
|
||||
<span style="font-weight: bold;">名称</span><span>: </span><span class="name"></span><br>
|
||||
<span style="font-weight: bold;">发布者</span><span>: </span><span class="publisher"></span><br>
|
||||
<span style="font-weight: bold;">发布者 ID</span><span>: </span><span class="publisher-id"></span><br>
|
||||
<span style="font-weight: bold;">系列名</span><span>: </span><span class="family-name"></span><br>
|
||||
<span style="font-weight: bold;">全名</span><span>: </span><span class="full-name"></span><br>
|
||||
<span style="font-weight: bold;">支持的处理器架构</span><span>: </span><span class="architecture"></span><br>
|
||||
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_NAME"></span><span>: </span><span class="name"></span><br>
|
||||
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_PUBLISHER"></span><span>: </span><span class="publisher"></span><br>
|
||||
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_PUBLISHERID"></span><span>: </span><span class="publisher-id"></span><br>
|
||||
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_FAMILYNAME"></span><span>: </span><span class="family-name"></span><br>
|
||||
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_FULLNAME"></span><span>: </span><span class="full-name"></span><br>
|
||||
<span style="font-weight: bold;" data-res-resxml="MANAGER_APP_IDENTITY_ARCHITECTURE"></span><span>: </span><span class="architecture"></span><br>
|
||||
</div>
|
||||
<p><strong>卸载</strong></p>
|
||||
<p>卸载此应用及其设置。</p>
|
||||
<button id="detail-uninstall-btn" data-app-fullname="">卸载</button>
|
||||
<p><strong data-res-resxml="MANAGER_APP_HASAPPS"></strong></p>
|
||||
<p data-res-resxml="MANAGER_APP_HASAPPS_DESC"></p>
|
||||
<div class="loadingstatus" id="appinfo-loading">
|
||||
<div class="container">
|
||||
<progress class="win-ring"></progress>
|
||||
<span class="win-label title" data-res-resxml="MANAGER_APP_INSTALLEDAPPS_LOADING"></span>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
<div class="apps">
|
||||
</div>
|
||||
<p><strong data-res-resxml="MANAGER_APP_UNINSTALL"></strong></p>
|
||||
<p data-res-resxml="MANAGER_APP_UNINSTALL_DESC"></p>
|
||||
<div class="loadingstatus" id="appinfo-uninstallstatus">
|
||||
<div style="width: 100%;">
|
||||
<span class="status" data-res-resxml="MANAGER_APP_UNINSTALL_ING"></span><br>
|
||||
<progress class="win-progress progress" min="0" max="100"></progress>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
<button id="detail-uninstall-btn" data-res-resxml="MANAGER_APP_UNINSTALL">卸载</button>
|
||||
<div class="bottom-compensate"></div>
|
||||
</div>
|
||||
</main>
|
||||
<aside class="win-ui-dark">
|
||||
@@ -100,8 +150,8 @@
|
||||
<ul class="list top">
|
||||
<li class="title">
|
||||
<div role="img"></div>
|
||||
<div role="placeholder"></div>
|
||||
<span class="win-type-base">应用管理</span>
|
||||
<!--<div role="placeholder"></div>-->
|
||||
<span class="win-type-base" data-res-resxml="MANAGER_APPTITLE"></span>
|
||||
</li>
|
||||
<script>
|
||||
(function($) {
|
||||
@@ -117,7 +167,7 @@
|
||||
<ul class="list">
|
||||
<li id="tag-manager">
|
||||
<div role="img"></div>
|
||||
<span class="win-type-base">管理</span>
|
||||
<span class="win-type-base" data-res-resxml="MANAGER_MANAGE"></span>
|
||||
</li>
|
||||
<li id="tag-appinfo" class="subitem">
|
||||
<div role="img"></div>
|
||||
@@ -134,6 +184,39 @@
|
||||
</div>
|
||||
<div class="win-overlay win-commandlayout win-appbar win-bottom appbar win-ui-dark" id="appBar" role="menubar">
|
||||
</div>
|
||||
<div data-win-control="WinJS.UI.Flyout" id="app-uninstall-flyout" style="position: absolute; width: 336px; padding: 0; max-height: 284px;">
|
||||
<div class="top" style="padding: 20px 20px 0 20px;">
|
||||
<span data-res-resxml="MANAGER_APP_UNINSTALL_DESC"></span>
|
||||
</div>
|
||||
<div class="sapplist applist"></div>
|
||||
<style>
|
||||
#app-uninstall-flyout {
|
||||
/*min-height: 88px;
|
||||
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);*/
|
||||
}
|
||||
|
||||
#app-uninstall-flyout .sapplist {
|
||||
padding: 0 20px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-ms-overflow-style: -ms-autohiding-scrollbar;
|
||||
max-height: 160px;
|
||||
}
|
||||
</style>
|
||||
<div class="bottom" style="padding: 20px 20px 20px 20px; height: 32px;">
|
||||
<button class="confirm" data-res-resxml="MANAGER_APP_UNINSTALL" style="float: right;"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-deskshortcut-create" style="position: absolute;">
|
||||
<p>即将在桌面创建快捷方式,这里做一些调整。快捷方式不建议固定到开始菜单中,因为本快捷方式只是一种启动器。不具有其余磁贴功能。</p>
|
||||
<div>
|
||||
<div>
|
||||
<div class="win-radio"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -32,6 +32,7 @@
|
||||
}
|
||||
|
||||
.appitem div[role=img] {
|
||||
position: relative;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background-color: #464646;
|
||||
@@ -58,6 +59,16 @@
|
||||
transition: all 0.3s cubic-bezier(0.1, 0.9, 0.2, 1);
|
||||
}
|
||||
|
||||
.appitem div[role=img]::after {
|
||||
border: 1px solid rgba(254, 254, 254, 0.1);
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.appitem div[role=img] img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
@@ -113,6 +124,11 @@
|
||||
width: calc(100% - 40px - 10px);
|
||||
}
|
||||
|
||||
.appitem div[role=excepticon] div[role=progress] {
|
||||
display: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.appitem div[role=excepticon] div[role=control] {
|
||||
display: none;
|
||||
/* IE10 */
|
||||
@@ -136,11 +152,45 @@
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.appitem div[role=excepticon] div[role=progress] {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.appitem.uninstalling,
|
||||
.appitem.selected {
|
||||
height: 119px;
|
||||
background-color: rgba(232, 232, 232, 1);
|
||||
}
|
||||
|
||||
.appitem.uninstalled div[role=excepticon] div[role=progress],
|
||||
.appitem.uninstalling div[role=excepticon] div[role=progress] {
|
||||
display: block;
|
||||
flex: 1 0 auto;
|
||||
-ms-flex: 1 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.appitem.uninstalling div[role=excepticon] div[role=progress] progress {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.appitem.uninstalled div[role=excepticon] div[role=progress] progress {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.appitem.uninstalling div[role=excepticon] div[role=progress],
|
||||
.appitem.uninstalled div[role=excepticon] div[role=progress],
|
||||
.appitem.uninstalling div[role=excepticon] div[role=progress] .status,
|
||||
.appitem.uninstalled div[role=excepticon] div[role=progress] .status {
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.appitem.uninstalled {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.appitem.selected div[role=excepticon] div[role=control] {
|
||||
display: flex;
|
||||
display: -ms-flexbox;
|
||||
@@ -148,6 +198,23 @@
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.appitem.uninstalling div[role=excepticon] div[role=advance],
|
||||
.appitem.uninstalling div[role=excepticon] div[role=control],
|
||||
.appitem.uninstalling.selected div[role=excepticon] div[role=advance],
|
||||
.appitem.uninstalling.selected div[role=excepticon] div[role=control],
|
||||
.appitem.uninstalled div[role=excepticon] div[role=advance],
|
||||
.appitem.uninstalled div[role=excepticon] div[role=control],
|
||||
.appitem.uninstalled.selected div[role=excepticon] div[role=advance],
|
||||
.appitem.uninstalled.selected div[role=excepticon] div[role=control] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.appitem.uninstalling div[role=excepticon] div[role=title],
|
||||
.appitem.uninstalled div[role=excepticon] div[role=title] {
|
||||
-ms-flex: none;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
ul.appitem-list,
|
||||
ul.appitem-list li {
|
||||
margin: 0;
|
||||
@@ -169,6 +236,11 @@ ul.appitem-list li {
|
||||
}
|
||||
|
||||
.app-loading {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.app-loading .container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
@@ -176,7 +248,17 @@ ul.appitem-list li {
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
/*****/
|
||||
display: -ms-flexbox;
|
||||
/* IE10 */
|
||||
-ms-flex-direction: row;
|
||||
/* flex-direction: row */
|
||||
-ms-flex-wrap: wrap;
|
||||
/* flex-wrap: wrap */
|
||||
-ms-flex-pack: start;
|
||||
/* justify-content: flex-start */
|
||||
-ms-flex-align: center;
|
||||
/* align-items: center */
|
||||
}
|
||||
|
||||
.app-loading.noloading progress {
|
||||
@@ -204,6 +286,13 @@ ul.appitem-list li {
|
||||
height: 67px;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
display: -ms-flexbox;
|
||||
-ms-flex-direction: row;
|
||||
/* flex-direction: row */
|
||||
-ms-flex-wrap: nowrap;
|
||||
/* flex-wrap: nowrap */
|
||||
-ms-flex-pack: start;
|
||||
/* justify-content: flex-start */
|
||||
}
|
||||
|
||||
.app-detailpage header .win-backbutton {
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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">O‘ch</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">På</lang>
|
||||
<lang name="ne-NP">खोल्नुहोस्</lang>
|
||||
<lang name="nl-NL">Aan</lang>
|
||||
<lang name="nn-NO">På</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">På</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">Açı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">O‘ch</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">På</lang>
|
||||
<lang name="ne-NP">खोल्नुहोस्</lang>
|
||||
<lang name="nl-NL">Aan</lang>
|
||||
<lang name="nn-NO">På</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">På</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">Açı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>
|
||||
Reference in New Issue
Block a user