1FED79650016851F; 144
+			productRefGroup = 504EC3051FED79650016851F /* Products */;
145
+			projectDirPath = "";
146
+			projectRoot = "";
147
+			targets = (
148
+				504EC3031FED79650016851F /* App */,
149
+			);
150
+		};
151
+/* End PBXProject section */
152
+
153
+/* Begin PBXResourcesBuildPhase section */
154
+		504EC3021FED79650016851F /* Resources */ = {
155
+			isa = PBXResourcesBuildPhase;
156
+			buildActionMask = 2147483647;
157
+			files = (
158
+				504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
159
+				50B271D11FEDC1A000F3C39B /* public in Resources */,
160
+				504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
161
+				50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
162
+				504EC30D1FED79650016851F /* Main.storyboard in Resources */,
163
+				2FAD9763203C412B000D30F8 /* config.xml in Resources */,
164
+			);
165
+			runOnlyForDeploymentPostprocessing = 0;
166
+		};
167
+/* End PBXResourcesBuildPhase section */
168
+
169
+/* Begin PBXShellScriptBuildPhase section */
170
+		6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */ = {
171
+			isa = PBXShellScriptBuildPhase;
172
+			buildActionMask = 2147483647;
173
+			files = (
174
+			);
175
+			inputPaths = (
176
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
177
+				"${PODS_ROOT}/Manifest.lock",
178
+			);
179
+			name = "[CP] Check Pods Manifest.lock";
180
+			outputPaths = (
181
+				"$(DERIVED_FILE_DIR)/Pods-App-checkManifestLockResult.txt",
182
+			);
183
+			runOnlyForDeploymentPostprocessing = 0;
184
+			shellPath = /bin/sh;
185
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
186
+			showEnvVarsInLog = 0;
187
+		};
188
+		9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */ = {
189
+			isa = PBXShellScriptBuildPhase;
190
+			buildActionMask = 2147483647;
191
+			files = (
192
+			);
193
+			inputPaths = (
194
+			);
195
+			name = "[CP] Embed Pods Frameworks";
196
+			outputPaths = (
197
+			);
198
+			runOnlyForDeploymentPostprocessing = 0;
199
+			shellPath = /bin/sh;
200
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-frameworks.sh\"\n";
201
+			showEnvVarsInLog = 0;
202
+		};
203
+/* End PBXShellScriptBuildPhase section */
204
+
205
+/* Begin PBXSourcesBuildPhase section */
206
+		504EC3001FED79650016851F /* Sources */ = {
207
+			isa = PBXSourcesBuildPhase;
208
+			buildActionMask = 2147483647;
209
+			files = (
210
+				504EC3081FED79650016851F /* AppDelegate.swift in Sources */,
211
+			);
212
+			runOnlyForDeploymentPostprocessing = 0;
213
+		};
214
+/* End PBXSourcesBuildPhase section */
215
+
216
+/* Begin PBXVariantGroup section */
217
+		504EC30B1FED79650016851F /* Main.storyboard */ = {
218
+			isa = PBXVariantGroup;
219
+			children = (
220
+				504EC30C1FED79650016851F /* Base */,
221
+			);
222
+			name = Main.storyboard;
223
+			sourceTree = "<group>";
224
+		};
225
+		504EC3101FED79650016851F /* LaunchScreen.storyboard */ = {
226
+			isa = PBXVariantGroup;
227
+			children = (
228
+				504EC3111FED79650016851F /* Base */,
229
+			);
230
+			name = LaunchScreen.storyboard;
231
+			sourceTree = "<group>";
232
+		};
233
+/* End PBXVariantGroup section */
234
+
235
+/* Begin XCBuildConfiguration section */
236
+		504EC3141FED79650016851F /* Debug */ = {
237
+			isa = XCBuildConfiguration;
238
+			buildSettings = {
239
+				ALWAYS_SEARCH_USER_PATHS = NO;
240
+				CLANG_ANALYZER_NONNULL = YES;
241
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
242
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
243
+				CLANG_CXX_LIBRARY = "libc++";
244
+				CLANG_ENABLE_MODULES = YES;
245
+				CLANG_ENABLE_OBJC_ARC = YES;
246
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
247
+				CLANG_WARN_BOOL_CONVERSION = YES;
248
+				CLANG_WARN_COMMA = YES;
249
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
250
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
251
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
252
+				CLANG_WARN_EMPTY_BODY = YES;
253
+				CLANG_WARN_ENUM_CONVERSION = YES;
254
+				CLANG_WARN_INFINITE_RECURSION = YES;
255
+				CLANG_WARN_INT_CONVERSION = YES;
256
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
257
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
258
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
259
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
260
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
261
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
262
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
263
+				CLANG_WARN_UNREACHABLE_CODE = YES;
264
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
265
+				CODE_SIGN_IDENTITY = "iPhone Developer";
266
+				COPY_PHASE_STRIP = NO;
267
+				DEBUG_INFORMATION_FORMAT = dwarf;
268
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
269
+				ENABLE_TESTABILITY = YES;
270
+				GCC_C_LANGUAGE_STANDARD = gnu11;
271
+				GCC_DYNAMIC_NO_PIC = NO;
272
+				GCC_NO_COMMON_BLOCKS = YES;
273
+				GCC_OPTIMIZATION_LEVEL = 0;
274
+				GCC_PREPROCESSOR_DEFINITIONS = (
275
+					"DEBUG=1",
276
+					"$(inherited)",
277
+				);
278
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
279
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
280
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
281
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
282
+				GCC_WARN_UNUSED_FUNCTION = YES;
283
+				GCC_WARN_UNUSED_VARIABLE = YES;
284
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
285
+				MTL_ENABLE_DEBUG_INFO = YES;
286
+				ONLY_ACTIVE_ARCH = YES;
287
+				SDKROOT = iphoneos;
288
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
289
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
290
+			};
291
+			name = Debug;
292
+		};
293
+		504EC3151FED79650016851F /* Release */ = {
294
+			isa = XCBuildConfiguration;
295
+			buildSettings = {
296
+				ALWAYS_SEARCH_USER_PATHS = NO;
297
+				CLANG_ANALYZER_NONNULL = YES;
298
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
299
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
300
+				CLANG_CXX_LIBRARY = "libc++";
301
+				CLANG_ENABLE_MODULES = YES;
302
+				CLANG_ENABLE_OBJC_ARC = YES;
303
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
304
+				CLANG_WARN_BOOL_CONVERSION = YES;
305
+				CLANG_WARN_COMMA = YES;
306
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
307
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
308
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
309
+				CLANG_WARN_EMPTY_BODY = YES;
310
+				CLANG_WARN_ENUM_CONVERSION = YES;
311
+				CLANG_WARN_INFINITE_RECURSION = YES;
312
+				CLANG_WARN_INT_CONVERSION = YES;
313
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
314
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
315
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
316
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
317
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
318
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
319
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
320
+				CLANG_WARN_UNREACHABLE_CODE = YES;
321
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
322
+				CODE_SIGN_IDENTITY = "iPhone Developer";
323
+				COPY_PHASE_STRIP = NO;
324
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
325
+				ENABLE_NS_ASSERTIONS = NO;
326
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
327
+				GCC_C_LANGUAGE_STANDARD = gnu11;
328
+				GCC_NO_COMMON_BLOCKS = YES;
329
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
330
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
331
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
332
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
333
+				GCC_WARN_UNUSED_FUNCTION = YES;
334
+				GCC_WARN_UNUSED_VARIABLE = YES;
335
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
336
+				MTL_ENABLE_DEBUG_INFO = NO;
337
+				SDKROOT = iphoneos;
338
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
339
+				VALIDATE_PRODUCT = YES;
340
+			};
341
+			name = Release;
342
+		};
343
+		504EC3171FED79650016851F /* Debug */ = {
344
+			isa = XCBuildConfiguration;
345
+			baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */;
346
+			buildSettings = {
347
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
348
+				CODE_SIGN_STYLE = Automatic;
349
+				CURRENT_PROJECT_VERSION = 1;
350
+				INFOPLIST_FILE = App/Info.plist;
351
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
352
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
353
+				MARKETING_VERSION = 1.0;
354
+				OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
355
+				PRODUCT_BUNDLE_IDENTIFIER = io.ionic.starter;
356
+				PRODUCT_NAME = "$(TARGET_NAME)";
357
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
358
+				SWIFT_VERSION = 5.0;
359
+				TARGETED_DEVICE_FAMILY = "1,2";
360
+			};
361
+			name = Debug;
362
+		};
363
+		504EC3181FED79650016851F /* Release */ = {
364
+			isa = XCBuildConfiguration;
365
+			baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */;
366
+			buildSettings = {
367
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
368
+				CODE_SIGN_STYLE = Automatic;
369
+				CURRENT_PROJECT_VERSION = 1;
370
+				INFOPLIST_FILE = App/Info.plist;
371
+				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
372
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
373
+				MARKETING_VERSION = 1.0;
374
+				PRODUCT_BUNDLE_IDENTIFIER = io.ionic.starter;
375
+				PRODUCT_NAME = "$(TARGET_NAME)";
376
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
377
+				SWIFT_VERSION = 5.0;
378
+				TARGETED_DEVICE_FAMILY = "1,2";
379
+			};
380
+			name = Release;
381
+		};
382
+/* End XCBuildConfiguration section */
383
+
384
+/* Begin XCConfigurationList section */
385
+		504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */ = {
386
+			isa = XCConfigurationList;
387
+			buildConfigurations = (
388
+				504EC3141FED79650016851F /* Debug */,
389
+				504EC3151FED79650016851F /* Release */,
390
+			);
391
+			defaultConfigurationIsVisible = 0;
392
+			defaultConfigurationName = Release;
393
+		};
394
+		504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */ = {
395
+			isa = XCConfigurationList;
396
+			buildConfigurations = (
397
+				504EC3171FED79650016851F /* Debug */,
398
+				504EC3181FED79650016851F /* Release */,
399
+			);
400
+			defaultConfigurationIsVisible = 0;
401
+			defaultConfigurationName = Release;
402
+		};
403
+/* End XCConfigurationList section */
404
+	};
405
+	rootObject = 504EC2FC1FED79650016851F /* Project object */;
406
+}

+ 7 - 0
ios/App/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<Workspace
3
+   version = "1.0">
4
+   <FileRef
5
+      location = "self:App.xcodeproj">
6
+   </FileRef>
7
+</Workspace>

+ 10 - 0
ios/App/App.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,10 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<Workspace
3
+   version = "1.0">
4
+   <FileRef
5
+      location = "group:App.xcodeproj">
6
+   </FileRef>
7
+   <FileRef
8
+      location = "group:Pods/Pods.xcodeproj">
9
+   </FileRef>
10
+</Workspace>

+ 8 - 0
ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist

@@ -0,0 +1,8 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>IDEDidComputeMac32BitWarning</key>
6
+	<true/>
7
+</dict>
8
+</plist>

+ 49 - 0
ios/App/App/AppDelegate.swift

@@ -0,0 +1,49 @@
1
+import UIKit
2
+import Capacitor
3
+
4
+@UIApplicationMain
5
+class AppDelegate: UIResponder, UIApplicationDelegate {
6
+
7
+    var window: UIWindow?
8
+
9
+    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
10
+        // Override point for customization after application launch.
11
+        return true
12
+    }
13
+
14
+    func applicationWillResignActive(_ application: UIApplication) {
15
+        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
16
+        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
17
+    }
18
+
19
+    func applicationDidEnterBackground(_ application: UIApplication) {
20
+        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
21
+        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
22
+    }
23
+
24
+    func applicationWillEnterForeground(_ application: UIApplication) {
25
+        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
26
+    }
27
+
28
+    func applicationDidBecomeActive(_ application: UIApplication) {
29
+        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
30
+    }
31
+
32
+    func applicationWillTerminate(_ application: UIApplication) {
33
+        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
34
+    }
35
+
36
+    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
37
+        // Called when the app was launched with a url. Feel free to add additional processing here,
38
+        // but if you want the App API to support tracking app url opens, make sure to keep this call
39
+        return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
40
+    }
41
+
42
+    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
43
+        // Called when the app was launched with an activity, including Universal Links.
44
+        // Feel free to add additional processing here, but if you want the App API to support
45
+        // tracking app url opens, make sure to keep this call
46
+        return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
47
+    }
48
+
49
+}

BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png


BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png


+ 116 - 0
ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,116 @@
1
+{
2
+  "images" : [
3
+    {
4
+      "size" : "20x20",
5
+      "idiom" : "iphone",
6
+      "filename" : "AppIcon-20x20@2x.png",
7
+      "scale" : "2x"
8
+    },
9
+    {
10
+      "size" : "20x20",
11
+      "idiom" : "iphone",
12
+      "filename" : "AppIcon-20x20@3x.png",
13
+      "scale" : "3x"
14
+    },
15
+    {
16
+      "size" : "29x29",
17
+      "idiom" : "iphone",
18
+      "filename" : "AppIcon-29x29@2x-1.png",
19
+      "scale" : "2x"
20
+    },
21
+    {
22
+      "size" : "29x29",
23
+      "idiom" : "iphone",
24
+      "filename" : "AppIcon-29x29@3x.png",
25
+      "scale" : "3x"
26
+    },
27
+    {
28
+      "size" : "40x40",
29
+      "idiom" : "iphone",
30
+      "filename" : "AppIcon-40x40@2x.png",
31
+      "scale" : "2x"
32
+    },
33
+    {
34
+      "size" : "40x40",
35
+      "idiom" : "iphone",
36
+      "filename" : "AppIcon-40x40@3x.png",
37
+      "scale" : "3x"
38
+    },
39
+    {
40
+      "size" : "60x60",
41
+      "idiom" : "iphone",
42
+      "filename" : "AppIcon-60x60@2x.png",
43
+      "scale" : "2x"
44
+    },
45
+    {
46
+      "size" : "60x60",
47
+      "idiom" : "iphone",
48
+      "filename" : "AppIcon-60x60@3x.png",
49
+      "scale" : "3x"
50
+    },
51
+    {
52
+      "size" : "20x20",
53
+      "idiom" : "ipad",
54
+      "filename" : "AppIcon-20x20@1x.png",
55
+      "scale" : "1x"
56
+    },
57
+    {
58
+      "size" : "20x20",
59
+      "idiom" : "ipad",
60
+      "filename" : "AppIcon-20x20@2x-1.png",
61
+      "scale" : "2x"
62
+    },
63
+    {
64
+      "size" : "29x29",
65
+      "idiom" : "ipad",
66
+      "filename" : "AppIcon-29x29@1x.png",
67
+      "scale" : "1x"
68
+    },
69
+    {
70
+      "size" : "29x29",
71
+      "idiom" : "ipad",
72
+      "filename" : "AppIcon-29x29@2x.png",
73
+      "scale" : "2x"
74
+    },
75
+    {
76
+      "size" : "40x40",
77
+      "idiom" : "ipad",
78
+      "filename" : "AppIcon-40x40@1x.png",
79
+      "scale" : "1x"
80
+    },
81
+    {
82
+      "size" : "40x40",
83
+      "idiom" : "ipad",
84
+      "filename" : "AppIcon-40x40@2x-1.png",
85
+      "scale" : "2x"
86
+    },
87
+    {
88
+      "size" : "76x76",
89
+      "idiom" : "ipad",
90
+      "filename" : "AppIcon-76x76@1x.png",
91
+      "scale" : "1x"
92
+    },
93
+    {
94
+      "size" : "76x76",
95
+      "idiom" : "ipad",
96
+      "filename" : "AppIcon-76x76@2x.png",
97
+      "scale" : "2x"
98
+    },
99
+    {
100
+      "size" : "83.5x83.5",
101
+      "idiom" : "ipad",
102
+      "filename" : "AppIcon-83.5x83.5@2x.png",
103
+      "scale" : "2x"
104
+    },
105
+    {
106
+      "size" : "1024x1024",
107
+      "idiom" : "ios-marketing",
108
+      "filename" : "AppIcon-512@2x.png",
109
+      "scale" : "1x"
110
+    }
111
+  ],
112
+  "info" : {
113
+    "version" : 1,
114
+    "author" : "xcode"
115
+  }
116
+}

+ 6 - 0
ios/App/App/Assets.xcassets/Contents.json

@@ -0,0 +1,6 @@
1
+{
2
+  "info" : {
3
+    "version" : 1,
4
+    "author" : "xcode"
5
+  }
6
+}

+ 23 - 0
ios/App/App/Assets.xcassets/Splash.imageset/Contents.json

@@ -0,0 +1,23 @@
1
+{
2
+  "images" : [
3
+    {
4
+      "idiom" : "universal",
5
+      "filename" : "splash-2732x2732-2.png",
6
+      "scale" : "1x"
7
+    },
8
+    {
9
+      "idiom" : "universal",
10
+      "filename" : "splash-2732x2732-1.png",
11
+      "scale" : "2x"
12
+    },
13
+    {
14
+      "idiom" : "universal",
15
+      "filename" : "splash-2732x2732.png",
16
+      "scale" : "3x"
17
+    }
18
+  ],
19
+  "info" : {
20
+    "version" : 1,
21
+    "author" : "xcode"
22
+  }
23
+}

BIN
ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png


BIN
ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png


BIN
ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png


+ 32 - 0
ios/App/App/Base.lproj/LaunchScreen.storyboard

@@ -0,0 +1,32 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17132" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
3
+    <device id="retina4_7" orientation="portrait" appearance="light"/>
4
+    <dependencies>
5
+        <deployment identifier="iOS"/>
6
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17105"/>
7
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
8
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
9
+    </dependencies>
10
+    <scenes>
11
+        <!--View Controller-->
12
+        <scene sceneID="EHf-IW-A2E">
13
+            <objects>
14
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
15
+                    <imageView key="view" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Splash" id="snD-IY-ifK">
16
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
17
+                        <autoresizingMask key="autoresizingMask"/>
18
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
19
+                    </imageView>
20
+                </viewController>
21
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
22
+            </objects>
23
+            <point key="canvasLocation" x="53" y="375"/>
24
+        </scene>
25
+    </scenes>
26
+    <resources>
27
+        <image name="Splash" width="1366" height="1366"/>
28
+        <systemColor name="systemBackgroundColor">
29
+            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
30
+        </systemColor>
31
+    </resources>
32
+</document>

+ 19 - 0
ios/App/App/Base.lproj/Main.storyboard

@@ -0,0 +1,19 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14111" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
3
+    <device id="retina4_7" orientation="portrait">
4
+        <adaptation id="fullscreen"/>
5
+    </device>
6
+    <dependencies>
7
+        <deployment identifier="iOS"/>
8
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
9
+    </dependencies>
10
+    <scenes>
11
+        <!--Bridge View Controller-->
12
+        <scene sceneID="tne-QT-ifu">
13
+            <objects>
14
+                <viewController id="BYZ-38-t0r" customClass="CAPBridgeViewController" customModule="Capacitor" sceneMemberID="viewController"/>
15
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
16
+            </objects>
17
+        </scene>
18
+    </scenes>
19
+</document>

+ 49 - 0
ios/App/App/Info.plist

@@ -0,0 +1,49 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+<plist version="1.0">
4
+<dict>
5
+	<key>CFBundleDevelopmentRegion</key>
6
+	<string>en</string>
7
+	<key>CFBundleDisplayName</key>
8
+        <string>ra100</string>
9
+	<key>CFBundleExecutable</key>
10
+	<string>$(EXECUTABLE_NAME)</string>
11
+	<key>CFBundleIdentifier</key>
12
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13
+	<key>CFBundleInfoDictionaryVersion</key>
14
+	<string>6.0</string>
15
+	<key>CFBundleName</key>
16
+	<string>$(PRODUCT_NAME)</string>
17
+	<key>CFBundlePackageType</key>
18
+	<string>APPL</string>
19
+	<key>CFBundleShortVersionString</key>
20
+	<string>$(MARKETING_VERSION)</string>
21
+	<key>CFBundleVersion</key>
22
+	<string>$(CURRENT_PROJECT_VERSION)</string>
23
+	<key>LSRequiresIPhoneOS</key>
24
+	<true/>
25
+	<key>UILaunchStoryboardName</key>
26
+	<string>LaunchScreen</string>
27
+	<key>UIMainStoryboardFile</key>
28
+	<string>Main</string>
29
+	<key>UIRequiredDeviceCapabilities</key>
30
+	<array>
31
+		<string>armv7</string>
32
+	</array>
33
+	<key>UISupportedInterfaceOrientations</key>
34
+	<array>
35
+		<string>UIInterfaceOrientationPortrait</string>
36
+		<string>UIInterfaceOrientationLandscapeLeft</string>
37
+		<string>UIInterfaceOrientationLandscapeRight</string>
38
+	</array>
39
+	<key>UISupportedInterfaceOrientations~ipad</key>
40
+	<array>
41
+		<string>UIInterfaceOrientationPortrait</string>
42
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
43
+		<string>UIInterfaceOrientationLandscapeLeft</string>
44
+		<string>UIInterfaceOrientationLandscapeRight</string>
45
+	</array>
46
+	<key>UIViewControllerBasedStatusBarAppearance</key>
47
+	<true/>
48
+</dict>
49
+</plist>

+ 27 - 0
ios/App/Podfile

@@ -0,0 +1,27 @@
1
+require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
2
+
3
+platform :ios, '13.0'
4
+use_frameworks!
5
+
6
+# workaround to avoid Xcode caching of Pods that requires
7
+# Product -> Clean Build Folder after new Cordova plugins installed
8
+# Requires CocoaPods 1.6 or newer
9
+install! 'cocoapods', :disable_input_output_paths => true
10
+
11
+def capacitor_pods
12
+  pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
13
+  pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
14
+  pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
15
+  pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
16
+  pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
17
+  pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
18
+end
19
+
20
+target 'App' do
21
+  capacitor_pods
22
+  # Add your Pods here
23
+end
24
+
25
+post_install do |installer|
26
+  assertDeploymentTarget(installer)
27
+end

File diff suppressed because it is too large
+ 43 - 16987
package-lock.json


+ 1 - 0
package.json

@@ -22,6 +22,7 @@
22 22
     "@capacitor/app": "4.1.0",
23 23
     "@capacitor/core": "4.4.0",
24 24
     "@capacitor/haptics": "4.0.1",
25
+    "@capacitor/ios": "4.4.0",
25 26
     "@capacitor/keyboard": "4.0.1",
26 27
     "@capacitor/status-bar": "4.0.1",
27 28
     "@fortawesome/angular-fontawesome": "^0.11.1",

+ 1 - 1
src/app/home/home.page.html

@@ -72,4 +72,4 @@
72 72
     <img src="../../../assets/img-static/banner-320x100.jpeg" alt="">
73 73
   </ion-grid>
74 74
 
75
-</ion-content>
75
+</ion-content>

BIN
www/IBMPlexSansThai-Regular.ttf


BIN
www/IBMPlexSansThai-SemiBold.ttf


BIN
www/K2D-Light.ttf


BIN
www/Montserrat-Medium.ttf


BIN
www/Prompt-Medium.ttf


BIN
www/Prompt-Regular.ttf


File diff suppressed because it is too large
+ 3244 - 0
www/assets/api/news-api.json


BIN
www/assets/fonts/IBMPlexSansThai-Regular.ttf


BIN
www/assets/fonts/IBMPlexSansThai-SemiBold.ttf


BIN
www/assets/fonts/K2D-Light.ttf


BIN
www/assets/fonts/Montserrat-Medium.ttf


BIN
www/assets/fonts/Montserrat-SemiBold.ttf


BIN
www/assets/fonts/Prompt-Light.ttf


BIN
www/assets/fonts/Prompt-Medium.ttf


BIN
www/assets/fonts/Prompt-Regular.ttf


BIN
www/assets/icon/favicon.png


BIN
www/assets/icon/logo-fm99.png


BIN
www/assets/img-static/SEI129887404-c4a9.jpg


BIN
www/assets/img-static/background_982645-1-min.png


BIN
www/assets/img-static/banner-250x250.jpeg


BIN
www/assets/img-static/banner-320x100.jpeg


BIN
www/assets/img-static/banner-320x50.jpeg


BIN
www/assets/img-static/bg-content-min.jpg


BIN
www/assets/img-static/fb-Ad-1.jpeg


BIN
www/assets/img-static/fb-Ad-2.jpeg


BIN
www/assets/img-static/fb-Ad-3.jpeg


BIN
www/assets/img-static/mqdefault-1.jpg


BIN
www/assets/img-static/mqdefault-2.jpg


BIN
www/assets/img-static/mqdefault-3.jpg


File diff suppressed because it is too large
+ 1 - 0
www/assets/shapes.svg


BIN
www/background_982645-1-min.png


BIN
www/bg-content-min.jpg


File diff suppressed because it is too large
+ 1329 - 0
www/common.js


File diff suppressed because it is too large
+ 1 - 0
www/common.js.map


File diff suppressed because it is too large
+ 1823 - 0
www/default-node_modules_ionic_core_dist_esm_parse-71f28cd7_js-node_modules_ionic_core_dist_esm_t-0c999b.js


File diff suppressed because it is too large
+ 1 - 0
www/default-node_modules_ionic_core_dist_esm_parse-71f28cd7_js-node_modules_ionic_core_dist_esm_t-0c999b.js.map


+ 26 - 0
www/index.html

@@ -0,0 +1,26 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+
4
+<head>
5
+  <meta charset="utf-8"/>
6
+  <title>Ionic App</title>
7
+
8
+  <base href="/"/>
9
+
10
+  <meta name="color-scheme" content="light dark"/>
11
+  <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
12
+  <meta name="format-detection" content="telephone=no"/>
13
+  <meta name="msapplication-tap-highlight" content="no"/>
14
+
15
+  <link rel="icon" type="image/png" href="assets/icon/favicon.png"/>
16
+
17
+  <!-- add to homescreen for ios -->
18
+  <meta name="apple-mobile-web-app-capable" content="yes"/>
19
+  <meta name="apple-mobile-web-app-status-bar-style" content="black"/>
20
+<link rel="stylesheet" href="styles.css"></head>
21
+
22
+<body>
23
+  <app-root></app-root>
24
+<script src="runtime.js" type="module"></script><script src="polyfills.js" type="module"></script><script src="vendor.js" type="module"></script><script src="main.js" type="module"></script></body>
25
+
26
+</html>

File diff suppressed because it is too large
+ 501 - 0
www/main.js


File diff suppressed because it is too large
+ 1 - 0
www/main.js.map


+ 239 - 0
www/node_modules_ionic_core_dist_esm_index-0bc00b33_js.js

@@ -0,0 +1,239 @@
1
+"use strict";
2
+(self["webpackChunkapp"] = self["webpackChunkapp"] || []).push([["node_modules_ionic_core_dist_esm_index-0bc00b33_js"],{
3
+
4
+/***/ 1612:
5
+/*!*************************************************************!*\
6
+  !*** ./node_modules/@ionic/core/dist/esm/index-0bc00b33.js ***!
7
+  \*************************************************************/
8
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
9
+
10
+__webpack_require__.r(__webpack_exports__);
11
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
12
+/* harmony export */   "startTapClick": () => (/* binding */ startTapClick)
13
+/* harmony export */ });
14
+/* harmony import */ var _helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./helpers-3b390e48.js */ 9234);
15
+/*!
16
+ * (C) Ionic http://ionicframework.com - MIT License
17
+ */
18
+
19
+
20
+const startTapClick = config => {
21
+  let lastTouch = -MOUSE_WAIT * 10;
22
+  let lastActivated = 0;
23
+  let activatableEle;
24
+  let activeRipple;
25
+  let activeDefer;
26
+  const useRippleEffect = config.getBoolean('animated', true) && config.getBoolean('rippleEffect', true);
27
+  const clearDefers = new WeakMap(); // Touch Events
28
+
29
+  const onTouchStart = ev => {
30
+    lastTouch = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_0__.u)(ev);
31
+    pointerDown(ev);
32
+  };
33
+
34
+  const onTouchEnd = ev => {
35
+    lastTouch = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_0__.u)(ev);
36
+    pointerUp(ev);
37
+  };
38
+
39
+  const onMouseDown = ev => {
40
+    // Ignore right clicks
41
+    if (ev.button === 2) {
42
+      return;
43
+    }
44
+
45
+    const t = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_0__.u)(ev) - MOUSE_WAIT;
46
+
47
+    if (lastTouch < t) {
48
+      pointerDown(ev);
49
+    }
50
+  };
51
+
52
+  const onMouseUp = ev => {
53
+    const t = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_0__.u)(ev) - MOUSE_WAIT;
54
+
55
+    if (lastTouch < t) {
56
+      pointerUp(ev);
57
+    }
58
+  };
59
+
60
+  const cancelActive = () => {
61
+    clearTimeout(activeDefer);
62
+    activeDefer = undefined;
63
+
64
+    if (activatableEle) {
65
+      removeActivated(false);
66
+      activatableEle = undefined;
67
+    }
68
+  };
69
+
70
+  const pointerDown = ev => {
71
+    if (activatableEle) {
72
+      return;
73
+    }
74
+
75
+    setActivatedElement(getActivatableTarget(ev), ev);
76
+  };
77
+
78
+  const pointerUp = ev => {
79
+    setActivatedElement(undefined, ev);
80
+  };
81
+
82
+  const setActivatedElement = (el, ev) => {
83
+    // do nothing
84
+    if (el && el === activatableEle) {
85
+      return;
86
+    }
87
+
88
+    clearTimeout(activeDefer);
89
+    activeDefer = undefined;
90
+    const {
91
+      x,
92
+      y
93
+    } = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_0__.p)(ev); // deactivate selected
94
+
95
+    if (activatableEle) {
96
+      if (clearDefers.has(activatableEle)) {
97
+        throw new Error('internal error');
98
+      }
99
+
100
+      if (!activatableEle.classList.contains(ACTIVATED)) {
101
+        addActivated(activatableEle, x, y);
102
+      }
103
+
104
+      removeActivated(true);
105
+    } // activate
106
+
107
+
108
+    if (el) {
109
+      const deferId = clearDefers.get(el);
110
+
111
+      if (deferId) {
112
+        clearTimeout(deferId);
113
+        clearDefers.delete(el);
114
+      }
115
+
116
+      const delay = isInstant(el) ? 0 : ADD_ACTIVATED_DEFERS;
117
+      el.classList.remove(ACTIVATED);
118
+      activeDefer = setTimeout(() => {
119
+        addActivated(el, x, y);
120
+        activeDefer = undefined;
121
+      }, delay);
122
+    }
123
+
124
+    activatableEle = el;
125
+  };
126
+
127
+  const addActivated = (el, x, y) => {
128
+    lastActivated = Date.now();
129
+    el.classList.add(ACTIVATED);
130
+    if (!useRippleEffect) return;
131
+    const rippleEffect = getRippleEffect(el);
132
+
133
+    if (rippleEffect !== null) {
134
+      removeRipple();
135
+      activeRipple = rippleEffect.addRipple(x, y);
136
+    }
137
+  };
138
+
139
+  const removeRipple = () => {
140
+    if (activeRipple !== undefined) {
141
+      activeRipple.then(remove => remove());
142
+      activeRipple = undefined;
143
+    }
144
+  };
145
+
146
+  const removeActivated = smooth => {
147
+    removeRipple();
148
+    const active = activatableEle;
149
+
150
+    if (!active) {
151
+      return;
152
+    }
153
+
154
+    const time = CLEAR_STATE_DEFERS - Date.now() + lastActivated;
155
+
156
+    if (smooth && time > 0 && !isInstant(active)) {
157
+      const deferId = setTimeout(() => {
158
+        active.classList.remove(ACTIVATED);
159
+        clearDefers.delete(active);
160
+      }, CLEAR_STATE_DEFERS);
161
+      clearDefers.set(active, deferId);
162
+    } else {
163
+      active.classList.remove(ACTIVATED);
164
+    }
165
+  };
166
+
167
+  const doc = document;
168
+  doc.addEventListener('ionGestureCaptured', cancelActive);
169
+  doc.addEventListener('touchstart', onTouchStart, true);
170
+  doc.addEventListener('touchcancel', onTouchEnd, true);
171
+  doc.addEventListener('touchend', onTouchEnd, true);
172
+  /**
173
+   * Tap click effects such as the ripple effect should
174
+   * not happen when scrolling. For example, if a user scrolls
175
+   * the page but also happens to do a touchstart on a button
176
+   * as part of the scroll, the ripple effect should not
177
+   * be dispatched. The ripple effect should only happen
178
+   * if the button is activated and the page is not scrolling.
179
+   *
180
+   * pointercancel is dispatched on a gesture when scrolling
181
+   * starts, so this lets us avoid having to listen for
182
+   * ion-content's scroll events.
183
+   */
184
+
185
+  doc.addEventListener('pointercancel', cancelActive, true);
186
+  doc.addEventListener('mousedown', onMouseDown, true);
187
+  doc.addEventListener('mouseup', onMouseUp, true);
188
+};
189
+
190
+const getActivatableTarget = ev => {
191
+  if (ev.composedPath !== undefined) {
192
+    /**
193
+     * composedPath returns EventTarget[]. However,
194
+     * objects other than Element can be targets too.
195
+     * For example, AudioContext can be a target. In this
196
+     * case, we know that the event is a UIEvent so we
197
+     * can assume that the path will contain either Element
198
+     * or ShadowRoot.
199
+     */
200
+    const path = ev.composedPath();
201
+
202
+    for (let i = 0; i < path.length - 2; i++) {
203
+      const el = path[i];
204
+
205
+      if (!(el instanceof ShadowRoot) && el.classList.contains('ion-activatable')) {
206
+        return el;
207
+      }
208
+    }
209
+  } else {
210
+    return ev.target.closest('.ion-activatable');
211
+  }
212
+};
213
+
214
+const isInstant = el => {
215
+  return el.classList.contains('ion-activatable-instant');
216
+};
217
+
218
+const getRippleEffect = el => {
219
+  if (el.shadowRoot) {
220
+    const ripple = el.shadowRoot.querySelector('ion-ripple-effect');
221
+
222
+    if (ripple) {
223
+      return ripple;
224
+    }
225
+  }
226
+
227
+  return el.querySelector('ion-ripple-effect');
228
+};
229
+
230
+const ACTIVATED = 'ion-activated';
231
+const ADD_ACTIVATED_DEFERS = 200;
232
+const CLEAR_STATE_DEFERS = 200;
233
+const MOUSE_WAIT = 2500;
234
+
235
+
236
+/***/ })
237
+
238
+}]);
239
+//# sourceMappingURL=node_modules_ionic_core_dist_esm_index-0bc00b33_js.js.map

File diff suppressed because it is too large
+ 1 - 0
www/node_modules_ionic_core_dist_esm_index-0bc00b33_js.js.map


+ 526 - 0
www/node_modules_ionic_core_dist_esm_input-shims-6ed8f5a5_js.js

@@ -0,0 +1,526 @@
1
+"use strict";
2
+(self["webpackChunkapp"] = self["webpackChunkapp"] || []).push([["node_modules_ionic_core_dist_esm_input-shims-6ed8f5a5_js"],{
3
+
4
+/***/ 4508:
5
+/*!*******************************************************************!*\
6
+  !*** ./node_modules/@ionic/core/dist/esm/input-shims-6ed8f5a5.js ***!
7
+  \*******************************************************************/
8
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
9
+
10
+__webpack_require__.r(__webpack_exports__);
11
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
12
+/* harmony export */   "startInputShims": () => (/* binding */ startInputShims)
13
+/* harmony export */ });
14
+/* harmony import */ var _Users_simplicoltd_projects_fm99_rev_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js */ 1670);
15
+/* harmony import */ var _index_5d0c8232_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./index-5d0c8232.js */ 3081);
16
+/* harmony import */ var _helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./helpers-3b390e48.js */ 9234);
17
+/* harmony import */ var _index_c4b11676_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./index-c4b11676.js */ 9273);
18
+
19
+
20
+/*!
21
+ * (C) Ionic http://ionicframework.com - MIT License
22
+ */
23
+
24
+
25
+
26
+const cloneMap = new WeakMap();
27
+
28
+const relocateInput = (componentEl, inputEl, shouldRelocate, inputRelativeY = 0) => {
29
+  if (cloneMap.has(componentEl) === shouldRelocate) {
30
+    return;
31
+  }
32
+
33
+  if (shouldRelocate) {
34
+    addClone(componentEl, inputEl, inputRelativeY);
35
+  } else {
36
+    removeClone(componentEl, inputEl);
37
+  }
38
+};
39
+
40
+const isFocused = input => {
41
+  return input === input.getRootNode().activeElement;
42
+};
43
+
44
+const addClone = (componentEl, inputEl, inputRelativeY) => {
45
+  // this allows for the actual input to receive the focus from
46
+  // the user's touch event, but before it receives focus, it
47
+  // moves the actual input to a location that will not screw
48
+  // up the app's layout, and does not allow the native browser
49
+  // to attempt to scroll the input into place (messing up headers/footers)
50
+  // the cloned input fills the area of where native input should be
51
+  // while the native input fakes out the browser by relocating itself
52
+  // before it receives the actual focus event
53
+  // We hide the focused input (with the visible caret) invisible by making it scale(0),
54
+  const parentEl = inputEl.parentNode; // DOM WRITES
55
+
56
+  const clonedEl = inputEl.cloneNode(false);
57
+  clonedEl.classList.add('cloned-input');
58
+  clonedEl.tabIndex = -1;
59
+  parentEl.appendChild(clonedEl);
60
+  cloneMap.set(componentEl, clonedEl);
61
+  const doc = componentEl.ownerDocument;
62
+  const tx = doc.dir === 'rtl' ? 9999 : -9999;
63
+  componentEl.style.pointerEvents = 'none';
64
+  inputEl.style.transform = `translate3d(${tx}px,${inputRelativeY}px,0) scale(0)`;
65
+};
66
+
67
+const removeClone = (componentEl, inputEl) => {
68
+  const clone = cloneMap.get(componentEl);
69
+
70
+  if (clone) {
71
+    cloneMap.delete(componentEl);
72
+    clone.remove();
73
+  }
74
+
75
+  componentEl.style.pointerEvents = '';
76
+  inputEl.style.transform = '';
77
+};
78
+
79
+const enableHideCaretOnScroll = (componentEl, inputEl, scrollEl) => {
80
+  if (!scrollEl || !inputEl) {
81
+    return () => {
82
+      return;
83
+    };
84
+  }
85
+
86
+  const scrollHideCaret = shouldHideCaret => {
87
+    if (isFocused(inputEl)) {
88
+      relocateInput(componentEl, inputEl, shouldHideCaret);
89
+    }
90
+  };
91
+
92
+  const onBlur = () => relocateInput(componentEl, inputEl, false);
93
+
94
+  const hideCaret = () => scrollHideCaret(true);
95
+
96
+  const showCaret = () => scrollHideCaret(false);
97
+
98
+  (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.a)(scrollEl, 'ionScrollStart', hideCaret);
99
+  (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.a)(scrollEl, 'ionScrollEnd', showCaret);
100
+  inputEl.addEventListener('blur', onBlur);
101
+  return () => {
102
+    (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.b)(scrollEl, 'ionScrollStart', hideCaret);
103
+    (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.b)(scrollEl, 'ionScrollEnd', showCaret);
104
+    inputEl.addEventListener('ionBlur', onBlur);
105
+  };
106
+};
107
+
108
+const SKIP_SELECTOR = 'input, textarea, [no-blur], [contenteditable]';
109
+
110
+const enableInputBlurring = () => {
111
+  let focused = true;
112
+  let didScroll = false;
113
+  const doc = document;
114
+
115
+  const onScroll = () => {
116
+    didScroll = true;
117
+  };
118
+
119
+  const onFocusin = () => {
120
+    focused = true;
121
+  };
122
+
123
+  const onTouchend = ev => {
124
+    // if app did scroll return early
125
+    if (didScroll) {
126
+      didScroll = false;
127
+      return;
128
+    }
129
+
130
+    const active = doc.activeElement;
131
+
132
+    if (!active) {
133
+      return;
134
+    } // only blur if the active element is a text-input or a textarea
135
+
136
+
137
+    if (active.matches(SKIP_SELECTOR)) {
138
+      return;
139
+    } // if the selected target is the active element, do not blur
140
+
141
+
142
+    const tapped = ev.target;
143
+
144
+    if (tapped === active) {
145
+      return;
146
+    }
147
+
148
+    if (tapped.matches(SKIP_SELECTOR) || tapped.closest(SKIP_SELECTOR)) {
149
+      return;
150
+    }
151
+
152
+    focused = false; // TODO: find a better way, why 50ms?
153
+
154
+    setTimeout(() => {
155
+      if (!focused) {
156
+        active.blur();
157
+      }
158
+    }, 50);
159
+  };
160
+
161
+  (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.a)(doc, 'ionScrollStart', onScroll);
162
+  doc.addEventListener('focusin', onFocusin, true);
163
+  doc.addEventListener('touchend', onTouchend, false);
164
+  return () => {
165
+    (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.b)(doc, 'ionScrollStart', onScroll, true);
166
+    doc.removeEventListener('focusin', onFocusin, true);
167
+    doc.removeEventListener('touchend', onTouchend, false);
168
+  };
169
+};
170
+
171
+const SCROLL_ASSIST_SPEED = 0.3;
172
+
173
+const getScrollData = (componentEl, contentEl, keyboardHeight) => {
174
+  var _a;
175
+
176
+  const itemEl = (_a = componentEl.closest('ion-item,[ion-item]')) !== null && _a !== void 0 ? _a : componentEl;
177
+  return calcScrollData(itemEl.getBoundingClientRect(), contentEl.getBoundingClientRect(), keyboardHeight, componentEl.ownerDocument.defaultView.innerHeight);
178
+};
179
+
180
+const calcScrollData = (inputRect, contentRect, keyboardHeight, platformHeight) => {
181
+  // compute input's Y values relative to the body
182
+  const inputTop = inputRect.top;
183
+  const inputBottom = inputRect.bottom; // compute visible area
184
+
185
+  const visibleAreaTop = contentRect.top;
186
+  const visibleAreaBottom = Math.min(contentRect.bottom, platformHeight - keyboardHeight); // compute safe area
187
+
188
+  const safeAreaTop = visibleAreaTop + 15;
189
+  const safeAreaBottom = visibleAreaBottom * 0.75; // figure out if each edge of the input is within the safe area
190
+
191
+  const distanceToBottom = safeAreaBottom - inputBottom;
192
+  const distanceToTop = safeAreaTop - inputTop; // desiredScrollAmount is the negated distance to the safe area according to our calculations.
193
+
194
+  const desiredScrollAmount = Math.round(distanceToBottom < 0 ? -distanceToBottom : distanceToTop > 0 ? -distanceToTop : 0); // our calculations make some assumptions that aren't always true, like the keyboard being closed when an input
195
+  // gets focus, so make sure we don't scroll the input above the visible area
196
+
197
+  const scrollAmount = Math.min(desiredScrollAmount, inputTop - visibleAreaTop);
198
+  const distance = Math.abs(scrollAmount);
199
+  const duration = distance / SCROLL_ASSIST_SPEED;
200
+  const scrollDuration = Math.min(400, Math.max(150, duration));
201
+  return {
202
+    scrollAmount,
203
+    scrollDuration,
204
+    scrollPadding: keyboardHeight,
205
+    inputSafeY: -(inputTop - safeAreaTop) + 4
206
+  };
207
+};
208
+
209
+const enableScrollAssist = (componentEl, inputEl, contentEl, footerEl, keyboardHeight) => {
210
+  let coord;
211
+
212
+  const touchStart = ev => {
213
+    coord = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.p)(ev);
214
+  };
215
+
216
+  const touchEnd = ev => {
217
+    // input cover touchend/mouseup
218
+    if (!coord) {
219
+      return;
220
+    } // get where the touchend/mouseup ended
221
+
222
+
223
+    const endCoord = (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.p)(ev); // focus this input if the pointer hasn't moved XX pixels
224
+    // and the input doesn't already have focus
225
+
226
+    if (!hasPointerMoved(6, coord, endCoord) && !isFocused(inputEl)) {
227
+      // begin the input focus process
228
+      jsSetFocus(componentEl, inputEl, contentEl, footerEl, keyboardHeight);
229
+    }
230
+  };
231
+
232
+  componentEl.addEventListener('touchstart', touchStart, {
233
+    capture: true,
234
+    passive: true
235
+  });
236
+  componentEl.addEventListener('touchend', touchEnd, true);
237
+  return () => {
238
+    componentEl.removeEventListener('touchstart', touchStart, true);
239
+    componentEl.removeEventListener('touchend', touchEnd, true);
240
+  };
241
+};
242
+
243
+const jsSetFocus = /*#__PURE__*/function () {
244
+  var _ref = (0,_Users_simplicoltd_projects_fm99_rev_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (componentEl, inputEl, contentEl, footerEl, keyboardHeight) {
245
+    if (!contentEl && !footerEl) {
246
+      return;
247
+    }
248
+
249
+    const scrollData = getScrollData(componentEl, contentEl || footerEl, keyboardHeight);
250
+
251
+    if (contentEl && Math.abs(scrollData.scrollAmount) < 4) {
252
+      // the text input is in a safe position that doesn't
253
+      // require it to be scrolled into view, just set focus now
254
+      inputEl.focus();
255
+      return;
256
+    } // temporarily move the focus to the focus holder so the browser
257
+    // doesn't freak out while it's trying to get the input in place
258
+    // at this point the native text input still does not have focus
259
+
260
+
261
+    relocateInput(componentEl, inputEl, true, scrollData.inputSafeY);
262
+    inputEl.focus();
263
+    /**
264
+     * Relocating/Focusing input causes the
265
+     * click event to be cancelled, so
266
+     * manually fire one here.
267
+     */
268
+
269
+    (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.r)(() => componentEl.click());
270
+
271
+    if (typeof window !== 'undefined') {
272
+      let scrollContentTimeout;
273
+
274
+      const scrollContent = /*#__PURE__*/function () {
275
+        var _ref2 = (0,_Users_simplicoltd_projects_fm99_rev_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () {
276
+          // clean up listeners and timeouts
277
+          if (scrollContentTimeout !== undefined) {
278
+            clearTimeout(scrollContentTimeout);
279
+          }
280
+
281
+          window.removeEventListener('ionKeyboardDidShow', doubleKeyboardEventListener);
282
+          window.removeEventListener('ionKeyboardDidShow', scrollContent); // scroll the input into place
283
+
284
+          if (contentEl) {
285
+            yield (0,_index_5d0c8232_js__WEBPACK_IMPORTED_MODULE_1__.c)(contentEl, 0, scrollData.scrollAmount, scrollData.scrollDuration);
286
+          } // the scroll view is in the correct position now
287
+          // give the native text input focus
288
+
289
+
290
+          relocateInput(componentEl, inputEl, false, scrollData.inputSafeY); // ensure this is the focused input
291
+
292
+          inputEl.focus();
293
+        });
294
+
295
+        return function scrollContent() {
296
+          return _ref2.apply(this, arguments);
297
+        };
298
+      }();
299
+
300
+      const doubleKeyboardEventListener = () => {
301
+        window.removeEventListener('ionKeyboardDidShow', doubleKeyboardEventListener);
302
+        window.addEventListener('ionKeyboardDidShow', scrollContent);
303
+      };
304
+
305
+      if (contentEl) {
306
+        const scrollEl = yield (0,_index_5d0c8232_js__WEBPACK_IMPORTED_MODULE_1__.g)(contentEl);
307
+        /**
308
+         * scrollData will only consider the amount we need
309
+         * to scroll in order to properly bring the input
310
+         * into view. It will not consider the amount
311
+         * we can scroll in the content element.
312
+         * As a result, scrollData may request a greater
313
+         * scroll position than is currently available
314
+         * in the DOM. If this is the case, we need to
315
+         * wait for the webview to resize/the keyboard
316
+         * to show in order for additional scroll
317
+         * bandwidth to become available.
318
+         */
319
+
320
+        const totalScrollAmount = scrollEl.scrollHeight - scrollEl.clientHeight;
321
+
322
+        if (scrollData.scrollAmount > totalScrollAmount - scrollEl.scrollTop) {
323
+          /**
324
+           * On iOS devices, the system will show a "Passwords" bar above the keyboard
325
+           * after the initial keyboard is shown. This prevents the webview from resizing
326
+           * until the "Passwords" bar is shown, so we need to wait for that to happen first.
327
+           */
328
+          if (inputEl.type === 'password') {
329
+            // Add 50px to account for the "Passwords" bar
330
+            scrollData.scrollAmount += 50;
331
+            window.addEventListener('ionKeyboardDidShow', doubleKeyboardEventListener);
332
+          } else {
333
+            window.addEventListener('ionKeyboardDidShow', scrollContent);
334
+          }
335
+          /**
336
+           * This should only fire in 2 instances:
337
+           * 1. The app is very slow.
338
+           * 2. The app is running in a browser on an old OS
339
+           * that does not support Ionic Keyboard Events
340
+           */
341
+
342
+
343
+          scrollContentTimeout = setTimeout(scrollContent, 1000);
344
+          return;
345
+        }
346
+      }
347
+
348
+      scrollContent();
349
+    }
350
+  });
351
+
352
+  return function jsSetFocus(_x, _x2, _x3, _x4, _x5) {
353
+    return _ref.apply(this, arguments);
354
+  };
355
+}();
356
+
357
+const hasPointerMoved = (threshold, startCoord, endCoord) => {
358
+  if (startCoord && endCoord) {
359
+    const deltaX = startCoord.x - endCoord.x;
360
+    const deltaY = startCoord.y - endCoord.y;
361
+    const distance = deltaX * deltaX + deltaY * deltaY;
362
+    return distance > threshold * threshold;
363
+  }
364
+
365
+  return false;
366
+};
367
+
368
+const PADDING_TIMER_KEY = '$ionPaddingTimer';
369
+
370
+const enableScrollPadding = keyboardHeight => {
371
+  const doc = document;
372
+
373
+  const onFocusin = ev => {
374
+    setScrollPadding(ev.target, keyboardHeight);
375
+  };
376
+
377
+  const onFocusout = ev => {
378
+    setScrollPadding(ev.target, 0);
379
+  };
380
+
381
+  doc.addEventListener('focusin', onFocusin);
382
+  doc.addEventListener('focusout', onFocusout);
383
+  return () => {
384
+    doc.removeEventListener('focusin', onFocusin);
385
+    doc.removeEventListener('focusout', onFocusout);
386
+  };
387
+};
388
+
389
+const setScrollPadding = (input, keyboardHeight) => {
390
+  var _a, _b;
391
+
392
+  if (input.tagName !== 'INPUT') {
393
+    return;
394
+  }
395
+
396
+  if (input.parentElement && input.parentElement.tagName === 'ION-INPUT') {
397
+    return;
398
+  }
399
+
400
+  if (((_b = (_a = input.parentElement) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.tagName) === 'ION-SEARCHBAR') {
401
+    return;
402
+  }
403
+
404
+  const el = (0,_index_5d0c8232_js__WEBPACK_IMPORTED_MODULE_1__.f)(input);
405
+
406
+  if (el === null) {
407
+    return;
408
+  }
409
+
410
+  const timer = el[PADDING_TIMER_KEY];
411
+
412
+  if (timer) {
413
+    clearTimeout(timer);
414
+  }
415
+
416
+  if (keyboardHeight > 0) {
417
+    el.style.setProperty('--keyboard-offset', `${keyboardHeight}px`);
418
+  } else {
419
+    el[PADDING_TIMER_KEY] = setTimeout(() => {
420
+      el.style.setProperty('--keyboard-offset', '0px');
421
+    }, 120);
422
+  }
423
+};
424
+
425
+const INPUT_BLURRING = true;
426
+const SCROLL_PADDING = true;
427
+
428
+const startInputShims = config => {
429
+  const doc = document;
430
+  const keyboardHeight = config.getNumber('keyboardHeight', 290);
431
+  const scrollAssist = config.getBoolean('scrollAssist', true);
432
+  const hideCaret = config.getBoolean('hideCaretOnScroll', true);
433
+  const inputBlurring = config.getBoolean('inputBlurring', true);
434
+  const scrollPadding = config.getBoolean('scrollPadding', true);
435
+  const inputs = Array.from(doc.querySelectorAll('ion-input, ion-textarea'));
436
+  const hideCaretMap = new WeakMap();
437
+  const scrollAssistMap = new WeakMap();
438
+
439
+  const registerInput = /*#__PURE__*/function () {
440
+    var _ref3 = (0,_Users_simplicoltd_projects_fm99_rev_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* (componentEl) {
441
+      yield new Promise(resolve => (0,_helpers_3b390e48_js__WEBPACK_IMPORTED_MODULE_2__.c)(componentEl, resolve));
442
+      const inputRoot = componentEl.shadowRoot || componentEl;
443
+      const inputEl = inputRoot.querySelector('input') || inputRoot.querySelector('textarea');
444
+      const scrollEl = (0,_index_5d0c8232_js__WEBPACK_IMPORTED_MODULE_1__.f)(componentEl);
445
+      const footerEl = !scrollEl ? componentEl.closest('ion-footer') : null;
446
+
447
+      if (!inputEl) {
448
+        return;
449
+      }
450
+
451
+      if (!!scrollEl && hideCaret && !hideCaretMap.has(componentEl)) {
452
+        const rmFn = enableHideCaretOnScroll(componentEl, inputEl, scrollEl);
453
+        hideCaretMap.set(componentEl, rmFn);
454
+      }
455
+      /**
456
+       * date/datetime-locale inputs on mobile devices show date picker
457
+       * overlays instead of keyboards. As a result, scroll assist is
458
+       * not needed. This also works around a bug in iOS <16 where
459
+       * scroll assist causes the browser to lock up. See FW-1997.
460
+       */
461
+
462
+
463
+      const isDateInput = inputEl.type === 'date' || inputEl.type === 'datetime-local';
464
+
465
+      if (!isDateInput && (!!scrollEl || !!footerEl) && scrollAssist && !scrollAssistMap.has(componentEl)) {
466
+        const rmFn = enableScrollAssist(componentEl, inputEl, scrollEl, footerEl, keyboardHeight);
467
+        scrollAssistMap.set(componentEl, rmFn);
468
+      }
469
+    });
470
+
471
+    return function registerInput(_x6) {
472
+      return _ref3.apply(this, arguments);
473
+    };
474
+  }();
475
+
476
+  const unregisterInput = componentEl => {
477
+    if (hideCaret) {
478
+      const fn = hideCaretMap.get(componentEl);
479
+
480
+      if (fn) {
481
+        fn();
482
+      }
483
+
484
+      hideCaretMap.delete(componentEl);
485
+    }
486
+
487
+    if (scrollAssist) {
488
+      const fn = scrollAssistMap.get(componentEl);
489
+
490
+      if (fn) {
491
+        fn();
492
+      }
493
+
494
+      scrollAssistMap.delete(componentEl);
495
+    }
496
+  };
497
+
498
+  if (inputBlurring && INPUT_BLURRING) {
499
+    enableInputBlurring();
500
+  }
501
+
502
+  if (scrollPadding && SCROLL_PADDING) {
503
+    enableScrollPadding(keyboardHeight);
504
+  } // Input might be already loaded in the DOM before ion-device-hacks did.
505
+  // At this point we need to look for all of the inputs not registered yet
506
+  // and register them.
507
+
508
+
509
+  for (const input of inputs) {
510
+    registerInput(input);
511
+  }
512
+
513
+  doc.addEventListener('ionInputDidLoad', ev => {
514
+    registerInput(ev.detail);
515
+  });
516
+  doc.addEventListener('ionInputDidUnload', ev => {
517
+    unregisterInput(ev.detail);
518
+  });
519
+};
520
+
521
+
522
+
523
+/***/ })
524
+
525
+}]);
526
+//# sourceMappingURL=node_modules_ionic_core_dist_esm_input-shims-6ed8f5a5_js.js.map

File diff suppressed because it is too large
+ 1 - 0
www/node_modules_ionic_core_dist_esm_input-shims-6ed8f5a5_js.js.map


File diff suppressed because it is too large
+ 799 - 0
www/node_modules_ionic_core_dist_esm_ion-accordion_2_entry_js.js


File diff suppressed because it is too large
+ 1 - 0
www/node_modules_ionic_core_dist_esm_ion-accordion_2_entry_js.js.map


File diff suppressed because it is too large
+ 450 - 0
www/node_modules_ionic_core_dist_esm_ion-action-sheet_entry_js.js


File diff suppressed because it is too large
+ 1 - 0
www/node_modules_ionic_core_dist_esm_ion-action-sheet_entry_js.js.map


File diff suppressed because it is too large
+ 780 - 0
www/node_modules_ionic_core_dist_esm_ion-alert_entry_js.js


File diff suppressed because it is too large
+ 1 - 0
www/node_modules_ionic_core_dist_esm_ion-alert_entry_js.js.map


File diff suppressed because it is too large
+ 1726 - 0
www/node_modules_ionic_core_dist_esm_ion-app_8_entry_js.js


File diff suppressed because it is too large
+ 1 - 0
www/node_modules_ionic_core_dist_esm_ion-app_8_entry_js.js.map


File diff suppressed because it is too large
+ 160 - 0
www/node_modules_ionic_core_dist_esm_ion-avatar_3_entry_js.js


File diff suppressed because it is too large
+ 1 - 0
www/node_modules_ionic_core_dist_esm_ion-avatar_3_entry_js.js.map


File diff suppressed because it is too large
+ 257 - 0
www/node_modules_ionic_core_dist_esm_ion-back-button_entry_js.js


File diff suppressed because it is too large
+ 1 - 0
www/node_modules_ionic_core_dist_esm_ion-back-button_entry_js.js.map


+ 97 - 0
www/node_modules_ionic_core_dist_esm_ion-backdrop_entry_js.js

@@ -0,0 +1,97 @@
1
+"use strict";
2
+(self["webpackChunkapp"] = self["webpackChunkapp"] || []).push([["node_modules_ionic_core_dist_esm_ion-backdrop_entry_js"],{
3
+
4
+/***/ 3059:
5
+/*!*****************************************************************!*\
6
+  !*** ./node_modules/@ionic/core/dist/esm/ion-backdrop.entry.js ***!
7
+  \*****************************************************************/
8
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
9
+
10
+__webpack_require__.r(__webpack_exports__);
11
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
12
+/* harmony export */   "ion_backdrop": () => (/* binding */ Backdrop)
13
+/* harmony export */ });
14
+/* harmony import */ var _index_8e692445_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./index-8e692445.js */ 1559);
15
+/* harmony import */ var _ionic_global_c95cf239_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ionic-global-c95cf239.js */ 8607);
16
+/* harmony import */ var _gesture_controller_17060b7c_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./gesture-controller-17060b7c.js */ 6379);
17
+/*!
18
+ * (C) Ionic http://ionicframework.com - MIT License
19
+ */
20
+
21
+
22
+
23
+const backdropIosCss = ":host{left:0;right:0;top:0;bottom:0;display:block;position:absolute;-webkit-transform:translateZ(0);transform:translateZ(0);contain:strict;cursor:pointer;opacity:0.01;-ms-touch-action:none;touch-action:none;z-index:2}:host(.backdrop-hide){background:transparent}:host(.backdrop-no-tappable){cursor:auto}:host{background-color:var(--ion-backdrop-color, #000)}";
24
+const backdropMdCss = ":host{left:0;right:0;top:0;bottom:0;display:block;position:absolute;-webkit-transform:translateZ(0);transform:translateZ(0);contain:strict;cursor:pointer;opacity:0.01;-ms-touch-action:none;touch-action:none;z-index:2}:host(.backdrop-hide){background:transparent}:host(.backdrop-no-tappable){cursor:auto}:host{background-color:var(--ion-backdrop-color, #000)}";
25
+const Backdrop = class {
26
+  constructor(hostRef) {
27
+    (0,_index_8e692445_js__WEBPACK_IMPORTED_MODULE_0__.r)(this, hostRef);
28
+    this.ionBackdropTap = (0,_index_8e692445_js__WEBPACK_IMPORTED_MODULE_0__.e)(this, "ionBackdropTap", 7);
29
+    this.blocker = _gesture_controller_17060b7c_js__WEBPACK_IMPORTED_MODULE_2__.G.createBlocker({
30
+      disableScroll: true
31
+    });
32
+    /**
33
+     * If `true`, the backdrop will be visible.
34
+     */
35
+
36
+    this.visible = true;
37
+    /**
38
+     * If `true`, the backdrop will can be clicked and will emit the `ionBackdropTap` event.
39
+     */
40
+
41
+    this.tappable = true;
42
+    /**
43
+     * If `true`, the backdrop will stop propagation on tap.
44
+     */
45
+
46
+    this.stopPropagation = true;
47
+  }
48
+
49
+  connectedCallback() {
50
+    if (this.stopPropagation) {
51
+      this.blocker.block();
52
+    }
53
+  }
54
+
55
+  disconnectedCallback() {
56
+    this.blocker.unblock();
57
+  }
58
+
59
+  onMouseDown(ev) {
60
+    this.emitTap(ev);
61
+  }
62
+
63
+  emitTap(ev) {
64
+    if (this.stopPropagation) {
65
+      ev.preventDefault();
66
+      ev.stopPropagation();
67
+    }
68
+
69
+    if (this.tappable) {
70
+      this.ionBackdropTap.emit();
71
+    }
72
+  }
73
+
74
+  render() {
75
+    const mode = (0,_ionic_global_c95cf239_js__WEBPACK_IMPORTED_MODULE_1__.b)(this);
76
+    return (0,_index_8e692445_js__WEBPACK_IMPORTED_MODULE_0__.h)(_index_8e692445_js__WEBPACK_IMPORTED_MODULE_0__.H, {
77
+      tabindex: "-1",
78
+      "aria-hidden": "true",
79
+      class: {
80
+        [mode]: true,
81
+        'backdrop-hide': !this.visible,
82
+        'backdrop-no-tappable': !this.tappable
83
+      }
84
+    });
85
+  }
86
+
87
+};
88
+Backdrop.style = {
89
+  ios: backdropIosCss,
90
+  md: backdropMdCss
91
+};
92
+
93
+
94
+/***/ })
95
+
96
+}]);
97
+//# sourceMappingURL=node_modules_ionic_core_dist_esm_ion-backdrop_entry_js.js.map

File diff suppressed because it is too large
+ 1 - 0
www/node_modules_ionic_core_dist_esm_ion-backdrop_entry_js.js.map


File diff suppressed because it is too large
+ 414 - 0
www/node_modules_ionic_core_dist_esm_ion-breadcrumb_2_entry_js.js


File diff suppressed because it is too large
+ 1 - 0
www/node_modules_ionic_core_dist_esm_ion-breadcrumb_2_entry_js.js.map


File diff suppressed because it is too large
+ 770 - 0
www/node_modules_ionic_core_dist_esm_ion-button_2_entry_js.js


File diff suppressed because it is too large
+ 1 - 0
www/node_modules_ionic_core_dist_esm_ion-button_2_entry_js.js.map


File diff suppressed because it is too large
+ 299 - 0
www/node_modules_ionic_core_dist_esm_ion-card_5_entry_js.js


+ 0 - 0
www/node_modules_ionic_core_dist_esm_ion-card_5_entry_js.js.map


Some files were not shown because too many files changed in this diff

tum/whitesports - Gogs: Simplico Git Service

説明なし

ms-blogs.php 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. <?php
  2. /**
  3. * Site/blog functions that work with the blogs table and related data.
  4. *
  5. * @package WordPress
  6. * @subpackage Multisite
  7. * @since MU (3.0.0)
  8. */
  9. require_once ABSPATH . WPINC . '/ms-site.php';
  10. require_once ABSPATH . WPINC . '/ms-network.php';
  11. /**
  12. * Update the last_updated field for the current site.
  13. *
  14. * @since MU (3.0.0)
  15. */
  16. function wpmu_update_blogs_date() {
  17. $site_id = get_current_blog_id();
  18. update_blog_details( $site_id, array( 'last_updated' => current_time( 'mysql', true ) ) );
  19. /**
  20. * Fires after the blog details are updated.
  21. *
  22. * @since MU (3.0.0)
  23. *
  24. * @param int $blog_id Site ID.
  25. */
  26. do_action( 'wpmu_blog_updated', $site_id );
  27. }
  28. /**
  29. * Get a full blog URL, given a blog ID.
  30. *
  31. * @since MU (3.0.0)
  32. *
  33. * @param int $blog_id Blog ID.
  34. * @return string Full URL of the blog if found. Empty string if not.
  35. */
  36. function get_blogaddress_by_id( $blog_id ) {
  37. $bloginfo = get_site( (int) $blog_id );
  38. if ( empty( $bloginfo ) ) {
  39. return '';
  40. }
  41. $scheme = parse_url( $bloginfo->home, PHP_URL_SCHEME );
  42. $scheme = empty( $scheme ) ? 'http' : $scheme;
  43. return esc_url( $scheme . '://' . $bloginfo->domain . $bloginfo->path );
  44. }
  45. /**
  46. * Get a full blog URL, given a blog name.
  47. *
  48. * @since MU (3.0.0)
  49. *
  50. * @param string $blogname The (subdomain or directory) name
  51. * @return string
  52. */
  53. function get_blogaddress_by_name( $blogname ) {
  54. if ( is_subdomain_install() ) {
  55. if ( 'main' === $blogname ) {
  56. $blogname = 'www';
  57. }
  58. $url = rtrim( network_home_url(), '/' );
  59. if ( ! empty( $blogname ) ) {
  60. $url = preg_replace( '|^([^\.]+://)|', '${1}' . $blogname . '.', $url );
  61. }
  62. } else {
  63. $url = network_home_url( $blogname );
  64. }
  65. return esc_url( $url . '/' );
  66. }
  67. /**
  68. * Retrieves a sites ID given its (subdomain or directory) slug.
  69. *
  70. * @since MU (3.0.0)
  71. * @since 4.7.0 Converted to use `get_sites()`.
  72. *
  73. * @param string $slug A site's slug.
  74. * @return int|null The site ID, or null if no site is found for the given slug.
  75. */
  76. function get_id_from_blogname( $slug ) {
  77. $current_network = get_network();
  78. $slug = trim( $slug, '/' );
  79. if ( is_subdomain_install() ) {
  80. $domain = $slug . '.' . preg_replace( '|^www\.|', '', $current_network->domain );
  81. $path = $current_network->path;
  82. } else {
  83. $domain = $current_network->domain;
  84. $path = $current_network->path . $slug . '/';
  85. }
  86. $site_ids = get_sites(
  87. array(
  88. 'number' => 1,
  89. 'fields' => 'ids',
  90. 'domain' => $domain,
  91. 'path' => $path,
  92. 'update_site_meta_cache' => false,
  93. )
  94. );
  95. if ( empty( $site_ids ) ) {
  96. return null;
  97. }
  98. return array_shift( $site_ids );
  99. }
  100. /**
  101. * Retrieve the details for a blog from the blogs table and blog options.
  102. *
  103. * @since MU (3.0.0)
  104. *
  105. * @global wpdb $wpdb WordPress database abstraction object.
  106. *
  107. * @param int|string|array $fields Optional. A blog ID, a blog slug, or an array of fields to query against.
  108. * If not specified the current blog ID is used.
  109. * @param bool $get_all Whether to retrieve all details or only the details in the blogs table.
  110. * Default is true.
  111. * @return WP_Site|false Blog details on success. False on failure.
  112. */
  113. function get_blog_details( $fields = null, $get_all = true ) {
  114. global $wpdb;
  115. if ( is_array( $fields ) ) {
  116. if ( isset( $fields['blog_id'] ) ) {
  117. $blog_id = $fields['blog_id'];
  118. } elseif ( isset( $fields['domain'] ) && isset( $fields['path'] ) ) {
  119. $key = md5( $fields['domain'] . $fields['path'] );
  120. $blog = wp_cache_get( $key, 'blog-lookup' );
  121. if ( false !== $blog ) {
  122. return $blog;
  123. }
  124. if ( 'www.' === substr( $fields['domain'], 0, 4 ) ) {
  125. $nowww = substr( $fields['domain'], 4 );
  126. $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain IN (%s,%s) AND path = %s ORDER BY CHAR_LENGTH(domain) DESC", $nowww, $fields['domain'], $fields['path'] ) );
  127. } else {
  128. $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s AND path = %s", $fields['domain'], $fields['path'] ) );
  129. }
  130. if ( $blog ) {
  131. wp_cache_set( $blog->blog_id . 'short', $blog, 'blog-details' );
  132. $blog_id = $blog->blog_id;
  133. } else {
  134. return false;
  135. }
  136. } elseif ( isset( $fields['domain'] ) && is_subdomain_install() ) {
  137. $key = md5( $fields['domain'] );
  138. $blog = wp_cache_get( $key, 'blog-lookup' );
  139. if ( false !== $blog ) {
  140. return $blog;
  141. }
  142. if ( 'www.' === substr( $fields['domain'], 0, 4 ) ) {
  143. $nowww = substr( $fields['domain'], 4 );
  144. $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain IN (%s,%s) ORDER BY CHAR_LENGTH(domain) DESC", $nowww, $fields['domain'] ) );
  145. } else {
  146. $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s", $fields['domain'] ) );
  147. }
  148. if ( $blog ) {
  149. wp_cache_set( $blog->blog_id . 'short', $blog, 'blog-details' );
  150. $blog_id = $blog->blog_id;
  151. } else {
  152. return false;
  153. }
  154. } else {
  155. return false;
  156. }
  157. } else {
  158. if ( ! $fields ) {
  159. $blog_id = get_current_blog_id();
  160. } elseif ( ! is_numeric( $fields ) ) {
  161. $blog_id = get_id_from_blogname( $fields );
  162. } else {
  163. $blog_id = $fields;
  164. }
  165. }
  166. $blog_id = (int) $blog_id;
  167. $all = $get_all ? '' : 'short';
  168. $details = wp_cache_get( $blog_id . $all, 'blog-details' );
  169. if ( $details ) {
  170. if ( ! is_object( $details ) ) {
  171. if ( -1 == $details ) {
  172. return false;
  173. } else {
  174. // Clear old pre-serialized objects. Cache clients do better with that.
  175. wp_cache_delete( $blog_id . $all, 'blog-details' );
  176. unset( $details );
  177. }
  178. } else {
  179. return $details;
  180. }
  181. }
  182. // Try the other cache.
  183. if ( $get_all ) {
  184. $details = wp_cache_get( $blog_id . 'short', 'blog-details' );
  185. } else {
  186. $details = wp_cache_get( $blog_id, 'blog-details' );
  187. // If short was requested and full cache is set, we can return.
  188. if ( $details ) {
  189. if ( ! is_object( $details ) ) {
  190. if ( -1 == $details ) {
  191. return false;
  192. } else {
  193. // Clear old pre-serialized objects. Cache clients do better with that.
  194. wp_cache_delete( $blog_id, 'blog-details' );
  195. unset( $details );
  196. }
  197. } else {
  198. return $details;
  199. }
  200. }
  201. }
  202. if ( empty( $details ) ) {
  203. $details = WP_Site::get_instance( $blog_id );
  204. if ( ! $details ) {
  205. // Set the full cache.
  206. wp_cache_set( $blog_id, -1, 'blog-details' );
  207. return false;
  208. }
  209. }
  210. if ( ! $details instanceof WP_Site ) {
  211. $details = new WP_Site( $details );
  212. }
  213. if ( ! $get_all ) {
  214. wp_cache_set( $blog_id . $all, $details, 'blog-details' );
  215. return $details;
  216. }
  217. $switched_blog = false;
  218. if ( get_current_blog_id() !== $blog_id ) {
  219. switch_to_blog( $blog_id );
  220. $switched_blog = true;
  221. }
  222. $details->blogname = get_option( 'blogname' );
  223. $details->siteurl = get_option( 'siteurl' );
  224. $details->post_count = get_option( 'post_count' );
  225. $details->home = get_option( 'home' );
  226. if ( $switched_blog ) {
  227. restore_current_blog();
  228. }
  229. /**
  230. * Filters a blog's details.
  231. *
  232. * @since MU (3.0.0)
  233. * @deprecated 4.7.0 Use {@see 'site_details'} instead.
  234. *
  235. * @param WP_Site $details The blog details.
  236. */
  237. $details = apply_filters_deprecated( 'blog_details', array( $details ), '4.7.0', 'site_details' );
  238. wp_cache_set( $blog_id . $all, $details, 'blog-details' );
  239. $key = md5( $details->domain . $details->path );
  240. wp_cache_set( $key, $details, 'blog-lookup' );
  241. return $details;
  242. }
  243. /**
  244. * Clear the blog details cache.
  245. *
  246. * @since MU (3.0.0)
  247. *
  248. * @param int $blog_id Optional. Blog ID. Defaults to current blog.
  249. */
  250. function refresh_blog_details( $blog_id = 0 ) {
  251. $blog_id = (int) $blog_id;
  252. if ( ! $blog_id ) {
  253. $blog_id = get_current_blog_id();
  254. }
  255. clean_blog_cache( $blog_id );
  256. }
  257. /**
  258. * Update the details for a blog. Updates the blogs table for a given blog ID.
  259. *
  260. * @since MU (3.0.0)
  261. *
  262. * @global wpdb $wpdb WordPress database abstraction object.
  263. *
  264. * @param int $blog_id Blog ID.
  265. * @param array $details Array of details keyed by blogs table field names.
  266. * @return bool True if update succeeds, false otherwise.
  267. */
  268. function update_blog_details( $blog_id, $details = array() ) {
  269. global $wpdb;
  270. if ( empty( $details ) ) {
  271. return false;
  272. }
  273. if ( is_object( $details ) ) {
  274. $details = get_object_vars( $details );
  275. }
  276. $site = wp_update_site( $blog_id, $details );
  277. if ( is_wp_error( $site ) ) {
  278. return false;
  279. }
  280. return true;
  281. }
  282. /**
  283. * Cleans the site details cache for a site.
  284. *
  285. * @since 4.7.4
  286. *
  287. * @param int $site_id Optional. Site ID. Default is the current site ID.
  288. */
  289. function clean_site_details_cache( $site_id = 0 ) {
  290. $site_id = (int) $site_id;
  291. if ( ! $site_id ) {
  292. $site_id = get_current_blog_id();
  293. }
  294. wp_cache_delete( $site_id, 'site-details' );
  295. wp_cache_delete( $site_id, 'blog-details' );
  296. }
  297. /**
  298. * Retrieve option value for a given blog id based on name of option.
  299. *
  300. * If the option does not exist or does not have a value, then the return value
  301. * will be false. This is useful to check whether you need to install an option
  302. * and is commonly used during installation of plugin options and to test
  303. * whether upgrading is required.
  304. *
  305. * If the option was serialized then it will be unserialized when it is returned.
  306. *
  307. * @since MU (3.0.0)
  308. *
  309. * @param int $id A blog ID. Can be null to refer to the current blog.
  310. * @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
  311. * @param mixed $default Optional. Default value to return if the option does not exist.
  312. * @return mixed Value set for the option.
  313. */
  314. function get_blog_option( $id, $option, $default = false ) {
  315. $id = (int) $id;
  316. if ( empty( $id ) ) {
  317. $id = get_current_blog_id();
  318. }
  319. if ( get_current_blog_id() == $id ) {
  320. return get_option( $option, $default );
  321. }
  322. switch_to_blog( $id );
  323. $value = get_option( $option, $default );
  324. restore_current_blog();
  325. /**
  326. * Filters a blog option value.
  327. *
  328. * The dynamic portion of the hook name, `$option`, refers to the blog option name.
  329. *
  330. * @since 3.5.0
  331. *
  332. * @param string $value The option value.
  333. * @param int $id Blog ID.
  334. */
  335. return apply_filters( "blog_option_{$option}", $value, $id );
  336. }
  337. /**
  338. * Add a new option for a given blog ID.
  339. *
  340. * You do not need to serialize values. If the value needs to be serialized, then
  341. * it will be serialized before it is inserted into the database. Remember,
  342. * resources can not be serialized or added as an option.
  343. *
  344. * You can create options without values and then update the values later.
  345. * Existing options will not be updated and checks are performed to ensure that you
  346. * aren't adding a protected WordPress option. Care should be taken to not name
  347. * options the same as the ones which are protected.
  348. *
  349. * @since MU (3.0.0)
  350. *
  351. * @param int $id A blog ID. Can be null to refer to the current blog.
  352. * @param string $option Name of option to add. Expected to not be SQL-escaped.
  353. * @param mixed $value Optional. Option value, can be anything. Expected to not be SQL-escaped.
  354. * @return bool True if the option was added, false otherwise.
  355. */
  356. function add_blog_option( $id, $option, $value ) {
  357. $id = (int) $id;
  358. if ( empty( $id ) ) {
  359. $id = get_current_blog_id();
  360. }
  361. if ( get_current_blog_id() == $id ) {
  362. return add_option( $option, $value );
  363. }
  364. switch_to_blog( $id );
  365. $return = add_option( $option, $value );
  366. restore_current_blog();
  367. return $return;
  368. }
  369. /**
  370. * Removes option by name for a given blog ID. Prevents removal of protected WordPress options.
  371. *
  372. * @since MU (3.0.0)
  373. *
  374. * @param int $id A blog ID. Can be null to refer to the current blog.
  375. * @param string $option Name of option to remove. Expected to not be SQL-escaped.
  376. * @return bool True if the option was deleted, false otherwise.
  377. */
  378. function delete_blog_option( $id, $option ) {
  379. $id = (int) $id;
  380. if ( empty( $id ) ) {
  381. $id = get_current_blog_id();
  382. }
  383. if ( get_current_blog_id() == $id ) {
  384. return delete_option( $option );
  385. }
  386. switch_to_blog( $id );
  387. $return = delete_option( $option );
  388. restore_current_blog();
  389. return $return;
  390. }
  391. /**
  392. * Update an option for a particular blog.
  393. *
  394. * @since MU (3.0.0)
  395. *
  396. * @param int $id The blog ID.
  397. * @param string $option The option key.
  398. * @param mixed $value The option value.
  399. * @param mixed $deprecated Not used.
  400. * @return bool True if the value was updated, false otherwise.
  401. */
  402. function update_blog_option( $id, $option, $value, $deprecated = null ) {
  403. $id = (int) $id;
  404. if ( null !== $deprecated ) {
  405. _deprecated_argument( __FUNCTION__, '3.1.0' );
  406. }
  407. if ( get_current_blog_id() == $id ) {
  408. return update_option( $option, $value );
  409. }
  410. switch_to_blog( $id );
  411. $return = update_option( $option, $value );
  412. restore_current_blog();
  413. return $return;
  414. }
  415. /**
  416. * Switch the current blog.
  417. *
  418. * This function is useful if you need to pull posts, or other information,
  419. * from other blogs. You can switch back afterwards using restore_current_blog().
  420. *
  421. * Things that aren't switched:
  422. * - plugins. See #14941
  423. *
  424. * @see restore_current_blog()
  425. * @since MU (3.0.0)
  426. *
  427. * @global wpdb $wpdb WordPress database abstraction object.
  428. * @global int $blog_id
  429. * @global array $_wp_switched_stack
  430. * @global bool $switched
  431. * @global string $table_prefix
  432. * @global WP_Object_Cache $wp_object_cache
  433. *
  434. * @param int $new_blog_id The ID of the blog to switch to. Default: current blog.
  435. * @param bool $deprecated Not used.
  436. * @return true Always returns true.
  437. */
  438. function switch_to_blog( $new_blog_id, $deprecated = null ) {
  439. global $wpdb;
  440. $prev_blog_id = get_current_blog_id();
  441. if ( empty( $new_blog_id ) ) {
  442. $new_blog_id = $prev_blog_id;
  443. }
  444. $GLOBALS['_wp_switched_stack'][] = $prev_blog_id;
  445. /*
  446. * If we're switching to the same blog id that we're on,
  447. * set the right vars, do the associated actions, but skip
  448. * the extra unnecessary work
  449. */
  450. if ( $new_blog_id == $prev_blog_id ) {
  451. /**
  452. * Fires when the blog is switched.
  453. *
  454. * @since MU (3.0.0)
  455. * @since 5.4.0 The `$context` parameter was added.
  456. *
  457. * @param int $new_blog_id New blog ID.
  458. * @param int $prev_blog_id Previous blog ID.
  459. * @param string $context Additional context. Accepts 'switch' when called from switch_to_blog()
  460. * or 'restore' when called from restore_current_blog().
  461. */
  462. do_action( 'switch_blog', $new_blog_id, $prev_blog_id, 'switch' );
  463. $GLOBALS['switched'] = true;
  464. return true;
  465. }
  466. $wpdb->set_blog_id( $new_blog_id );
  467. $GLOBALS['table_prefix'] = $wpdb->get_blog_prefix();
  468. $GLOBALS['blog_id'] = $new_blog_id;
  469. if ( function_exists( 'wp_cache_switch_to_blog' ) ) {
  470. wp_cache_switch_to_blog( $new_blog_id );
  471. } else {
  472. global $wp_object_cache;
  473. if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) {
  474. $global_groups = $wp_object_cache->global_groups;
  475. } else {
  476. $global_groups = false;
  477. }
  478. wp_cache_init();
  479. if ( function_exists( 'wp_cache_add_global_groups' ) ) {
  480. if ( is_array( $global_groups ) ) {
  481. wp_cache_add_global_groups( $global_groups );
  482. } else {
  483. wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details', 'blog_meta' ) );
  484. }
  485. wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) );
  486. }
  487. }
  488. /** This filter is documented in wp-includes/ms-blogs.php */
  489. do_action( 'switch_blog', $new_blog_id, $prev_blog_id, 'switch' );
  490. $GLOBALS['switched'] = true;
  491. return true;
  492. }
  493. /**
  494. * Restore the current blog, after calling switch_to_blog().
  495. *
  496. * @see switch_to_blog()
  497. * @since MU (3.0.0)
  498. *
  499. * @global wpdb $wpdb WordPress database abstraction object.
  500. * @global array $_wp_switched_stack
  501. * @global int $blog_id
  502. * @global bool $switched
  503. * @global string $table_prefix
  504. * @global WP_Object_Cache $wp_object_cache
  505. *
  506. * @return bool True on success, false if we're already on the current blog.
  507. */
  508. function restore_current_blog() {
  509. global $wpdb;
  510. if ( empty( $GLOBALS['_wp_switched_stack'] ) ) {
  511. return false;
  512. }
  513. $new_blog_id = array_pop( $GLOBALS['_wp_switched_stack'] );
  514. $prev_blog_id = get_current_blog_id();
  515. if ( $new_blog_id == $prev_blog_id ) {
  516. /** This filter is documented in wp-includes/ms-blogs.php */
  517. do_action( 'switch_blog', $new_blog_id, $prev_blog_id, 'restore' );
  518. // If we still have items in the switched stack, consider ourselves still 'switched'.
  519. $GLOBALS['switched'] = ! empty( $GLOBALS['_wp_switched_stack'] );
  520. return true;
  521. }
  522. $wpdb->set_blog_id( $new_blog_id );
  523. $GLOBALS['blog_id'] = $new_blog_id;
  524. $GLOBALS['table_prefix'] = $wpdb->get_blog_prefix();
  525. if ( function_exists( 'wp_cache_switch_to_blog' ) ) {
  526. wp_cache_switch_to_blog( $new_blog_id );
  527. } else {
  528. global $wp_object_cache;
  529. if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) ) {
  530. $global_groups = $wp_object_cache->global_groups;
  531. } else {
  532. $global_groups = false;
  533. }
  534. wp_cache_init();
  535. if ( function_exists( 'wp_cache_add_global_groups' ) ) {
  536. if ( is_array( $global_groups ) ) {
  537. wp_cache_add_global_groups( $global_groups );
  538. } else {
  539. wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details', 'blog_meta' ) );
  540. }
  541. wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) );
  542. }
  543. }
  544. /** This filter is documented in wp-includes/ms-blogs.php */
  545. do_action( 'switch_blog', $new_blog_id, $prev_blog_id, 'restore' );
  546. // If we still have items in the switched stack, consider ourselves still 'switched'.
  547. $GLOBALS['switched'] = ! empty( $GLOBALS['_wp_switched_stack'] );
  548. return true;
  549. }
  550. /**
  551. * Switches the initialized roles and current user capabilities to another site.
  552. *
  553. * @since 4.9.0
  554. *
  555. * @param int $new_site_id New site ID.
  556. * @param int $old_site_id Old site ID.
  557. */
  558. function wp_switch_roles_and_user( $new_site_id, $old_site_id ) {
  559. if ( $new_site_id == $old_site_id ) {
  560. return;
  561. }
  562. if ( ! did_action( 'init' ) ) {
  563. return;
  564. }
  565. wp_roles()->for_site( $new_site_id );
  566. wp_get_current_user()->for_site( $new_site_id );
  567. }
  568. /**
  569. * Determines if switch_to_blog() is in effect
  570. *
  571. * @since 3.5.0
  572. *
  573. * @global array $_wp_switched_stack
  574. *
  575. * @return bool True if switched, false otherwise.
  576. */
  577. function ms_is_switched() {
  578. return ! empty( $GLOBALS['_wp_switched_stack'] );
  579. }
  580. /**
  581. * Check if a particular blog is archived.
  582. *
  583. * @since MU (3.0.0)
  584. *
  585. * @param int $id Blog ID.
  586. * @return string Whether the blog is archived or not.
  587. */
  588. function is_archived( $id ) {
  589. return get_blog_status( $id, 'archived' );
  590. }
  591. /**
  592. * Update the 'archived' status of a particular blog.
  593. *
  594. * @since MU (3.0.0)
  595. *
  596. * @param int $id Blog ID.
  597. * @param string $archived The new status.
  598. * @return string $archived
  599. */
  600. function update_archived( $id, $archived ) {
  601. update_blog_status( $id, 'archived', $archived );
  602. return $archived;
  603. }
  604. /**
  605. * Update a blog details field.
  606. *
  607. * @since MU (3.0.0)
  608. * @since 5.1.0 Use wp_update_site() internally.
  609. *
  610. * @global wpdb $wpdb WordPress database abstraction object.
  611. *
  612. * @param int $blog_id Blog ID.
  613. * @param string $pref Field name.
  614. * @param string $value Field value.
  615. * @param null $deprecated Not used.
  616. * @return string|false $value
  617. */
  618. function update_blog_status( $blog_id, $pref, $value, $deprecated = null ) {
  619. global $wpdb;
  620. if ( null !== $deprecated ) {
  621. _deprecated_argument( __FUNCTION__, '3.1.0' );
  622. }
  623. $allowed_field_names = array( 'site_id', 'domain', 'path', 'registered', 'last_updated', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' );
  624. if ( ! in_array( $pref, $allowed_field_names, true ) ) {
  625. return $value;
  626. }
  627. $result = wp_update_site(
  628. $blog_id,
  629. array(
  630. $pref => $value,
  631. )
  632. );
  633. if ( is_wp_error( $result ) ) {
  634. return false;
  635. }
  636. return $value;
  637. }
  638. /**
  639. * Get a blog details field.
  640. *
  641. * @since MU (3.0.0)
  642. *
  643. * @global wpdb $wpdb WordPress database abstraction object.
  644. *
  645. * @param int $id Blog ID.
  646. * @param string $pref Field name.
  647. * @return bool|string|null $value
  648. */
  649. function get_blog_status( $id, $pref ) {
  650. global $wpdb;
  651. $details = get_site( $id );
  652. if ( $details ) {
  653. return $details->$pref;
  654. }
  655. return $wpdb->get_var( $wpdb->prepare( "SELECT %s FROM {$wpdb->blogs} WHERE blog_id = %d", $pref, $id ) );
  656. }
  657. /**
  658. * Get a list of most recently updated blogs.
  659. *
  660. * @since MU (3.0.0)
  661. *
  662. * @global wpdb $wpdb WordPress database abstraction object.
  663. *
  664. * @param mixed $deprecated Not used.
  665. * @param int $start Optional. Number of blogs to offset the query. Used to build LIMIT clause.
  666. * Can be used for pagination. Default 0.
  667. * @param int $quantity Optional. The maximum number of blogs to retrieve. Default 40.
  668. * @return array The list of blogs.
  669. */
  670. function get_last_updated( $deprecated = '', $start = 0, $quantity = 40 ) {
  671. global $wpdb;
  672. if ( ! empty( $deprecated ) ) {
  673. _deprecated_argument( __FUNCTION__, 'MU' ); // Never used.
  674. }
  675. return $wpdb->get_results( $wpdb->prepare( "SELECT blog_id, domain, path FROM $wpdb->blogs WHERE site_id = %d AND public = '1' AND archived = '0' AND mature = '0' AND spam = '0' AND deleted = '0' AND last_updated != '0000-00-00 00:00:00' ORDER BY last_updated DESC limit %d, %d", get_current_network_id(), $start, $quantity ), ARRAY_A );
  676. }
  677. /**
  678. * Handler for updating the site's last updated date when a post is published or
  679. * an already published post is changed.
  680. *
  681. * @since 3.3.0
  682. *
  683. * @param string $new_status The new post status.
  684. * @param string $old_status The old post status.
  685. * @param WP_Post $post Post object.
  686. */
  687. function _update_blog_date_on_post_publish( $new_status, $old_status, $post ) {
  688. $post_type_obj = get_post_type_object( $post->post_type );
  689. if ( ! $post_type_obj || ! $post_type_obj->public ) {
  690. return;
  691. }
  692. if ( 'publish' !== $new_status && 'publish' !== $old_status ) {
  693. return;
  694. }
  695. // Post was freshly published, published post was saved, or published post was unpublished.
  696. wpmu_update_blogs_date();
  697. }
  698. /**
  699. * Handler for updating the current site's last updated date when a published
  700. * post is deleted.
  701. *
  702. * @since 3.4.0
  703. *
  704. * @param int $post_id Post ID
  705. */
  706. function _update_blog_date_on_post_delete( $post_id ) {
  707. $post = get_post( $post_id );
  708. $post_type_obj = get_post_type_object( $post->post_type );
  709. if ( ! $post_type_obj || ! $post_type_obj->public ) {
  710. return;
  711. }
  712. if ( 'publish' !== $post->post_status ) {
  713. return;
  714. }
  715. wpmu_update_blogs_date();
  716. }
  717. /**
  718. * Handler for updating the current site's posts count when a post is deleted.
  719. *
  720. * @since 4.0.0
  721. *
  722. * @param int $post_id Post ID.
  723. */
  724. function _update_posts_count_on_delete( $post_id ) {
  725. $post = get_post( $post_id );
  726. if ( ! $post || 'publish' !== $post->post_status || 'post' !== $post->post_type ) {
  727. return;
  728. }
  729. update_posts_count();
  730. }
  731. /**
  732. * Handler for updating the current site's posts count when a post status changes.
  733. *
  734. * @since 4.0.0
  735. * @since 4.9.0 Added the `$post` parameter.
  736. *
  737. * @param string $new_status The status the post is changing to.
  738. * @param string $old_status The status the post is changing from.
  739. * @param WP_Post $post Post object
  740. */
  741. function _update_posts_count_on_transition_post_status( $new_status, $old_status, $post = null ) {
  742. if ( $new_status === $old_status ) {
  743. return;
  744. }
  745. if ( 'post' !== get_post_type( $post ) ) {
  746. return;
  747. }
  748. if ( 'publish' !== $new_status && 'publish' !== $old_status ) {
  749. return;
  750. }
  751. update_posts_count();
  752. }
  753. /**
  754. * Count number of sites grouped by site status.
  755. *
  756. * @since 5.3.0
  757. *
  758. * @param int $network_id Optional. The network to get counts for. Default is the current network ID.
  759. * @return int[] {
  760. * Numbers of sites grouped by site status.
  761. *
  762. * @type int $all The total number of sites.
  763. * @type int $public The number of public sites.
  764. * @type int $archived The number of archived sites.
  765. * @type int $mature The number of mature sites.
  766. * @type int $spam The number of spam sites.
  767. * @type int $deleted The number of deleted sites.
  768. * }
  769. */
  770. function wp_count_sites( $network_id = null ) {
  771. if ( empty( $network_id ) ) {
  772. $network_id = get_current_network_id();
  773. }
  774. $counts = array();
  775. $args = array(
  776. 'network_id' => $network_id,
  777. 'number' => 1,
  778. 'fields' => 'ids',
  779. 'no_found_rows' => false,
  780. );
  781. $q = new WP_Site_Query( $args );
  782. $counts['all'] = $q->found_sites;
  783. $_args = $args;
  784. $statuses = array( 'public', 'archived', 'mature', 'spam', 'deleted' );
  785. foreach ( $statuses as $status ) {
  786. $_args = $args;
  787. $_args[ $status ] = 1;
  788. $q = new WP_Site_Query( $_args );
  789. $counts[ $status ] = $q->found_sites;
  790. }
  791. return $counts;
  792. }