diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.ps1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.ps1 new file mode 100644 index 00000000..861a3bc6 --- /dev/null +++ b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.ps1 @@ -0,0 +1,750 @@ +# +# Add-AppxDevPackage.ps1 is a PowerShell script designed to install app +# packages created by Visual Studio for developers. To run this script from +# Explorer, right-click on its icon and choose "Run with PowerShell". +# +# Visual Studio supplies this script in the folder generated with its +# "Prepare Package" command. The same folder will also contain the app +# package (a .appx file), the signing certificate (a .cer file), and a +# "Dependencies" subfolder containing all the framework packages used by the +# app. +# +# This script simplifies installing these packages by automating the +# following functions: +# 1. Find the app package and signing certificate in the script directory +# 2. Prompt the user to acquire a developer license and to install the +# certificate if necessary +# 3. Find dependency packages that are applicable to the operating system's +# CPU architecture +# 4. Install the package along with all applicable dependencies +# +# All command line parameters are reserved for use internally by the script. +# Users should launch this script from Explorer. +# + +# .Link +# http://go.microsoft.com/fwlink/?LinkId=243053 + +param( + [switch]$Force = $false, + [switch]$GetDeveloperLicense = $false, + [string]$CertificatePath = $null +) + +$ErrorActionPreference = "Stop" + +# The language resources for this script are placed in the +# "Add-AppDevPackage.resources" subfolder alongside the script. Since the +# current working directory might not be the directory that contains the +# script, we need to create the full path of the resources directory to +# pass into Import-LocalizedData +$ScriptPath = $null +try +{ + $ScriptPath = (Get-Variable MyInvocation).Value.MyCommand.Path + $ScriptDir = Split-Path -Parent $ScriptPath +} +catch {} + +if (!$ScriptPath) +{ + PrintMessageAndExit $UiStrings.ErrorNoScriptPath $ErrorCodes.NoScriptPath +} + +$LocalizedResourcePath = Join-Path $ScriptDir "Add-AppDevPackage.resources" +Import-LocalizedData -BindingVariable UiStrings -BaseDirectory $LocalizedResourcePath + +$ErrorCodes = Data { + ConvertFrom-StringData @' + Success = 0 + NoScriptPath = 1 + NoPackageFound = 2 + ManyPackagesFound = 3 + NoCertificateFound = 4 + ManyCertificatesFound = 5 + BadCertificate = 6 + PackageUnsigned = 7 + CertificateMismatch = 8 + ForceElevate = 9 + LaunchAdminFailed = 10 + GetDeveloperLicenseFailed = 11 + InstallCertificateFailed = 12 + AddPackageFailed = 13 + ForceDeveloperLicense = 14 + CertUtilInstallFailed = 17 + CertIsCA = 18 + BannedEKU = 19 + NoBasicConstraints = 20 + NoCodeSigningEku = 21 + InstallCertificateCancelled = 22 + BannedKeyUsage = 23 + ExpiredCertificate = 24 +'@ +} + +function PrintMessageAndExit($ErrorMessage, $ReturnCode) +{ + Write-Host $ErrorMessage + if (!$Force) + { + Pause + } + exit $ReturnCode +} + +# +# Warns the user about installing certificates, and presents a Yes/No prompt +# to confirm the action. The default is set to No. +# +function ConfirmCertificateInstall +{ + $Answer = $host.UI.PromptForChoice( + "", + $UiStrings.WarningInstallCert, + [System.Management.Automation.Host.ChoiceDescription[]]@($UiStrings.PromptYesString, $UiStrings.PromptNoString), + 1) + + return $Answer -eq 0 +} + +# +# Validates whether a file is a valid certificate using CertUtil. +# This needs to be done before calling Get-PfxCertificate on the file, otherwise +# the user will get a cryptic "Password: " prompt for invalid certs. +# +function ValidateCertificateFormat($FilePath) +{ + # certutil -verify prints a lot of text that we don't need, so it's redirected to $null here + certutil.exe -verify $FilePath > $null + if ($LastExitCode -lt 0) + { + PrintMessageAndExit ($UiStrings.ErrorBadCertificate -f $FilePath, $LastExitCode) $ErrorCodes.BadCertificate + } + + # Check if certificate is expired + $cert = Get-PfxCertificate $FilePath + if (($cert.NotBefore -gt (Get-Date)) -or ($cert.NotAfter -lt (Get-Date))) + { + PrintMessageAndExit ($UiStrings.ErrorExpiredCertificate -f $FilePath) $ErrorCodes.ExpiredCertificate + } +} + +# +# Verify that the developer certificate meets the following restrictions: +# - The certificate must contain a Basic Constraints extension, and its +# Certificate Authority (CA) property must be false. +# - The certificate's Key Usage extension must be either absent, or set to +# only DigitalSignature. +# - The certificate must contain an Extended Key Usage (EKU) extension with +# Code Signing usage. +# - The certificate must NOT contain any other EKU except Code Signing and +# Lifetime Signing. +# +# These restrictions are enforced to decrease security risks that arise from +# trusting digital certificates. +# +function CheckCertificateRestrictions +{ + Set-Variable -Name BasicConstraintsExtensionOid -Value "2.5.29.19" -Option Constant + Set-Variable -Name KeyUsageExtensionOid -Value "2.5.29.15" -Option Constant + Set-Variable -Name EkuExtensionOid -Value "2.5.29.37" -Option Constant + Set-Variable -Name CodeSigningEkuOid -Value "1.3.6.1.5.5.7.3.3" -Option Constant + Set-Variable -Name LifetimeSigningEkuOid -Value "1.3.6.1.4.1.311.10.3.13" -Option Constant + + $CertificateExtensions = (Get-PfxCertificate $CertificatePath).Extensions + $HasBasicConstraints = $false + $HasCodeSigningEku = $false + + foreach ($Extension in $CertificateExtensions) + { + # Certificate must contain the Basic Constraints extension + if ($Extension.oid.value -eq $BasicConstraintsExtensionOid) + { + # CA property must be false + if ($Extension.CertificateAuthority) + { + PrintMessageAndExit $UiStrings.ErrorCertIsCA $ErrorCodes.CertIsCA + } + $HasBasicConstraints = $true + } + + # If key usage is present, it must be set to digital signature + elseif ($Extension.oid.value -eq $KeyUsageExtensionOid) + { + if ($Extension.KeyUsages -ne "DigitalSignature") + { + PrintMessageAndExit ($UiStrings.ErrorBannedKeyUsage -f $Extension.KeyUsages) $ErrorCodes.BannedKeyUsage + } + } + + elseif ($Extension.oid.value -eq $EkuExtensionOid) + { + # Certificate must contain the Code Signing EKU + $EKUs = $Extension.EnhancedKeyUsages.Value + if ($EKUs -contains $CodeSigningEkuOid) + { + $HasCodeSigningEKU = $True + } + + # EKUs other than code signing and lifetime signing are not allowed + foreach ($EKU in $EKUs) + { + if ($EKU -ne $CodeSigningEkuOid -and $EKU -ne $LifetimeSigningEkuOid) + { + PrintMessageAndExit ($UiStrings.ErrorBannedEKU -f $EKU) $ErrorCodes.BannedEKU + } + } + } + } + + if (!$HasBasicConstraints) + { + PrintMessageAndExit $UiStrings.ErrorNoBasicConstraints $ErrorCodes.NoBasicConstraints + } + if (!$HasCodeSigningEKU) + { + PrintMessageAndExit $UiStrings.ErrorNoCodeSigningEku $ErrorCodes.NoCodeSigningEku + } +} + +# +# Performs operations that require administrative privileges: +# - Prompt the user to obtain a developer license +# - Install the developer certificate (if -Force is not specified, also prompts the user to confirm) +# +function DoElevatedOperations +{ + if ($GetDeveloperLicense) + { + Write-Host $UiStrings.GettingDeveloperLicense + + if ($Force) + { + PrintMessageAndExit $UiStrings.ErrorForceDeveloperLicense $ErrorCodes.ForceDeveloperLicense + } + try + { + Show-WindowsDeveloperLicenseRegistration + } + catch + { + $Error[0] # Dump details about the last error + PrintMessageAndExit $UiStrings.ErrorGetDeveloperLicenseFailed $ErrorCodes.GetDeveloperLicenseFailed + } + } + + if ($CertificatePath) + { + Write-Host $UiStrings.InstallingCertificate + + # Make sure certificate format is valid and usage constraints are followed + ValidateCertificateFormat $CertificatePath + CheckCertificateRestrictions + + # If -Force is not specified, warn the user and get consent + if ($Force -or (ConfirmCertificateInstall)) + { + # Add cert to store + certutil.exe -addstore TrustedPeople $CertificatePath + if ($LastExitCode -lt 0) + { + PrintMessageAndExit ($UiStrings.ErrorCertUtilInstallFailed -f $LastExitCode) $ErrorCodes.CertUtilInstallFailed + } + } + else + { + PrintMessageAndExit $UiStrings.ErrorInstallCertificateCancelled $ErrorCodes.InstallCertificateCancelled + } + } +} + +# +# Checks whether the machine is missing a valid developer license. +# +function CheckIfNeedDeveloperLicense +{ + $Result = $true + try + { + $Result = (Get-WindowsDeveloperLicense | Where-Object { $_.IsValid } | Measure-Object).Count -eq 0 + } + catch {} + + return $Result +} + +# +# Launches an elevated process running the current script to perform tasks +# that require administrative privileges. This function waits until the +# elevated process terminates, and checks whether those tasks were successful. +# +function LaunchElevated +{ + # Set up command line arguments to the elevated process + $RelaunchArgs = '-ExecutionPolicy Unrestricted -file "' + $ScriptPath + '"' + + if ($Force) + { + $RelaunchArgs += ' -Force' + } + if ($NeedDeveloperLicense) + { + $RelaunchArgs += ' -GetDeveloperLicense' + } + if ($NeedInstallCertificate) + { + $RelaunchArgs += ' -CertificatePath "' + $DeveloperCertificatePath.FullName + '"' + } + + # Launch the process and wait for it to finish + try + { + $AdminProcess = Start-Process "$PsHome\PowerShell.exe" -Verb RunAs -ArgumentList $RelaunchArgs -PassThru + } + catch + { + $Error[0] # Dump details about the last error + PrintMessageAndExit $UiStrings.ErrorLaunchAdminFailed $ErrorCodes.LaunchAdminFailed + } + + while (!($AdminProcess.HasExited)) + { + Start-Sleep -Seconds 2 + } + + # Check if all elevated operations were successful + if ($NeedDeveloperLicense) + { + if (CheckIfNeedDeveloperLicense) + { + PrintMessageAndExit $UiStrings.ErrorGetDeveloperLicenseFailed $ErrorCodes.GetDeveloperLicenseFailed + } + else + { + Write-Host $UiStrings.AcquireLicenseSuccessful + } + } + if ($NeedInstallCertificate) + { + $Signature = Get-AuthenticodeSignature $DeveloperPackagePath -Verbose + if ($Signature.Status -ne "Valid") + { + PrintMessageAndExit ($UiStrings.ErrorInstallCertificateFailed -f $Signature.Status) $ErrorCodes.InstallCertificateFailed + } + else + { + Write-Host $UiStrings.InstallCertificateSuccessful + } + } +} + +# +# Finds all applicable dependency packages according to OS architecture, and +# installs the developer package with its dependencies. The expected layout +# of dependencies is: +# +# +# \Dependencies +# .appx +# \x86 +# .appx +# \x64 +# .appx +# \arm +# .appx +# +function InstallPackageWithDependencies +{ + $DependencyPackagesDir = (Join-Path $ScriptDir "Dependencies") + $DependencyPackages = @() + if (Test-Path $DependencyPackagesDir) + { + # Get architecture-neutral dependencies + $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "*.appx") | Where-Object { $_.Mode -NotMatch "d" } + + # Get architecture-specific dependencies + if (($Env:Processor_Architecture -eq "x86" -or $Env:Processor_Architecture -eq "amd64") -and (Test-Path (Join-Path $DependencyPackagesDir "x86"))) + { + $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "x86\*.appx") | Where-Object { $_.Mode -NotMatch "d" } + } + if (($Env:Processor_Architecture -eq "amd64") -and (Test-Path (Join-Path $DependencyPackagesDir "x64"))) + { + $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "x64\*.appx") | Where-Object { $_.Mode -NotMatch "d" } + } + if (($Env:Processor_Architecture -eq "arm") -and (Test-Path (Join-Path $DependencyPackagesDir "arm"))) + { + $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "arm\*.appx") | Where-Object { $_.Mode -NotMatch "d" } + } + } + Write-Host $UiStrings.InstallingPackage + + $AddPackageSucceeded = $False + try + { + if ($DependencyPackages.FullName.Count -gt 0) + { + Write-Host $UiStrings.DependenciesFound + $DependencyPackages.FullName + Add-AppxPackage -Path $DeveloperPackagePath.FullName -DependencyPath $DependencyPackages.FullName -ForceApplicationShutdown + } + else + { + Add-AppxPackage -Path $DeveloperPackagePath.FullName -ForceApplicationShutdown + } + $AddPackageSucceeded = $? + } + catch + { + $Error[0] # Dump details about the last error + } + + if (!$AddPackageSucceeded) + { + if ($NeedInstallCertificate) + { + PrintMessageAndExit $UiStrings.ErrorAddPackageFailedWithCert $ErrorCodes.AddPackageFailed + } + else + { + PrintMessageAndExit $UiStrings.ErrorAddPackageFailed $ErrorCodes.AddPackageFailed + } + } +} + +# +# Main script logic when the user launches the script without parameters. +# +function DoStandardOperations +{ + # List all .appx files in the script directory + $PackagePath = Get-ChildItem (Join-Path $ScriptDir "*.appx") | Where-Object { $_.Mode -NotMatch "d" } + $PackageCount = ($PackagePath | Measure-Object).Count + + # List all .appxbundle files in the script directory + $BundlePath = Get-ChildItem (Join-Path $ScriptDir "*.appxbundle") | Where-Object { $_.Mode -NotMatch "d" } + $BundleCount = ($BundlePath | Measure-Object).Count + + # List all .eappx files in the script directory + $EncryptedPackagePath = Get-ChildItem (Join-Path $ScriptDir "*.eappx") | Where-Object { $_.Mode -NotMatch "d" } + $EncryptedPackageCount = ($EncryptedPackagePath | Measure-Object).Count + + # List all .eappxbundle files in the script directory + $EncryptedBundlePath = Get-ChildItem (Join-Path $ScriptDir "*.eappxbundle") | Where-Object { $_.Mode -NotMatch "d" } + $EncryptedBundleCount = ($EncryptedBundlePath | Measure-Object).Count + + $NumberOfPackagesAndBundles = $PackageCount + $BundleCount + $EncryptedPackageCount + $EncryptedBundleCount + + # There must be exactly 1 package/bundle + if ($NumberOfPackagesAndBundles -lt 1) + { + PrintMessageAndExit $UiStrings.ErrorNoPackageFound $ErrorCodes.NoPackageFound + } + elseif ($NumberOfPackagesAndBundles -gt 1) + { + PrintMessageAndExit $UiStrings.ErrorManyPackagesFound $ErrorCodes.ManyPackagesFound + } + + if ($PackageCount -eq 1) + { + $DeveloperPackagePath = $PackagePath + Write-Host ($UiStrings.PackageFound -f $DeveloperPackagePath.FullName) + } + elseif ($BundleCount -eq 1) + { + $DeveloperPackagePath = $BundlePath + Write-Host ($UiStrings.BundleFound -f $DeveloperPackagePath.FullName) + } + elseif ($EncryptedPackageCount -eq 1) + { + $DeveloperPackagePath = $EncryptedPackagePath + Write-Host ($UiStrings.EncryptedPackageFound -f $DeveloperPackagePath.FullName) + } + elseif ($EncryptedBundleCount -eq 1) + { + $DeveloperPackagePath = $EncryptedBundlePath + Write-Host ($UiStrings.EncryptedBundleFound -f $DeveloperPackagePath.FullName) + } + + # The package must be signed + $PackageSignature = Get-AuthenticodeSignature $DeveloperPackagePath + $PackageCertificate = $PackageSignature.SignerCertificate + if (!$PackageCertificate) + { + PrintMessageAndExit $UiStrings.ErrorPackageUnsigned $ErrorCodes.PackageUnsigned + } + + # Test if the package signature is trusted. If not, the corresponding certificate + # needs to be present in the current directory and needs to be installed. + $NeedInstallCertificate = ($PackageSignature.Status -ne "Valid") + + if ($NeedInstallCertificate) + { + # List all .cer files in the script directory + $DeveloperCertificatePath = Get-ChildItem (Join-Path $ScriptDir "*.cer") | Where-Object { $_.Mode -NotMatch "d" } + $DeveloperCertificateCount = ($DeveloperCertificatePath | Measure-Object).Count + + # There must be exactly 1 certificate + if ($DeveloperCertificateCount -lt 1) + { + PrintMessageAndExit $UiStrings.ErrorNoCertificateFound $ErrorCodes.NoCertificateFound + } + elseif ($DeveloperCertificateCount -gt 1) + { + PrintMessageAndExit $UiStrings.ErrorManyCertificatesFound $ErrorCodes.ManyCertificatesFound + } + + Write-Host ($UiStrings.CertificateFound -f $DeveloperCertificatePath.FullName) + + # The .cer file must have the format of a valid certificate + ValidateCertificateFormat $DeveloperCertificatePath + + # The package signature must match the certificate file + if ($PackageCertificate -ne (Get-PfxCertificate $DeveloperCertificatePath)) + { + PrintMessageAndExit $UiStrings.ErrorCertificateMismatch $ErrorCodes.CertificateMismatch + } + } + + $NeedDeveloperLicense = CheckIfNeedDeveloperLicense + + # Relaunch the script elevated with the necessary parameters if needed + if ($NeedDeveloperLicense -or $NeedInstallCertificate) + { + Write-Host $UiStrings.ElevateActions + if ($NeedDeveloperLicense) + { + Write-Host $UiStrings.ElevateActionDevLicense + } + if ($NeedInstallCertificate) + { + Write-Host $UiStrings.ElevateActionCertificate + } + + $IsAlreadyElevated = ([Security.Principal.WindowsIdentity]::GetCurrent().Groups.Value -contains "S-1-5-32-544") + if ($IsAlreadyElevated) + { + if ($Force -and $NeedDeveloperLicense) + { + PrintMessageAndExit $UiStrings.ErrorForceDeveloperLicense $ErrorCodes.ForceDeveloperLicense + } + if ($Force -and $NeedInstallCertificate) + { + Write-Warning $UiStrings.WarningInstallCert + } + } + else + { + if ($Force) + { + PrintMessageAndExit $UiStrings.ErrorForceElevate $ErrorCodes.ForceElevate + } + else + { + Write-Host $UiStrings.ElevateActionsContinue + Pause + } + } + + LaunchElevated + } + + InstallPackageWithDependencies +} + +# +# Main script entry point +# +if ($GetDeveloperLicense -or $CertificatePath) +{ + DoElevatedOperations +} +else +{ + DoStandardOperations + PrintMessageAndExit $UiStrings.Success $ErrorCodes.Success +} + +# SIG # Begin signature block +# MIIiBQYJKoZIhvcNAQcCoIIh9jCCIfICAQExDzANBglghkgBZQMEAgEFADB5Bgor +# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAnYmBUpv/sjF9s +# UpSJeaz8bsgho4m0HYf/wsPXcJL9raCCC4QwggUMMIID9KADAgECAhMzAAABT+fG +# YslG9Kl/AAAAAAFPMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD +# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy +# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p +# bmcgUENBIDIwMTAwHhcNMTYxMTE3MjE1OTE0WhcNMTgwMjE3MjE1OTE0WjCBgzEL +# MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v +# bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjENMAsGA1UECxMETU9Q +# UjEeMBwGA1UEAxMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMIIBIjANBgkqhkiG9w0B +# AQEFAAOCAQ8AMIIBCgKCAQEAtImQinYMrMU9obyB6NdQCLtaaaeux8y4W704DyFR +# Rggj0b0imXO3KO/3B6sr+Uj3pRQFqU0kG21hlpyDnTPALHmZ8F3z7NVE36XNWfp2 +# rQY/xkoD5uotlBDCZm/9YtBQitEikSOXZTShxJoCXpLiuHwoeMJe40b3yu84V4is +# VgZYypgbx6jXXjaumkUw47a3PRjCpyeweU1T2DLmdqNQKvY/urtBHiSGTZibep72 +# LOK8kGBl+5Zp+uATaOKJKi51GJ3Cbbgh9JleKn8xoKcNzO9PEW7+SUJOYd43yyue +# QO/Oq15wCHOlcnu3Rs5bMlNdijlRb7DXqHjdoyhvXu5CHwIDAQABo4IBezCCAXcw +# HwYDVR0lBBgwFgYKKwYBBAGCNz0GAQYIKwYBBQUHAwMwHQYDVR0OBBYEFJIOoRFx +# ti9VDcMP9MlcdC5aDGq/MFIGA1UdEQRLMEmkRzBFMQ0wCwYDVQQLEwRNT1BSMTQw +# MgYDVQQFEysyMzA4NjUrYjRiMTI4NzgtZTI5My00M2U5LWIyMWUtN2QzMDcxOWQ0 +# NTJmMB8GA1UdIwQYMBaAFOb8X3u7IgBY5HJOtfQhdCMy5u+sMFYGA1UdHwRPME0w +# S6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3Rz +# L01pY0NvZFNpZ1BDQV8yMDEwLTA3LTA2LmNybDBaBggrBgEFBQcBAQROMEwwSgYI +# KwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWlj +# Q29kU2lnUENBXzIwMTAtMDctMDYuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN +# AQELBQADggEBABHAuWpDNf6FsTiADbh0dSyNcUm4PEHtLb3iBjaQdiuJ5baB6Ybj +# GIyWkzJCp6f2tzQlOdDGekPq23dwzNTpQuuoxVUCdXie2BC+BxvKlGP7PA9x7tRV +# Z9cp9mq/B7zlj4Lq+KHiczM/FJJeobplVzdFhYBc1izGizxqh6MHEcvs2XE4IDUk +# PVS9zFWJ9HcQm+WZqg+uxjyOn9oAT8994bPAIPdSMfciSNVhjX8mAhl9g8xhkyrd +# uNziCLOn3+EEd2DI9Kw1yzHlbHVRxTd7E2pOlWuPQJ7ITT6uvVnFINbCeK23ZFs7 +# 0MAVcDQU5cWephzH9P/2y0jB4o3zbs6qtKAwggZwMIIEWKADAgECAgphDFJMAAAA +# AAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz +# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv +# cnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBB +# dXRob3JpdHkgMjAxMDAeFw0xMDA3MDYyMDQwMTdaFw0yNTA3MDYyMDUwMTdaMH4x +# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt +# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p +# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTAwggEiMA0GCSqGSIb3DQEBAQUA +# A4IBDwAwggEKAoIBAQDpDmRQeWe1xOP9CQBMnpSs91Zo6kTYz8VYT6mldnxtRbrT +# OZK0pB75+WWC5BfSj/1EnAjoZZPOLFWEv30I4y4rqEErGLeiS25JTGsVB97R0sKJ +# HnGUzbV/S7SvCNjMiNZrF5Q6k84mP+zm/jSYV9UdXUn2siou1YW7WT/4kLQrg3TK +# K7M7RuPwRknBF2ZUyRy9HcRVYldy+Ge5JSA03l2mpZVeqyiAzdWynuUDtWPTshTI +# wciKJgpZfwfs/w7tgBI1TBKmvlJb9aba4IsLSHfWhUfVELnG6Krui2otBVxgxrQq +# W5wjHF9F4xoUHm83yxkzgGqJTaNqZmN4k9Uwz5UfAgMBAAGjggHjMIIB3zAQBgkr +# BgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU5vxfe7siAFjkck619CF0IzLm76wwGQYJ +# KwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +# MAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8w +# TTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVj +# dHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBK +# BggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9N +# aWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwgZ0GA1UdIASBlTCBkjCBjwYJKwYB +# BAGCNy4DMIGBMD0GCCsGAQUFBwIBFjFodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20v +# UEtJL2RvY3MvQ1BTL2RlZmF1bHQuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBn +# AGEAbABfAFAAbwBsAGkAYwB5AF8AUwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqG +# SIb3DQEBCwUAA4ICAQAadO9XTyl7xBaFeLhQ0yL8CZ2sgpf4NP8qLJeVEuXkv8+/ +# k8jjNKnbgbjcHgC+0jVvr+V/eZV35QLU8evYzU4eG2GiwlojGvCMqGJRRWcI4z88 +# HpP4MIUXyDlAptcOsyEp5aWhaYwik8x0mOehR0PyU6zADzBpf/7SJSBtb2HT3wfV +# 2XIALGmGdj1R26Y5SMk3YW0H3VMZy6fWYcK/4oOrD+Brm5XWfShRsIlKUaSabMi3 +# H0oaDmmp19zBftFJcKq2rbtyR2MX+qbWoqaG7KgQRJtjtrJpiQbHRoZ6GD/oxR0h +# 1Xv5AiMtxUHLvx1MyBbvsZx//CJLSYpuFeOmf3Zb0VN5kYWd1dLbPXM18zyuVLJS +# R2rAqhOV0o4R2plnXjKM+zeF0dx1hZyHxlpXhcK/3Q2PjJst67TuzyfTtV5p+qQW +# BAGnJGdzz01Ptt4FVpd69+lSTfR3BU+FxtgL8Y7tQgnRDXbjI1Z4IiY2vsqxjG6q +# HeSF2kczYo+kyZEzX3EeQK+YZcki6EIhJYocLWDZN4lBiSoWD9dhPJRoYFLv1keZ +# oIBA7hWBdz6c4FMYGlAdOJWbHmYzEyc5F3iHNs5Ow1+y9T1HU7bg5dsLYT0q15Is +# zjdaPkBCMaQfEAjCVpy/JF1RAp1qedIX09rBlI4HeyVxRKsGaubUxt8jmpZ1xTGC +# FdcwghXTAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u +# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp +# b24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTACEzMA +# AAFP58ZiyUb0qX8AAAAAAU8wDQYJYIZIAWUDBAIBBQCggcIwGQYJKoZIhvcNAQkD +# MQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJ +# KoZIhvcNAQkEMSIEIM6sGgl9EI3BKHGPaKRgrF1O/bVv8y7tQZuqLVzy8rFiMFYG +# CisGAQQBgjcCAQwxSDBGoCyAKgBBAGQAZAAtAEEAcABwAEQAZQB2AFAAYQBjAGsA +# YQBnAGUALgBwAHMAMaEWgBRodHRwOi8vbWljcm9zb2Z0LmNvbTANBgkqhkiG9w0B +# AQEFAASCAQB+h3AYSy8MV5bb3ZfjI9xGXZgMGVKhmRo9yYG3wIelD9RULoRtCN4J +# ScCz++xjjxhUEdJ57ZeRdobQGnjEKyepHccHJsnxiFXUqd8gHWN56LxVKXLK6lgH +# RnSmMm63Z/s6/qA7XdgHKjUGqG0MsZgFiX0DBfVQUQnPPPgkicc2xwWI1G4ZTDVn +# Qoi9zUNb1bvJJhcN1BlPcvKVrVOqBLLfsSDsYGMmLcrh0v9QkMPBefLexqGxoibs +# fvzJiwiCSRTRiC29aUrAP3s6EazYYP866d7F94qZfF5Qy8fy3RnnjErxD1PpgEVx +# EZus2pc23sNrQzNokH1A7q3beEKTKal8oYITTTCCE0kGCisGAQQBgjcDAwExghM5 +# MIITNQYJKoZIhvcNAQcCoIITJjCCEyICAQMxDzANBglghkgBZQMEAgEFADCCAT0G +# CyqGSIb3DQEJEAEEoIIBLASCASgwggEkAgEBBgorBgEEAYRZCgMBMDEwDQYJYIZI +# AWUDBAIBBQAEIJPdm/WIYp5J5+KJJMbxhHziKQ+l8HJ9bF3jCZXkxTgaAgZY1UYJ +# UwIYEzIwMTcwNDIwMDAzMzU5LjY0NFowBwIBAYACAfSggbmkgbYwgbMxCzAJBgNV +# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w +# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIxJzAl +# BgNVBAsTHm5DaXBoZXIgRFNFIEVTTjpCOEVDLTMwQTQtNzE0NDElMCMGA1UEAxMc +# TWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaCCDtAwggZxMIIEWaADAgECAgph +# CYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE +# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z +# b2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZp +# Y2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3MDEyMTQ2 +# NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH +# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV +# BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkqhkiG9w0B +# AQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWlCgCChfvt +# fGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/FgiIRUQwzX +# Tbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeRX4FUsc+T +# TJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/XcfPfBXday9 +# ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogINeh4HLDp +# mc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB5jCCAeIw +# EAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvFM2hahW1V +# MBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMB +# Af8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1Ud +# HwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3By +# b2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcBAQRO +# MEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2Vy +# dHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8EgZUwgZIw +# gY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5taWNyb3Nv +# ZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcCAjA0HjIg +# HQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUAbgB0AC4g +# HTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Prpsz1Mb7P +# BeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOMzPRgEop2 +# zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCvOA8X9S95 +# gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v/rbljjO7 +# Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99lmqQeKZt +# 0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1klD3ouOVd2 +# onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQHm+98eEA +# 3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30uIUBHoD7 +# G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp25ayp0Ki +# yc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HSxVXjad5X +# wdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi62jbb01+P +# 3nSISRIwggTaMIIDwqADAgECAhMzAAAAn2fytagjBlt7AAAAAACfMA0GCSqGSIb3 +# DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD +# VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAk +# BgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTE2MDkwNzE3 +# NTY0N1oXDTE4MDkwNzE3NTY0N1owgbMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX +# YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg +# Q29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIxJzAlBgNVBAsTHm5DaXBoZXIgRFNF +# IEVTTjpCOEVDLTMwQTQtNzE0NDElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3Rh +# bXAgU2VydmljZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALkI8SOc +# 3cQCLwKFoaMnl2T5A5wSVD9Tglq4Put9bhjFcsEn1XApDPCWS9aPhMcWOWKe+7EN +# I4Si4zD30nVQC9PZ0NDu+pK9XV83OfjGchFkKzOBRddOhpsQkxFgMF3RfLTNXAEq +# ffnNaReXwtVUkiGEJvW6KmABixzP0aeUVmJ6MHnJnmo+TKZdoVl7cg6TY6LCoze/ +# F6rhOXmi/P3X/K3jHtmAaxL9Ou53jjDgO5Rjxt6ZEamdEsGF2SWZ6wH6Dmg9G6iZ +# Pxgw+mjODwReL6jwh7H2XhsvzoFMrSERMzIIf2eJGAM9C0GR0BZHyRti17QqL5Ta +# CuWPjMxTKXX4DlkCAwEAAaOCARswggEXMB0GA1UdDgQWBBT9ixsiw30jR3amHt/g +# ZtRS6bb5oDAfBgNVHSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8E +# TzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9k +# dWN0cy9NaWNUaW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBM +# MEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRz +# L01pY1RpbVN0YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1Ud +# JQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IBAQBlEMFsa88VHq8PSDbr +# 3y0LvAAA5pFmGlCWZbkxD2WMqfF0y8fnlvgb874z8sz8QZzByCmY1jHyHTc98Zek +# z7L2Y5SANUIa8jyU36c64Ck5fY6Pe9hUA1RG/1zP+eq080chUPCF2zezhfwuz9Ob +# 0obO64BwW0GZgYYz1hjsq+DBkSCBRV59ryFpzgKRwhWF8quXtHDpimiJx+ds2VZS +# wEVk/QRY7pLuUvedN8P5DNuLaaRw3oJcs2Wxh2jWS5T8Y3JevUo3K3VTtHPi2IBW +# ISkEG7TOnNEUcUXDMGSOeZ27kuPFzKkDVbtzvwEVepkGrsZ1W+1xuDYPQ1b3BMG8 +# C79HoYIDeTCCAmECAQEwgeOhgbmkgbYwgbMxCzAJBgNVBAYTAlVTMRMwEQYDVQQI +# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv +# ZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIxJzAlBgNVBAsTHm5DaXBoZXIg +# RFNFIEVTTjpCOEVDLTMwQTQtNzE0NDElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt +# U3RhbXAgU2VydmljZaIlCgEBMAkGBSsOAwIaBQADFQBs0ycI8vnZqMv5Gd6SS0qt +# 2xmjwaCBwjCBv6SBvDCBuTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0 +# b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh +# dGlvbjENMAsGA1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBOVFMgRVNOOjU3 +# RjYtQzFFMC01NTRDMSswKQYDVQQDEyJNaWNyb3NvZnQgVGltZSBTb3VyY2UgTWFz +# dGVyIENsb2NrMA0GCSqGSIb3DQEBBQUAAgUA3KJ+BDAiGA8yMDE3MDQyMDAwMjMz +# MloYDzIwMTcwNDIxMDAyMzMyWjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDcon4E +# AgEAMAoCAQACAgIpAgH/MAcCAQACAhpTMAoCBQDco8+EAgEAMDYGCisGAQQBhFkK +# BAIxKDAmMAwGCisGAQQBhFkKAwGgCjAIAgEAAgMW42ChCjAIAgEAAgMHoSAwDQYJ +# KoZIhvcNAQEFBQADggEBAMNu8xSY3BVCszbhzYVReDYtQq5osuZNWMIQG3z0VMBy +# 2CesXSvJhJ3FRfaH8T1oXKkKtpMKWzYRvoSN2QFLxsrja3QAWFpK+L2tc3SZn0Fh +# oAbA3wrGX+PPZc+7KCe1011rLLU3jpU5p8WyXhoLNc0YpGT3Rf50P+J4mK0NCOQt +# weBieStXSi7fvfxd7AyOnd/Sl/qVXaVWc7RWrHOxwyb3VMgFwPy73WWELCmHmtDa +# zmZE+kX8uwFCweFCTZraxXf/QCZ6S6qxWsUbmgL3og4DWk3KHUFLaXUAJCbYLkv2 +# 9/K2km3/D/pMnEuA97lLPkaTmS2qjPZ6OIwsefeQSvsxggL1MIIC8QIBATCBkzB8 +# MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk +# bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N +# aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAJ9n8rWoIwZbewAAAAAA +# nzANBglghkgBZQMEAgEFAKCCATIwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEE +# MC8GCSqGSIb3DQEJBDEiBCDOKIBEM8xfNhB0LPgIdV4IVpvEHSpJJY1OElQEf/7o +# 8TCB4gYLKoZIhvcNAQkQAgwxgdIwgc8wgcwwgbEEFGzTJwjy+dmoy/kZ3pJLSq3b +# GaPBMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x +# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv +# bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAACf +# Z/K1qCMGW3sAAAAAAJ8wFgQUuddYY/HPCoksb/xOBDjdPXlDGMEwDQYJKoZIhvcN +# AQELBQAEggEAO+i4nAivWpc98DvCdqDpFvPa1+YQ+w4w59An08W8QDzLFvr4nDLz +# SdXYQKnWFQaSI6qf81pe2tHfc4uehs/nbfFRK9CiVi321Ao7B31szkLCLWnClG7l +# Ar+FQv0vFx6cIe2fOZeobsm1GDsiAroe6MGz3wAM4LzuZ3FkO1i9K1RlrBrN+28C +# bjXmHksJHQNMBcGOLbRDrmpfrc6ijKjheepQekxBxfboGc0B57MM+LRIL2GC8mdn +# Q6Iv/mcJnYW1pjLzlnRRqW32fjjKa/iygkVsU+aNrj3XxLU4GyDsV5NWBLl5LJ7z +# dd+w7o1/PK5+wn4z52qQvpLt6luLRdHq9Q== +# SIG # End signature block diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..89c0d417 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/cs-CZ/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/cs-CZ/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..6de68269 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/cs-CZ/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/de-DE/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/de-DE/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..7f8ea728 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/de-DE/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/en-US/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/en-US/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..89c0d417 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/en-US/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/es-ES/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/es-ES/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..25f74983 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/es-ES/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/fr-FR/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/fr-FR/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..8ccf86c7 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/fr-FR/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/it-IT/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/it-IT/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..fbfe178a Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/it-IT/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/ja-JP/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/ja-JP/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..9ccfe666 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/ja-JP/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/ko-KR/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/ko-KR/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..de73c344 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/ko-KR/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/pl-PL/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/pl-PL/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..f73c27b0 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/pl-PL/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/pt-BR/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/pt-BR/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..4abe47c9 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/pt-BR/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/ru-RU/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/ru-RU/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..138c448b Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/ru-RU/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/tr-TR/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/tr-TR/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..4cfe1a8a Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/tr-TR/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/zh-CN/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/zh-CN/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..88c08a20 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/zh-CN/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/zh-TW/Add-AppDevPackage.psd1 b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/zh-TW/Add-AppDevPackage.psd1 new file mode 100644 index 00000000..717ed258 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/Add-AppDevPackage.resources/zh-TW/Add-AppDevPackage.psd1 differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/KiwixWebApp_0.7.8.0_AnyCPU.appxbundle b/AppPackages/KiwixWebApp_0.7.8.0_Test/KiwixWebApp_0.7.8.0_AnyCPU.appxbundle new file mode 100644 index 00000000..7460e88a Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/KiwixWebApp_0.7.8.0_AnyCPU.appxbundle differ diff --git a/AppPackages/KiwixWebApp_0.7.8.0_Test/KiwixWebApp_0.7.8.0_AnyCPU.cer b/AppPackages/KiwixWebApp_0.7.8.0_Test/KiwixWebApp_0.7.8.0_AnyCPU.cer new file mode 100644 index 00000000..8cafb5e4 Binary files /dev/null and b/AppPackages/KiwixWebApp_0.7.8.0_Test/KiwixWebApp_0.7.8.0_AnyCPU.cer differ diff --git a/BundleArtifacts/neutral.txt b/BundleArtifacts/neutral.txt index 7f37384d..f4c524e2 100644 --- a/BundleArtifacts/neutral.txt +++ b/BundleArtifacts/neutral.txt @@ -1,5 +1,5 @@ -MainPackage=C:\Users\geoff\Source\Repos\kiwix-js-windows\bin\Release\KiwixWebApp_0.7.7.0_AnyCPU.appx -ResourcePack=C:\Users\geoff\Source\Repos\kiwix-js-windows\bin\Release\KiwixWebApp_0.7.7.0_scale-100.appx -ResourcePack=C:\Users\geoff\Source\Repos\kiwix-js-windows\bin\Release\KiwixWebApp_0.7.7.0_scale-125.appx -ResourcePack=C:\Users\geoff\Source\Repos\kiwix-js-windows\bin\Release\KiwixWebApp_0.7.7.0_scale-150.appx -ResourcePack=C:\Users\geoff\Source\Repos\kiwix-js-windows\bin\Release\KiwixWebApp_0.7.7.0_scale-400.appx +MainPackage=C:\Users\geoff\Source\Repos\kiwix-js-windows\bin\Release\KiwixWebApp_0.7.8.0_AnyCPU.appx +ResourcePack=C:\Users\geoff\Source\Repos\kiwix-js-windows\bin\Release\KiwixWebApp_0.7.8.0_scale-100.appx +ResourcePack=C:\Users\geoff\Source\Repos\kiwix-js-windows\bin\Release\KiwixWebApp_0.7.8.0_scale-125.appx +ResourcePack=C:\Users\geoff\Source\Repos\kiwix-js-windows\bin\Release\KiwixWebApp_0.7.8.0_scale-150.appx +ResourcePack=C:\Users\geoff\Source\Repos\kiwix-js-windows\bin\Release\KiwixWebApp_0.7.8.0_scale-400.appx diff --git a/bin/Release/AppxManifest.xml b/bin/Release/AppxManifest.xml index 907b64a2..bc3ca432 100644 --- a/bin/Release/AppxManifest.xml +++ b/bin/Release/AppxManifest.xml @@ -7,7 +7,7 @@ For more information on package manifest files, see http://go.microsoft.com/fwlink/?LinkID=241727 --> - + Kiwix JS diff --git a/bin/Release/ForBundle/AppxManifest.xml b/bin/Release/ForBundle/AppxManifest.xml index b6ff118d..e85eef4c 100644 --- a/bin/Release/ForBundle/AppxManifest.xml +++ b/bin/Release/ForBundle/AppxManifest.xml @@ -7,7 +7,7 @@ For more information on package manifest files, see http://go.microsoft.com/fwlink/?LinkID=241727 --> - + Kiwix JS diff --git a/bin/Release/KiwixWebApp.build.appxrecipe b/bin/Release/KiwixWebApp.build.appxrecipe index 4ae1f7d8..4e0b7900 100644 --- a/bin/Release/KiwixWebApp.build.appxrecipe +++ b/bin/Release/KiwixWebApp.build.appxrecipe @@ -376,7 +376,7 @@ www\js\lib\zimfile.js - + resources.pri true diff --git a/bin/Release/KiwixWebApp_0.7.8.0_AnyCPU.appx b/bin/Release/KiwixWebApp_0.7.8.0_AnyCPU.appx new file mode 100644 index 00000000..ed485e1d Binary files /dev/null and b/bin/Release/KiwixWebApp_0.7.8.0_AnyCPU.appx differ diff --git a/bin/Release/KiwixWebApp_0.7.8.0_scale-100.appx b/bin/Release/KiwixWebApp_0.7.8.0_scale-100.appx new file mode 100644 index 00000000..10347c73 Binary files /dev/null and b/bin/Release/KiwixWebApp_0.7.8.0_scale-100.appx differ diff --git a/bin/Release/KiwixWebApp_0.7.8.0_scale-125.appx b/bin/Release/KiwixWebApp_0.7.8.0_scale-125.appx new file mode 100644 index 00000000..0b1685c3 Binary files /dev/null and b/bin/Release/KiwixWebApp_0.7.8.0_scale-125.appx differ diff --git a/bin/Release/KiwixWebApp_0.7.8.0_scale-150.appx b/bin/Release/KiwixWebApp_0.7.8.0_scale-150.appx new file mode 100644 index 00000000..b8052d4a Binary files /dev/null and b/bin/Release/KiwixWebApp_0.7.8.0_scale-150.appx differ diff --git a/bin/Release/KiwixWebApp_0.7.8.0_scale-400.appx b/bin/Release/KiwixWebApp_0.7.8.0_scale-400.appx new file mode 100644 index 00000000..fca78a05 Binary files /dev/null and b/bin/Release/KiwixWebApp_0.7.8.0_scale-400.appx differ diff --git a/bin/Release/ReverseMap/resources.pri b/bin/Release/resources.pri similarity index 56% rename from bin/Release/ReverseMap/resources.pri rename to bin/Release/resources.pri index 8f828639..c953922b 100644 Binary files a/bin/Release/ReverseMap/resources.pri and b/bin/Release/resources.pri differ diff --git a/bld/Release/KiwixWebApp.jsproj.FileListAbsolute.txt b/bld/Release/KiwixWebApp.jsproj.FileListAbsolute.txt index e1291aca..77952dbc 100644 --- a/bld/Release/KiwixWebApp.jsproj.FileListAbsolute.txt +++ b/bld/Release/KiwixWebApp.jsproj.FileListAbsolute.txt @@ -45,4 +45,4 @@ C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\qualifiers.txt C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\qualifiers.txt.intermediate C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\MultipleQualifiersPerDimensionFound.txt C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\ProjectArchitectures.txt -C:\Users\geoff\Source\Repos\kiwix-js-windows\bin\Release\ReverseMap\resources.pri +C:\Users\geoff\Source\Repos\kiwix-js-windows\bin\Release\resources.pri diff --git a/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_AnyCPU.appx b/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_AnyCPU.appx new file mode 100644 index 00000000..ed485e1d Binary files /dev/null and b/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_AnyCPU.appx differ diff --git a/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_scale-100.appx b/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_scale-100.appx new file mode 100644 index 00000000..10347c73 Binary files /dev/null and b/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_scale-100.appx differ diff --git a/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_scale-125.appx b/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_scale-125.appx new file mode 100644 index 00000000..0b1685c3 Binary files /dev/null and b/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_scale-125.appx differ diff --git a/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_scale-150.appx b/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_scale-150.appx new file mode 100644 index 00000000..b8052d4a Binary files /dev/null and b/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_scale-150.appx differ diff --git a/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_scale-400.appx b/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_scale-400.appx new file mode 100644 index 00000000..fca78a05 Binary files /dev/null and b/bld/Release/KiwixWebApp_0.7.8.0_Bundle/KiwixWebApp_0.7.8.0_scale-400.appx differ diff --git a/bld/Release/PackageLayout/www/-/s/css_modules/ext.kartographer.frame.css b/bld/Release/PackageLayout/www/-/s/css_modules/ext.kartographer.frame.css new file mode 100644 index 00000000..d461ce40 --- /dev/null +++ b/bld/Release/PackageLayout/www/-/s/css_modules/ext.kartographer.frame.css @@ -0,0 +1,6 @@ +/** + * Dummy stylesheet + * + * This sheet returns an empty css from the ZIM, so it is included here + * to prevent useless retrieval of empty data. + */ diff --git a/bld/Release/PackageLayout/www/-/s/css_modules/ext.kartographer.link.css b/bld/Release/PackageLayout/www/-/s/css_modules/ext.kartographer.link.css new file mode 100644 index 00000000..d461ce40 --- /dev/null +++ b/bld/Release/PackageLayout/www/-/s/css_modules/ext.kartographer.link.css @@ -0,0 +1,6 @@ +/** + * Dummy stylesheet + * + * This sheet returns an empty css from the ZIM, so it is included here + * to prevent useless retrieval of empty data. + */ diff --git a/bld/Release/PackageLayout/www/-/s/css_modules/ext.kartographer.style.css b/bld/Release/PackageLayout/www/-/s/css_modules/ext.kartographer.style.css new file mode 100644 index 00000000..ad77a044 --- /dev/null +++ b/bld/Release/PackageLayout/www/-/s/css_modules/ext.kartographer.style.css @@ -0,0 +1,560 @@ +/** + * CSS Classes Definitions + * + * .mw-kartographer-maplink: + * Represents a element as output by the Parser. + * May or may not be an interactive link yet (meanwhile JS gets loaded). + * + * .mw-kartographer-map + * Represents a element as output by the Parser. + * May or may not be an interactive map yet (meanwhile JS gets loaded) + * + * .mw-kartographer-link + * Represents an interactive map link. + * The class is added when the element becomes an interactive link. + * May or may not be a or (if created via Developer API) + * + * .mw-kartographer-interactive + * Represents an interactive map. + * The class is added when the element becomes an interactive map. + * + * .mw-kartographer-mapDialog-map + * Represents an interactive map within a full screen map dialog. + * + * .mw-kartographer-static + * Represents an interactive map that was made static afterward because the + * viewport is too small. + * + * In practice: + * + * - will have .mw-kartographer-maplink first, + * .mw-kartographer-link then. + * + * - will have .mw-kartographer-map first, + * .mw-kartographer-link then, if displaying static snapshot. + * .mw-kartographer-interactive then, if directly interactive. + */ +.mw-kartographer-mapDialog-map { + position: absolute; + top: 0; + bottom: 4.11em; + left: 0; + right: 0; + z-index: 1; +} +.mw-kartographer-error { + display: inline-block; + background: #ffc0cb; +} +.mw-kartographer-static .leaflet-control-container .leaflet-top .leaflet-control { + display: none; +} +.mw-kartographer-static .leaflet-control-container .leaflet-top .leaflet-control-static { + display: block; +} +.mw-kartographer-static .leaflet-clickable { + pointer-events: none; +} +.mw-kartographer-static.leaflet-container { + cursor: default; +} +.mw-kartographer-map { + position: relative; + background-position: center; + background-repeat: no-repeat; + background-size: contain; + display: block; + font-size: 14px; +} +.mw-kartographer-map.mw-kartographer-link { + display: block; +} +.mw-kartographer-map.leaflet-container { + background-size: contain; +} +.mw-kartographer-fullScreen { + position: absolute; + top: 10px; + right: 10px; + margin-right: 0; +} +.mw-kartographer-container:not(.mw-kartographer-full) { + max-width: 100%; + /* Fixes `align=center` use case */ +} +.mw-kartographer-container:not(.mw-kartographer-full).center { + margin-left: auto; + margin-right: auto; + display: block; +} +.mw-kartographer-container:not(.mw-kartographer-full).thumb .thumbinner { + max-width: 100%; +} +.mw-kartographer-container:not(.mw-kartographer-full).thumb .thumbinner > .mw-kartographer-map { + width: 100%; +} +.mw-kartographer-container.mw-kartographer-full { + width: 100%; +} +/* @noflip */ +a.floatright { + float: right; + clear: right; + margin: 0 0 1em 1em; +} +/* @noflip */ +a.floatleft { + float: left; + clear: left; + margin: 0.3em 0.5em 0.5em 0; +} + +/* stylelint-disable selector-no-vendor-prefix, at-rule-no-unknown */ +/* stylelint-enable selector-no-vendor-prefix, at-rule-no-unknown */ +/* stylelint-disable no-descending-specificity */ +.mw-kartographer-link, +.mw-kartographer-maplink { + cursor: pointer; +} +.mw-kartographer-maplink:not( .mw-kartographer-autostyled ):not( .mw-kartographer-map ):not( .no-icon ), +a.mw-kartographer-link:not( .mw-kartographer-autostyled ):not( .mw-kartographer-map ):not( .no-icon ) { + /** + * These two files were copied from OOjs UI repository after the build process + * generated the progressive icons. + * + * See ./images/COPYING + * + * The master version of the icon is at: + * https://github.com/wikimedia/oojs-ui/blob/master/src/themes/mediawiki/images/icons/mapPin.svg + */ + background-image: url(/w/extensions/Kartographer/styles/images/mapPin-progressive.png?eaddd); + background-image: linear-gradient(transparent, transparent), url(data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%0A%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cg%20fill%3D%22%2336c%22%3E%0A%20%20%20%20%3Cpath%20d%3D%22M19%2012c0-3.9-3.1-7-7-7s-7%203.1-7%207c0%201.4.4%202.6%201.1%203.7L12%2023l5.9-7.3c.7-1.1%201.1-2.3%201.1-3.7zm-7%203c-1.6%200-3-1.4-3-3s1.4-3%203-3%203%201.4%203%203-1.4%203-3%203z%22%2F%3E%0A%3C%2Fg%3E%3C%2Fsvg%3E%0A); + background-image: -o-linear-gradient(transparent, transparent), url(/w/extensions/Kartographer/styles/images/mapPin-progressive.png?eaddd); + background-position: left -3px; + background-repeat: no-repeat; + background-size: 18px 18px; + padding-left: 19px; + margin-left: 2px; +} +.mw-kartographer-maplink.no-icon, +a.mw-kartographer-link.no-icon { + background: none; + padding-left: 0; + margin-left: 0; +} +.skin-minerva a.mw-kartographer-link:not( .mw-kartographer-autostyled ):not( .mw-kartographer-map ):not( .no-icon ), +.skin-minerva .mw-kartographer-maplink:not( .mw-kartographer-autostyled ):not( .mw-kartographer-map ):not( .no-icon ) { + background-size: 20px 20px; + padding-left: 20px; +} +.skin-minerva a.mw-kartographer-link.no-icon, +.skin-minerva .mw-kartographer-maplink.no-icon { + background: none; + padding-left: 0; + margin-left: 0; +} +.mw-kartographer-map .mw-kartographer-fullScreen .oo-ui-iconElement > .oo-ui-buttonElement-button { + font-size: 0.91428571em; + min-width: 2.5em; +} +.mw-kartographer-map .mw-kartographer-fullScreen .oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon { + left: 0.25em; +} +.mw-kartographer-map:hover .mw-kartographer-fullScreen .oo-ui-buttonElement-button { + background-color: #fff; +} +/** + * Applied only when JS is enabled. + */ +.client-js { + /* stylelint-disable-next-line indentation */ +} +.client-js .mw-kartographer-map { + cursor: pointer; +} +.client-js .mw-kartographer-maplink:not( .mw-kartographer-link ):not( .ve-ce-focusableNode ), +.client-js .mw-kartographer-map:not( .mw-kartographer-link ):not( .mw-kartographer-interactive ) { + pointer-events: none; + cursor: default; +} +/** + * If `$wgKartographerUseMarkerStyle = true`. + */ +a.mw-kartographer-autostyled { + color: #fff; + display: inline-block; + position: relative; + top: -0.08em; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0.85em; + margin-left: 0; + border-radius: 1px; + padding: 0.24em 0.42em; + font-size: 0.85em; + font-weight: bold; + line-height: 1; + text-align: center; + vertical-align: middle; +} +a.mw-kartographer-autostyled:visited { + color: #fff; +} + +/** + * WikimediaUI base v0.7.1 + * Wikimedia Foundation user interface base variables + */ +/* Colors */ +/* Positioning */ +/* Box Model properties */ +/* Max Widths */ +/* Typography incl. print properties */ +/* Other Properties */ +/* Animation & Transition */ +/* + Anyone who changes the width of the sidebar should + update Kartographer.Dialog.DialogClass `SIDEBAR_WIDTH` accordingly +*/ +/* Dialog footer */ +.mw-kartographer-mapDialog-foot { + /* + Anyone who changes the height of the footer should + update Kartographer.Dialog.DialogClass `FOOTER_HEIGHT` accordingly + */ + padding: 1em; + height: 4.5em; + background-color: #ffffff; + border-top: 1px solid #a2a9b1; +} +.mw-kartographer-captionfoot { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: 20px; + line-height: 31px; +} +.mw-kartographer-buttonfoot { + float: right; + margin-left: 1em; +} +/* Dialog Sidebar */ +.mw-kartographer-mapDialog-sidebar { + position: absolute; + right: 0; + top: 0; + bottom: 4.5em; + z-index: 2; + border-left: 1px solid #a2a9b1; + /* + Anyone who changes the width of the sidebar should + update Kartographer.Dialog.DialogClass `SIDEBAR_WIDTH` accordingly + */ + width: 321px; + /* 320+1 so border is hidden on common 320px wide mobile devices */ + box-sizing: border-box; + background-color: #fff; + padding: 3em 2em 1em; + overflow-y: scroll; + /* For MobileFrontend */ +} +.mw-kartographer-mapDialog-sidebar .mw-kartographer-mapDialog-closeButton { + position: absolute; + top: 10px; + right: 10px; + margin-right: 0; +} +.mw-kartographer-mapDialog-sidebar .mw-kartographer-mapDialog-closeButton .oo-ui-buttonElement-button { + border: 0; +} +.mw-kartographer-mapDialog-sidebar .mw-kartographer-mapDialog-collapseButton { + position: absolute; + top: 10px; + right: 44px; + margin-right: 0; +} +.mw-kartographer-mapDialog-sidebar .mw-kartographer-mapDialog-collapseButton .oo-ui-buttonElement-button { + border: 0; +} +.skin-minerva .mw-kartographer-mapDialog-sidebar h2 { + margin-bottom: 0.6em; +} +.mw-kartographer-mapdetails-table { + width: 100%; + border-collapse: collapse; +} +.mw-kartographer-mapdetails-table tr { + background-color: #eaecf0; + text-align: center; +} +.mw-kartographer-mapdetails-table th { + text-align: left; +} +.mw-kartographer-mapdetails-table th, +.mw-kartographer-mapdetails-table td { + padding: 0.5em 1em; + font-size: 90%; +} +.mw-kartographer-mapdetails-table thead tr { + background-color: #c8ccd1; +} +.mw-kartographer-mapdetails-table thead tr th { + font-weight: bold; +} +.mw-kartographer-mapdetails-table tbody tr th:first-child { + width: 70%; + text-align: left; +} +.mw-kartographer-mapdetails-table tbody tr:nth-child( even ) { + background-color: #ffffff; +} +.mw-kartographer-externalservices .mw-kartographer-mapdetails-table tbody tr.featured { + background-color: #fef6e7; + border-bottom: 1px solid #ffcc33; +} +.mw-kartographer-externalservices .mw-kartographer-mapdetails-table tbody tr th { + font-weight: normal; +} +.mw-kartographer-description, +.mw-kartographer-mapdetails { + margin-bottom: 1.5em; +} +.mw-kartographer-mapdetails .geo { + white-space: nowrap; +} +.mw-kartographer-filterservices { + margin-bottom: 1em; +} +.kartographer-mapDialog-loading { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 4.5em; + background-image: url(data:image/gif;base64,R0lGODlhQABAAPIEALOzs05OTouLixoaGkxMTAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgAEACwAAAAAQABAAAAD/0i63P4wyknrGnjYzW3OXSgyHzaeXamhaOAGkRoBNMBC7wvJT13fjpxrV4L4aMCGcOjgNY7IJGP5cDKgUiW1YVVAbdnp9lK8YsNiIbe8+KK1avLHfHzDcyQ2wc3SRZYwCk58RlF/cQ9jBHNtdYU+EoCBd0wSZ0+EiZKTC3gVkJhfYDibnFmiP5GlpiyoqRSrSa6jG5uyoieSt5e5iK2OSX67dsTFxsfICgLLzM3NdrOvztPOaNGg1NkC1tdR2tTc3crf1WHdhuTM0NfJ7e7v8BHqUq9A07v1I9n4oCLa/P02kAMIbEK6U7MMfluHSsLCULQs5dvTUB44B7weTaSYsVTBPY2GONLq2Cjgg3kgDV3KhDHkiEy8WL6BWVCmuYw4SdLLadImwZYmRW4EQrJowZ1HvSQV6pLoUqYpww3VqfNX05JDRcZTGnRrVK8UqoKlE3EsvAQAIfkEBQoABAAsBQABACwAMAAAA5dIutzOIYZHq21S3s1Vjl1YfZNoQl81rMP5kBTLulj6yCuNZjfe6h5bwwdcwIbEIuG48P2UTIVTGeQ1k9TodCHo0phbRXcscFmluAaZTMWK1+yizAFfUyt1+/2RH+8pfX+AdYJ4eoWDZYiLjI2Oj5CRkpOUlZaXlgCakpqdAI+eno6hooukoYinqIWqnYytn6+noKuQrpIJACH5BAUKAAQALAEABQA6AB4AAAOLSLrc8qLJKYMNNFMItSfX9X3cM2ahdWqluTKp+m7lvMQ2Xc8xlk+tyKr303FexCKwdUoqJcEm7rncaZyTgfbH9Eyz2nCue02Bw+JxZxSSoN8D6hP+lv/odbsNn9bv8X5FgIF3eYSCW4eKi4yNOQCQkZKSjhOTl5OVDZicAJoMnZifC6GXo6SlkKcKCQAh+QQFCgAEACwFAAEAOgAiAAADiki63M4iikervVRKzDvXkSeOEEieHjihrKW28PPGtDLX8Y23+o72PhIwKBoSO0YWYPkznQLQxnIKOGme0CyDSj06suDAltv1hsNj8vR4RqfVTFzb7YCvaXPtxV7Le+B9bSRkgWAtd4VeiouMjY4kA5GSk5OPDJSYlJYKmZ0DmwSemaCimKChpZEECQAh+QQFCgAEACwPAAUAMAAsAAADjEiwQP4wyieqmJgxzKO1HaQtYfhVpTOSqXSi7dq656zINvFe9trMu9xtZAsKfS3jEVdSLommlzDC5EinImjnin1okqCueEwum8/otHrNbrvf8LicEKjb7/c2fo9n8/8BfoB7goN5hYZziouMLQOPjQSPkwOMlJSKl5hympecnZtwoJOfoJmdlp6NpBAJACH5BAUKAAQALB0AAQAeADoAAAOQSLBA/jBKyNi8uC7Mo25d+IWiRnbjmZnqlbbSC1PsTFe2V+fKnsstgdCBmwmPAh4BicwxmbYnNChtUqtJY5W35U6VyyF4TC6bz+i0es1uuzGBeDlOD4zrdSU+n9vj+358M4F0HAOHAxKEdheIiBOBGI6HcH+Nk4mVjJKYYJiZSp+enaOTY6ShqDyqOaytjxwJACH5BAUKAAQALB0ABQAiADoAAAOTSLrc8KDJSReENdf7tGdc933hSJZmFkapirbTCm/vDNa2xeXxzkuXn3BILBqPyKRyyWwqBNCoVDqbWqewq1aQ3Vq7Xio47Cybz+i0et0MuAPH99s2qA8YcvfMbl/k9S18dXh/gYKEeYZ8DX9wJoJ3iHIpkBKNj4eWiSOVmpsenZ5zH6GMnxqlpoCkmUSpP6+wfUYJACH5BAUKAAQALA8ADwAsADAAAAOUSLrc/pCBGauNM4PLrdZd2HyfaJKlyaGp6rGUu7JySNcdiZ/x7v/AoHBILBqPyKRyyWw6BdAndMqcWgXKqzWpvSK73iOY2hiYB74xlnE+/8DlNnoRqAdcWrZ8TrDbZWQKe3x9fndAgwyGhz6JioaIew2LP46PfpVyD5Q7lpd/nZqbkKFtEJylhJOkSqhJrkiwsaA7CQAh+QQFCgAEACwFAB0AOgAeAAADhEi63P7wgUlrjThrYrvdYOiNQGhmpHeuUvqx8OJScW3feK6fQ7/jveDgFxMKiSzjERlSGpkb5xOakQapUasjwA2ABGABTProdjXhcHJaNnszafDYF3Fz0XEx0f7Gx/d2X3k/fCZ5ejmFIYc6ioaDOIEskDaOJ4yVbjWUMZIwnJ1nNmkhCQAh+QQFCgAEACwBAB0AOgAiAAADjUiz3E0wykmrrS67y7vX4OCNZBRqZdqdmepaLPPOdG3feK7fQb8DwFpvGMgBjwAXkWhEHktLJs6J9ESXTeqzcsXqtM5Jd7iTgLeQcbFsPku6bAv47VUJ7oIXVex74fEzaDl/d3E0hHmGfoSKi3+NLoiQdoyTJZKWJJiZHpucHJ6fFqGiFKSlEqeoEY83CQAh+QQFCgAEACwBAA8AMAAsAAADjkiq0/swyklZuzVrevvY4OZ5YSmNpKlaKLaqrfua8by29jvms8z/wKBwCAoYj0gkcZFsJpcEpzQAnTqr1ic2S4V6v+CweEwum8/o9FjAFoAAcMCv3dbE4zw6236X2/R7GX1wM4BuG4N+KoZvgyuMIYmLgCWSJZCVjiGUK5obmCaWGpwvnhmknX2bdTl3BAkAIfkEBQoABAAsBQAFAB4AOgAAA49Iukzzo8k5IaS42pi72o/ngWIHciV1pirJatsrrVlgZ/Rk7wHm6rwd7EIJBmfEopEnUyyPzaewSZBSncvrwqhlTLvgsHhMLpvP6LR6TRG4w+64QCuXX+t2Gb7+2vNZfnFNgXODe3R/LwCLAAqCTYyMYJGLk5SWkZiSXZSNnJefmaGbWp2alaOopaCroqMECQA7); + background-image: url(/w/extensions/Kartographer/styles/images/ajax-loader.gif?b3af8)!ie; + background-position: center center; + background-size: 32px; + background-repeat: no-repeat; +} +.mw-kartographer-mapDialog-sidebar-opened .leaflet-right.leaflet-bottom { + right: 320px; +} + +/* == Attribution control == */ +/** + * WikimediaUI base v0.7.1 + * Wikimedia Foundation user interface base variables + */ +/* Colors */ +/* Positioning */ +/* Box Model properties */ +/* Max Widths */ +/* Typography incl. print properties */ +/* Other Properties */ +/* Animation & Transition */ +/* Static snapshot */ +.mw-kartographer-attribution { + position: absolute; + right: 0; + bottom: 0; + margin: 0; + padding: 0 5px; + box-shadow: none; +} +/* Static + Interactive */ +.mw-kartographer-attribution, +.leaflet-right.leaflet-bottom { + background-color: rgba(255, 255, 255, 0.8); + color: #222222; +} +/* Interactive */ +.leaflet-right.leaflet-bottom .leaflet-control.leaflet-control-attribution { + /** Override initial properties */ + background-color: transparent; + float: none; + clear: none; +} +/* Static + Interactive */ +.mw-kartographer-attribution, +.leaflet-right.leaflet-bottom .leaflet-control.leaflet-control-attribution { + font-size: 10px; + font-family: sans-serif; + line-height: 1.6; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + /* Removes ellipsis on hover */ +} +.mw-kartographer-attribution:hover, +.leaflet-right.leaflet-bottom .leaflet-control.leaflet-control-attribution:hover { + overflow: hidden; + text-overflow: clip; + white-space: normal; +} +.mw-kartographer-attribution a, +.leaflet-right.leaflet-bottom .leaflet-control.leaflet-control-attribution a { + color: #3366cc; +} +/* Static + Interactive */ +.mw-kartographer-map:hover .mw-kartographer-attribution, +.mw-kartographer-interactive:hover .leaflet-right.leaflet-bottom { + background-color: rgba(255, 255, 255, 0.9); +} + +/* == Scale control == */ +/* Scale Line style */ +.leaflet-control-scale.leaflet-control .leaflet-control-scale-line { + background-color: transparent; + padding: 0 5px; + font-size: 10px; + font-family: sans-serif; +} +.leaflet-right.leaflet-bottom { + /** Override initial properties */ +} +.leaflet-right.leaflet-bottom .leaflet-control.leaflet-control-scale { + float: left; + clear: none; + margin: 1px 5px; + line-height: initial; +} +.leaflet-right.leaflet-bottom .leaflet-control.leaflet-control-scale .leaflet-control-scale-line { + /* Scale Line style on hover */ + /** Override initial properties */ +} +.leaflet-right.leaflet-bottom .leaflet-control.leaflet-control-scale .leaflet-control-scale-line:hover { + border-color: #000; + cursor: pointer; +} +.leaflet-right.leaflet-bottom .leaflet-control.leaflet-control-scale .leaflet-control-scale-line:not( :first-child ) { + border: 1px solid #999; + border-color: #000; + border-top: 0; + margin-top: 0; +} + +/** + * WikimediaUI base v0.7.1 + * Wikimedia Foundation user interface base variables + */ +/* Colors */ +/* Positioning */ +/* Box Model properties */ +/* Max Widths */ +/* Typography incl. print properties */ +/* Other Properties */ +/* Animation & Transition */ +/* stylelint-disable no-descending-specificity */ +.mw-kartographer-interactive { + z-index: 0; + /* Leaflet Popups */ + /* Leaflet Controls */ +} +.mw-kartographer-interactive.leaflet-container { + font: 14px 'Helvetica Neue', 'Helvetica', 'Nimbus Sans L', 'Arial', 'Liberation Sans', sans-serif; + color: #222222; +} +.mw-kartographer-interactive.leaflet-container .marker-description img { + width: 100%; + height: auto; + margin-bottom: 0; + margin-top: 0.5em; +} +.mw-kartographer-interactive.leaflet-container a { + color: #3366cc; +} +.mw-kartographer-interactive.leaflet-container a:hover { + color: #447ff5; + text-decoration: underline; +} +.mw-kartographer-interactive.leaflet-container a:active { + color: #2a4b8d; +} +.mw-kartographer-interactive.leaflet-container a:focus { + color: #3366cc; +} +.mw-kartographer-interactive.leaflet-container a.new { + color: #ba0000; +} +.mw-kartographer-interactive.leaflet-container a.new:visited { + color: #a55858; +} +.mw-kartographer-interactive .leaflet-popup-content { + padding: 1em; +} +.mw-kartographer-interactive .leaflet-popup-content .marker-title { + text-align: center; +} +.mw-kartographer-interactive .leaflet-popup-content .marker-title > a { + font-weight: bold; +} +.mw-kartographer-interactive .leaflet-popup-content .marker-description { + text-align: center; +} +.mw-kartographer-interactive .leaflet-popup-content-wrapper, +.mw-kartographer-interactive .map-legends, +.mw-kartographer-interactive .map-tooltip { + border-radius: 2px; +} +.mw-kartographer-interactive .leaflet-control-layers, +.mw-kartographer-interactive .leaflet-bar { + background-color: #f8f9fa; + border: 0; + box-shadow: none; +} +.mw-kartographer-interactive .leaflet-bar > a, +.mw-kartographer-interactive .leaflet-bar > a:hover { + color: #000; + border: 1px solid #a2a9b1; + border-radius: 2px; + border-bottom: 0; + box-sizing: content-box; +} +.mw-kartographer-interactive .leaflet-bar > a:hover { + border-color: #a2a9b1; + background-color: #ffffff; +} +.mw-kartographer-interactive .leaflet-bar > a:active { + border-color: #72777d; + background-color: #c8ccd1; +} +.mw-kartographer-interactive .leaflet-bar > a:only-of-type { + border-bottom: 1px solid #a2a9b1; + border-radius: 2px; +} +.mw-kartographer-interactive .leaflet-bar > a:first-child:not( :only-of-type ) { + border-radius: 2px 2px 0 0; +} +.mw-kartographer-interactive .leaflet-bar > a:last-child { + border-bottom: 1px solid #a2a9b1; +} +.mw-kartographer-interactive .leaflet-bar > a:last-child:hover { + border-bottom: 1px solid #a2a9b1; + border-color: #a2a9b1; +} +.mw-kartographer-interactive .leaflet-bar > a:last-child:active { + border-bottom: 1px solid #a2a9b1; + border-color: #72777d; +} +.mw-kartographer-interactive .leaflet-bar > a:last-child:not( :only-of-type ) { + border-radius: 0 0 2px 2px; +} +.mw-kartographer-interactive .leaflet-bar > a:hover:only-of-type { + border-radius: 2px; +} +.mw-kartographer-interactive .leaflet-bar > .oo-ui-icon-close, +.mw-kartographer-interactive .leaflet-bar > .oo-ui-icon-fullScreen { + background-position: center center; +} +.mw-kartographer-interactive .leaflet-control-attribution:after, +.mw-kartographer-interactive .leaflet-control-zoom-in, +.mw-kartographer-interactive .leaflet-control-zoom-out, +.mw-kartographer-interactive .leaflet-popup-close-button, +.mw-kartographer-interactive .leaflet-control-layers-toggle, +.mw-kartographer-interactive .map-tooltip .close, +.mw-kartographer-interactive .leaflet-container.dark .map-tooltip .close, +.mw-kartographer-interactive .mapbox-icon { + opacity: 1; +} \ No newline at end of file diff --git a/bld/Release/PackageLayout/www/index.html b/bld/Release/PackageLayout/www/index.html index c4ee64bb..d045c056 100644 --- a/bld/Release/PackageLayout/www/index.html +++ b/bld/Release/PackageLayout/www/index.html @@ -205,29 +205,31 @@

Display settings

-
+
- Please select the display style:
- - - (for Wikipedia files) -
-
- - - (for Wikipedia files) - +

Please select the display style:

+

+ +  Use Wikipedia desktop display style (for Wikipedia files) +

+

+ +  Use Wikipedia mobile display style (for Wikipedia files) +

-
- Please select the display option:
- - - (recommended for Wikipedia ZIM) - +
+

Please select the display option:

+

+ +  Use locally cached display styles (recommended for Wikipedia ZIM) +

+

+ +  Display images if any (if you hide them, click on blue area to display one-by-one) +

-
diff --git a/bld/Release/PackageLayout/www/js/app.js b/bld/Release/PackageLayout/www/js/app.js index 4a144cd4..7009c970 100644 --- a/bld/Release/PackageLayout/www/js/app.js +++ b/bld/Release/PackageLayout/www/js/app.js @@ -39,7 +39,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles * @type ZIMArchive */ var selectedArchive = null; - + /** * Resize the IFrame height, so that it fills the whole available height in the window */ @@ -197,6 +197,9 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles $('input:checkbox[name=cssCacheMode]').on('change', function (e) { params['cssCache'] = this.checked ? true : false; }); + $('input:checkbox[name=imageDisplayMode]').on('change', function (e) { + params['imageDisplay'] = this.checked ? true : false; + }); $('input:radio[name=cssInjectionMode]').on('change', function (e) { params['cssSource'] = this.value; document.getElementById('returntoArticle_top').innerHTML = ""; @@ -205,6 +208,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles $(document).ready(function (e) { // Set checkbox for cssCache and radio for cssSource document.getElementById('cssCacheModeCheck').checked = params['cssCache']; + document.getElementById('imageDisplayModeCheck').checked = params['imageDisplay']; }); /** @@ -681,9 +685,11 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles */ function handleTitleClick(event) { - //TESTING// + /*/TESTING// console.log("Initiating HTML load..."); console.time("Time to HTML load"); + console.log("Initiating Document Ready timer..."); + console.time("Time to Document Ready"); */ var dirEntryId = event.target.getAttribute("dirEntryId"); $("#articleList").empty(); @@ -728,6 +734,13 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles selectedArchive.resolveRedirect(dirEntry, readArticle); } else { + + //TESTING// + console.log("Initiating HTML load..."); + console.time("Time to HTML load"); + console.log("Initiating Document Ready timer..."); + console.time("Time to Document Ready"); + selectedArchive.readArticle(dirEntry, displayArticleInForm); } } @@ -808,8 +821,12 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles console.time("Time to First Paint"); //Fast-replace img src with data-kiwixsrc and hide image [kiwix-js #272] - htmlArticle = htmlArticle.replace(/(]*\b)src(\s*=)/ig, - "$1style=\"display: none;\" onload=\"this.style.display='inline';\" data-kiwixsrc$2"); + htmlArticle = htmlArticle.replace(/(]*\b)src(\s*=)/ig, "$1data-kiwixsrc$2"); + //Ensure 24px clickable image height so user can request images by clicking [kiwix-js #173] + htmlArticle = htmlArticle.replace(/(]*\b)height(\s*=\s*)/ig, + '$1height="24" alt="Image" style="color: lightblue; background-color: lightblue;" ' + + 'onload="this.height = this.getAttribute(\'data-kiwixheight\'); this.style.background = \'\';" ' + + 'data-kiwixheight$2'); //Preload stylesheets [kiwix-js @149] //Set up blobArray of promises @@ -853,7 +870,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles function (dirEntry) { selectedArchive.readBinaryFile(dirEntry, function (readableTitle, content, namespace, url) { - var cssContent = util.uintToString(content); //Uncomment this line and break on next to capture cssContent for local filesystem cache + //var cssContent = util.uintToString(content); //Uncomment this line and break on next to capture cssContent for local filesystem cache var cssBlob = new Blob([content], { type: 'text/css' }, { oneTimeOnly: true }); var newURL = [namespace + "/" + url, URL.createObjectURL(cssBlob)]; //blobArray[index] = newURL; //Don't bother with "index" -- you don't need to track the order of the blobs TODO: delete this logic @@ -870,7 +887,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles function injectCSS() { if (blobArray.length === cssArray.length) { //If all promised values have been obtained - var resultsArray= []; + var resultsArray = []; for (var i in cssArray) { //Put them back in the correct order var match = 0; for (var j in blobArray) { //Iterate the blobArray to find the matching entry @@ -928,7 +945,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles //var articleTitle = articleTitle ? articleTitle[1] : htmlContent.match(regexpType2ZIMTitle); //If not found, use "Article" //articleTitle = articleTitle ? articleTitle[1] : "Article"; - uiUtil.makeReturnLink(dirEntry); //[kiwix-js #127] + uiUtil.makeReturnLink(dirEntry); //[kiwix-js #127] // If the ServiceWorker is not useable, we need to fallback to parse the DOM // to inject math images, and replace some links with javascript calls @@ -995,26 +1012,133 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles console.log("** First Paint complete **"); console.timeEnd("Time to First Paint"); - $('#articleContent').contents().find('body').find('img').each(function () { - var image = $(this); - // It's a standard image contained in the ZIM file - // We try to find its name (from an absolute or relative URL) - var imageMatch = image.attr('data-kiwixsrc').match(regexpImageUrl); //kiwix-js #272 - if (imageMatch) { - var title = decodeURIComponent(imageMatch[1]); - selectedArchive.getDirEntryByTitle(title).then(function (dirEntry) { - selectedArchive.readBinaryFile(dirEntry, function (readableTitle, content) { - // TODO : use the complete MIME-type of the image (as read from the ZIM file) - uiUtil.feedNodeWithBlob(image, 'src', content, 'image'); - }); - }).fail(function (e) { - console.error("could not find DirEntry for image:" + title, e); + //var imageURLs = htmlContent.match(/kiwixsrc\s*=\s*["'](?:\.\.\/|\/)+(I\/)/ig); + var imageDisplay = params['imageDisplay']; + var images = $('#articleContent').contents().find('body').find('img'); + var countImages = 0; + //DEV: firstSliceSize determines maximum number of images loaded above the fold (should be <= 10) + //Smaller numbers give faster subjective experience, but too small may delay load of visible images above the fold + var firstSliceSize = 10; + //DEV: sliceSize determines minimum batch size of background image extraction for remaining images + //Larger numbers marginally increase speed of background extraction but take longer for directory lookup and conflict with user scrolling + var sliceSize = 20; + var remainder = (images.length - firstSliceSize) % (sliceSize); + var imageSlice = {}; + var slice$x = 0; + var slice$y = 0; + var windowScroll = false; + if (images.length && imageDisplay) { //If there are images in the article, set up a listener function for onscroll event + if (images.length > firstSliceSize) { + $("#articleContent").contents().on("scroll", function () { + //Ensure event doesn't fire multiple times and waits for previous slice to be retrieved + if (windowScroll && countImages == slice$y) { + windowScroll = false; //Indicate we no longer need to delay execution because user has scrolled + sliceImages(); + } }); } - }); + sliceImages(); + } else { //User did not request images, so give option of loading one by one {kiwix-js #173] + if (images.length) { + images.each(function () { + // Attach an onclick function to load the image + var img = $(this); + $(this).on('click', function () { + loadOneImage(img.attr('data-kiwixsrc'), function (url) { + img[0].src = url; + }); + }); + }); + } + } + //TESTING + if (!images.length) { + console.log("No images in document"); + console.timeEnd("Time to Document Ready"); + } else { + if (!imageDisplay) { + console.log("Image retrieval disabled by user"); + console.timeEnd("Time to Document Ready"); + } + } + //END TESTING - /*/ Load Javascript content - $('#articleContent').contents().find('script').each(function () { + /** + * Loads images in batches or "slices" according to firstSliceSize and sliceSize parameters set above + * Slices after firstSlice are delayed until the user scrolls the iframe window + **/ + function sliceImages() { + //If starting loop or slice batch is complete AND we still need images for article + if ((countImages >= slice$y) && (countImages < images.length)) { + if (!windowScroll) { //If we haven't requested the next loop to be on scroll + slice$x = slice$y; + slice$y = slice$y > 0 ? slice$y + sliceSize : slice$y + firstSliceSize; //Increment by standard or initial sliceSize + //If all images can be obtained in one batch, set slice$y to number of images + slice$y = slice$y > images.length ? images.length : slice$y; + //Last batch should be increased to include any remainder + if (slice$x > 0 && (slice$y + remainder === images.length)) { slice$y += remainder; } + console.log("Requesting images # " + (slice$x + 1) + " to " + slice$y + "..."); + imageSlice = images.slice(slice$x, slice$y); + serializeImages(); + } else { + console.log("** Waiting for user to scroll the window..."); + } + } else { //All images requested, so Unload the scroll listener + if (images && images.length > firstSliceSize) { + if (countImages == images.length) { + console.log("Unloading scroll listener"); + $("#articleContent").contents().off('scroll'); + } + } + } + } + + function serializeImages() { + $(imageSlice).each(function () { + var image = $(this); + // It's a standard image contained in the ZIM file + // We try to find its name (from an absolute or relative URL) + var imageMatch = image.attr('data-kiwixsrc').match(regexpImageUrl); //kiwix-js #272 + if (imageMatch) { + var title = decodeURIComponent(imageMatch[1]); + selectedArchive.getDirEntryByTitle(title).then(function (dirEntry) { + selectedArchive.readBinaryFile(dirEntry, function (readableTitle, content) { + // TODO : use the complete MIME-type of the image (as read from the ZIM file) + uiUtil.feedNodeWithBlob(image, 'src', content, 'image'); + countImages++ + + //TESTING + console.log("Extracted image " + (countImages) + " of " + images.length + "..."); + if (countImages == firstSliceSize || (countImages <= firstSliceSize && countImages == images.length)) { + console.log("** First image slice extracted: document ready **"); + console.timeEnd("Time to Document Ready"); + console.log(""); + } + if (countImages == images.length) { + console.log("** All images extracted **"); + } + //END TESTING + + if (countImages == slice$y) { + windowScroll = true; //Once slice is complete, delay the loop + } + sliceImages(); + }); + }).fail(function (e) { + console.error("Could not find DirEntry for image:" + title, e); + countImages++; + if (countImages == slice$y) { + windowScroll = true; //Once slice is complete, delay the loop + } + sliceImages(); + }); + } + }); + } + + // Load Javascript content + function loadJavascript() { + //$('#articleContent').contents().find('script').each(function () { var script = $(this); // We try to find its name (from an absolute or relative URL) if (script) { var srcMatch = script.attr("src").match(regexpMetadataUrl) } @@ -1035,13 +1159,33 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles console.error("could not find DirEntry for javascript : " + title, e); }); } - });*/ + } } } } - /** + function loadOneImage(image, callback) { + // It's a standard image contained in the ZIM file + // We try to find its name (from an absolute or relative URL) + var imageMatch = image.match(regexpImageUrl); + if (imageMatch) { + var title = decodeURIComponent(imageMatch[1]); + selectedArchive.getDirEntryByTitle(title).then(function (dirEntry) { + selectedArchive.readBinaryFile(dirEntry, function (readableTitle, content, namespace, url) { + var imageBlob = new Blob([content], { type: 'text/css' }, { oneTimeOnly: true }); + var newURL = URL.createObjectURL(imageBlob); + callback(newURL); + }); + }).fail(function (e) { + console.error("Could not find DirEntry for image:" + title, e); + callback(""); + }); + } + } + + + /** * Changes the URL of the browser page, so that the user might go back to it * * @param {String} title @@ -1088,7 +1232,8 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles } function goToRandomArticle() { - selectedArchive.getRandomDirEntry(function(dirEntry) { + if (selectedArchive === null) { return; } //Prevents exception if user hasn't selected an archive + selectedArchive.getRandomDirEntry(function (dirEntry) { if (dirEntry === null || dirEntry === undefined) { alert("Error finding random article."); } @@ -1110,10 +1255,6 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles } function goToMainArticle() { - - //TESTING - console.time("Time to HTML load"); - selectedArchive.getMainPageDirEntry(function (dirEntry) { if (dirEntry === null || dirEntry === undefined) { console.error("Error finding main article."); diff --git a/bld/Release/_pkginfo.txt b/bld/Release/_pkginfo.txt index 8d11cf28..14f4b6e5 100644 --- a/bld/Release/_pkginfo.txt +++ b/bld/Release/_pkginfo.txt @@ -1 +1 @@ -C:\Users\geoff\Source\Repos\kiwix-js-windows\AppPackages\KiwixWebApp_0.7.7.0_Test\KiwixWebApp_0.7.7.0_AnyCPU.appxbundle +C:\Users\geoff\Source\Repos\kiwix-js-windows\AppPackages\KiwixWebApp_0.7.8.0_Test\KiwixWebApp_0.7.8.0_AnyCPU.appxbundle diff --git a/bld/Release/filemap.map.txt b/bld/Release/filemap.map.txt index e6902e99..7e89ec50 100644 --- a/bld/Release/filemap.map.txt +++ b/bld/Release/filemap.map.txt @@ -50,6 +50,9 @@ "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\inserted_style_mobile.css" "www\-\s\css_modules\inserted_style_mobile.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.timeline.styles.css" "www\-\s\css_modules\ext.timeline.styles.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.scribunto.logs.css" "www\-\s\css_modules\ext.scribunto.logs.css" +"C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.kartographer.style.css" "www\-\s\css_modules\ext.kartographer.style.css" +"C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.kartographer.link.css" "www\-\s\css_modules\ext.kartographer.link.css" +"C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.kartographer.frame.css" "www\-\s\css_modules\ext.kartographer.frame.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.cite.styles.css" "www\-\s\css_modules\ext.cite.styles.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.cite.a11y.css" "www\-\s\css_modules\ext.cite.a11y.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\content.parsoid.css" "www\-\s\css_modules\content.parsoid.css" diff --git a/bld/Release/filemap.pri b/bld/Release/filemap.pri index a2fea9d8..7e53e093 100644 Binary files a/bld/Release/filemap.pri and b/bld/Release/filemap.pri differ diff --git a/bld/Release/filemap.scale-100.pri b/bld/Release/filemap.scale-100.pri index 451efb60..5dd7278b 100644 Binary files a/bld/Release/filemap.scale-100.pri and b/bld/Release/filemap.scale-100.pri differ diff --git a/bld/Release/filemap.scale-125.pri b/bld/Release/filemap.scale-125.pri index 5d0db7d9..4292b60a 100644 Binary files a/bld/Release/filemap.scale-125.pri and b/bld/Release/filemap.scale-125.pri differ diff --git a/bld/Release/filemap.scale-150.pri b/bld/Release/filemap.scale-150.pri index 9141c353..d49abb18 100644 Binary files a/bld/Release/filemap.scale-150.pri and b/bld/Release/filemap.scale-150.pri differ diff --git a/bld/Release/filemap.scale-400.pri b/bld/Release/filemap.scale-400.pri index f9b3ed74..04c010a8 100644 Binary files a/bld/Release/filemap.scale-400.pri and b/bld/Release/filemap.scale-400.pri differ diff --git a/bld/Release/main.map.txt b/bld/Release/main.map.txt index 2d8b0bd8..811765f2 100644 --- a/bld/Release/main.map.txt +++ b/bld/Release/main.map.txt @@ -51,6 +51,9 @@ "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\inserted_style_mobile.css" "www\-\s\css_modules\inserted_style_mobile.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.timeline.styles.css" "www\-\s\css_modules\ext.timeline.styles.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.scribunto.logs.css" "www\-\s\css_modules\ext.scribunto.logs.css" +"C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.kartographer.style.css" "www\-\s\css_modules\ext.kartographer.style.css" +"C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.kartographer.link.css" "www\-\s\css_modules\ext.kartographer.link.css" +"C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.kartographer.frame.css" "www\-\s\css_modules\ext.kartographer.frame.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.cite.styles.css" "www\-\s\css_modules\ext.cite.styles.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.cite.a11y.css" "www\-\s\css_modules\ext.cite.a11y.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\content.parsoid.css" "www\-\s\css_modules\content.parsoid.css" diff --git a/bld/Release/split.map.txt b/bld/Release/split.map.txt index 5c821ffc..464317b9 100644 --- a/bld/Release/split.map.txt +++ b/bld/Release/split.map.txt @@ -50,6 +50,9 @@ "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\inserted_style_mobile.css" "www\-\s\css_modules\inserted_style_mobile.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.timeline.styles.css" "www\-\s\css_modules\ext.timeline.styles.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.scribunto.logs.css" "www\-\s\css_modules\ext.scribunto.logs.css" +"C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.kartographer.style.css" "www\-\s\css_modules\ext.kartographer.style.css" +"C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.kartographer.link.css" "www\-\s\css_modules\ext.kartographer.link.css" +"C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.kartographer.frame.css" "www\-\s\css_modules\ext.kartographer.frame.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.cite.styles.css" "www\-\s\css_modules\ext.cite.styles.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\ext.cite.a11y.css" "www\-\s\css_modules\ext.cite.a11y.css" "C:\Users\geoff\Source\Repos\kiwix-js-windows\bld\Release\PackageLayout\www\-\s\css_modules\content.parsoid.css" "www\-\s\css_modules\content.parsoid.css" diff --git a/bld/Release/split.pri b/bld/Release/split.pri index 0067cf4e..83ddfc17 100644 Binary files a/bld/Release/split.pri and b/bld/Release/split.pri differ diff --git a/bld/Release/split.pri.xml b/bld/Release/split.pri.xml index 596044a1..ed7363bb 100644 --- a/bld/Release/split.pri.xml +++ b/bld/Release/split.pri.xml @@ -123,6 +123,21 @@ www\-\s\css_modules\ext.cite.styles.css + + + www\-\s\css_modules\ext.kartographer.frame.css + + + + + www\-\s\css_modules\ext.kartographer.link.css + + + + + www\-\s\css_modules\ext.kartographer.style.css + + www\-\s\css_modules\ext.scribunto.logs.css diff --git a/bld/Release/split.scale-100.pri b/bld/Release/split.scale-100.pri index f834680c..6be4c535 100644 Binary files a/bld/Release/split.scale-100.pri and b/bld/Release/split.scale-100.pri differ diff --git a/bld/Release/split.scale-125.pri b/bld/Release/split.scale-125.pri index 44fc2599..38afaea4 100644 Binary files a/bld/Release/split.scale-125.pri and b/bld/Release/split.scale-125.pri differ diff --git a/bld/Release/split.scale-150.pri b/bld/Release/split.scale-150.pri index 097a004f..4bbfabad 100644 Binary files a/bld/Release/split.scale-150.pri and b/bld/Release/split.scale-150.pri differ diff --git a/bld/Release/split.scale-400.pri b/bld/Release/split.scale-400.pri index e9c11487..7cbf666d 100644 Binary files a/bld/Release/split.scale-400.pri and b/bld/Release/split.scale-400.pri differ diff --git a/package.appxmanifest b/package.appxmanifest index 1c6425d4..45a49f37 100644 --- a/package.appxmanifest +++ b/package.appxmanifest @@ -1,6 +1,6 @@  - + Kiwix JS