@saltcorn/mobile-app 1.1.1-beta.0 → 1.1.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/share_extension_files/AppDelegate.swift +81 -0
- package/share_extension_files/Info.plist +33 -0
- package/share_extension_files/ShareViewController.swift +193 -0
- package/src/helpers/common.js +33 -1
- package/src/helpers/navigation.js +10 -9
- package/src/init.js +7 -0
- package/www/js/iframe_view_utils.js +53 -46
package/package.json
CHANGED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
import Capacitor
|
|
3
|
+
import SendIntent
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@UIApplicationMain
|
|
7
|
+
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
8
|
+
|
|
9
|
+
var window: UIWindow?
|
|
10
|
+
let store = ShareStore.store
|
|
11
|
+
|
|
12
|
+
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
|
13
|
+
// Override point for customization after application launch.
|
|
14
|
+
return true
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
func applicationWillResignActive(_ application: UIApplication) {
|
|
18
|
+
// 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.
|
|
19
|
+
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
func applicationDidEnterBackground(_ application: UIApplication) {
|
|
23
|
+
// 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.
|
|
24
|
+
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
func applicationWillEnterForeground(_ application: UIApplication) {
|
|
28
|
+
// 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.
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
func applicationDidBecomeActive(_ application: UIApplication) {
|
|
32
|
+
// 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.
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func applicationWillTerminate(_ application: UIApplication) {
|
|
36
|
+
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
|
|
40
|
+
var success = true
|
|
41
|
+
if CAPBridge.handleOpenUrl(url, options) {
|
|
42
|
+
success = ApplicationDelegateProxy.shared.application(app, open: url, options: options)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
guard let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true),
|
|
46
|
+
let params = components.queryItems else {
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
let titles = params.filter { $0.name == "title" }
|
|
50
|
+
let descriptions = params.filter { $0.name == "description" }
|
|
51
|
+
let types = params.filter { $0.name == "type" }
|
|
52
|
+
let urls = params.filter { $0.name == "url" }
|
|
53
|
+
|
|
54
|
+
store.shareItems.removeAll()
|
|
55
|
+
|
|
56
|
+
if(titles.count > 0){
|
|
57
|
+
for index in 0...titles.count-1 {
|
|
58
|
+
var shareItem: JSObject = JSObject()
|
|
59
|
+
shareItem["title"] = titles[index].value!
|
|
60
|
+
shareItem["description"] = descriptions[index].value!
|
|
61
|
+
shareItem["type"] = types[index].value!
|
|
62
|
+
shareItem["url"] = urls[index].value!
|
|
63
|
+
store.shareItems.append(shareItem)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
store.processed = false
|
|
68
|
+
let nc = NotificationCenter.default
|
|
69
|
+
nc.post(name: Notification.Name("triggerSendIntent"), object: nil )
|
|
70
|
+
|
|
71
|
+
return success
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
|
75
|
+
// Called when the app was launched with an activity, including Universal Links.
|
|
76
|
+
// Feel free to add additional processing here, but if you want the App API to support
|
|
77
|
+
// tracking app url opens, make sure to keep this call
|
|
78
|
+
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
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>NSExtension</key>
|
|
6
|
+
<dict>
|
|
7
|
+
<key>NSExtensionAttributes</key>
|
|
8
|
+
<dict>
|
|
9
|
+
<key>NSExtensionActivationRule</key>
|
|
10
|
+
<dict>
|
|
11
|
+
<key>NSExtensionActivationSupportsFileWithMaxCount</key>
|
|
12
|
+
<integer>5</integer>
|
|
13
|
+
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
|
14
|
+
<integer>5</integer>
|
|
15
|
+
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
|
|
16
|
+
<integer>5</integer>
|
|
17
|
+
<key>NSExtensionActivationSupportsText</key>
|
|
18
|
+
<true/>
|
|
19
|
+
<key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
|
|
20
|
+
<integer>1</integer>
|
|
21
|
+
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
|
22
|
+
<integer>1</integer>
|
|
23
|
+
<key>NSExtensionActivationUsesStrictMatching</key>
|
|
24
|
+
<false/>
|
|
25
|
+
</dict>
|
|
26
|
+
</dict>
|
|
27
|
+
<key>NSExtensionMainStoryboard</key>
|
|
28
|
+
<string>MainInterface</string>
|
|
29
|
+
<key>NSExtensionPointIdentifier</key>
|
|
30
|
+
<string>com.apple.share-services</string>
|
|
31
|
+
</dict>
|
|
32
|
+
</dict>
|
|
33
|
+
</plist>
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ShareViewController.swift
|
|
3
|
+
// mindlib
|
|
4
|
+
//
|
|
5
|
+
// Created by Carsten Klaffke on 05.07.20.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import MobileCoreServices
|
|
9
|
+
import Social
|
|
10
|
+
import UIKit
|
|
11
|
+
|
|
12
|
+
class ShareItem {
|
|
13
|
+
|
|
14
|
+
public var title: String?
|
|
15
|
+
public var type: String?
|
|
16
|
+
public var url: String?
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class ShareViewController: UIViewController {
|
|
20
|
+
|
|
21
|
+
private var shareItems: [ShareItem] = []
|
|
22
|
+
|
|
23
|
+
override public func viewDidAppear(_ animated: Bool) {
|
|
24
|
+
super.viewDidAppear(animated)
|
|
25
|
+
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private func sendData() {
|
|
29
|
+
let queryItems = shareItems.map {
|
|
30
|
+
[
|
|
31
|
+
URLQueryItem(
|
|
32
|
+
name: "title",
|
|
33
|
+
value: $0.title?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""),
|
|
34
|
+
URLQueryItem(name: "description", value: ""),
|
|
35
|
+
URLQueryItem(
|
|
36
|
+
name: "type",
|
|
37
|
+
value: $0.type?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""),
|
|
38
|
+
URLQueryItem(
|
|
39
|
+
name: "url",
|
|
40
|
+
value: $0.url?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""),
|
|
41
|
+
]
|
|
42
|
+
}.flatMap({ $0 })
|
|
43
|
+
var urlComps = URLComponents(string: "scappscheme://")!
|
|
44
|
+
urlComps.queryItems = queryItems
|
|
45
|
+
openURL(urlComps.url!)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fileprivate func createSharedFileUrl(_ url: URL?) -> String {
|
|
49
|
+
let fileManager = FileManager.default
|
|
50
|
+
|
|
51
|
+
let copyFileUrl =
|
|
52
|
+
fileManager.containerURL(forSecurityApplicationGroupIdentifier: "YOUR_APP_GROUP_ID")!
|
|
53
|
+
.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! + url!
|
|
54
|
+
.lastPathComponent.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
|
|
55
|
+
try? Data(contentsOf: url!).write(to: URL(string: copyFileUrl)!)
|
|
56
|
+
|
|
57
|
+
return copyFileUrl
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func saveScreenshot(_ image: UIImage, _ index: Int) -> String {
|
|
61
|
+
let fileManager = FileManager.default
|
|
62
|
+
|
|
63
|
+
let copyFileUrl =
|
|
64
|
+
fileManager.containerURL(forSecurityApplicationGroupIdentifier: "YOUR_APP_GROUP_ID")!
|
|
65
|
+
.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
|
|
66
|
+
+ "/screenshot_\(index).png"
|
|
67
|
+
do {
|
|
68
|
+
try image.pngData()?.write(to: URL(string: copyFileUrl)!)
|
|
69
|
+
return copyFileUrl
|
|
70
|
+
} catch {
|
|
71
|
+
print(error.localizedDescription)
|
|
72
|
+
return ""
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fileprivate func handleTypeUrl(_ attachment: NSItemProvider)
|
|
77
|
+
async throws -> ShareItem
|
|
78
|
+
{
|
|
79
|
+
let results = try await attachment.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil)
|
|
80
|
+
let url = results as! URL?
|
|
81
|
+
let shareItem: ShareItem = ShareItem()
|
|
82
|
+
|
|
83
|
+
if url!.isFileURL {
|
|
84
|
+
shareItem.title = url!.lastPathComponent
|
|
85
|
+
shareItem.type = "application/" + url!.pathExtension.lowercased()
|
|
86
|
+
shareItem.url = createSharedFileUrl(url)
|
|
87
|
+
} else {
|
|
88
|
+
shareItem.title = url!.absoluteString
|
|
89
|
+
shareItem.url = url!.absoluteString
|
|
90
|
+
shareItem.type = "text/plain"
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return shareItem
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fileprivate func handleTypeText(_ attachment: NSItemProvider)
|
|
97
|
+
async throws -> ShareItem
|
|
98
|
+
{
|
|
99
|
+
let results = try await attachment.loadItem(forTypeIdentifier: kUTTypeText as String, options: nil)
|
|
100
|
+
let shareItem: ShareItem = ShareItem()
|
|
101
|
+
let text = results as! String
|
|
102
|
+
shareItem.title = text
|
|
103
|
+
shareItem.type = "text/plain"
|
|
104
|
+
return shareItem
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
fileprivate func handleTypeMovie(_ attachment: NSItemProvider)
|
|
108
|
+
async throws -> ShareItem
|
|
109
|
+
{
|
|
110
|
+
let results = try await attachment.loadItem(forTypeIdentifier: kUTTypeMovie as String, options: nil)
|
|
111
|
+
let shareItem: ShareItem = ShareItem()
|
|
112
|
+
|
|
113
|
+
let url = results as! URL?
|
|
114
|
+
shareItem.title = url!.lastPathComponent
|
|
115
|
+
shareItem.type = "video/" + url!.pathExtension.lowercased()
|
|
116
|
+
shareItem.url = createSharedFileUrl(url)
|
|
117
|
+
return shareItem
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fileprivate func handleTypeImage(_ attachment: NSItemProvider, _ index: Int)
|
|
121
|
+
async throws -> ShareItem
|
|
122
|
+
{
|
|
123
|
+
let data = try await attachment.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil)
|
|
124
|
+
|
|
125
|
+
let shareItem: ShareItem = ShareItem()
|
|
126
|
+
switch data {
|
|
127
|
+
case let image as UIImage:
|
|
128
|
+
shareItem.title = "screenshot_\(index)"
|
|
129
|
+
shareItem.type = "image/png"
|
|
130
|
+
shareItem.url = self.saveScreenshot(image, index)
|
|
131
|
+
case let url as URL:
|
|
132
|
+
shareItem.title = url.lastPathComponent
|
|
133
|
+
shareItem.type = "image/" + url.pathExtension.lowercased()
|
|
134
|
+
shareItem.url = self.createSharedFileUrl(url)
|
|
135
|
+
default:
|
|
136
|
+
print("Unexpected image data:", type(of: data))
|
|
137
|
+
}
|
|
138
|
+
return shareItem
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
override public func viewDidLoad() {
|
|
142
|
+
super.viewDidLoad()
|
|
143
|
+
|
|
144
|
+
shareItems.removeAll()
|
|
145
|
+
|
|
146
|
+
let extensionItem = extensionContext?.inputItems[0] as! NSExtensionItem
|
|
147
|
+
Task {
|
|
148
|
+
try await withThrowingTaskGroup(
|
|
149
|
+
of: ShareItem.self,
|
|
150
|
+
body: { taskGroup in
|
|
151
|
+
|
|
152
|
+
for (index, attachment) in extensionItem.attachments!.enumerated() {
|
|
153
|
+
if attachment.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
|
|
154
|
+
taskGroup.addTask {
|
|
155
|
+
return try await self.handleTypeUrl(attachment)
|
|
156
|
+
}
|
|
157
|
+
} else if attachment.hasItemConformingToTypeIdentifier(kUTTypeText as String) {
|
|
158
|
+
taskGroup.addTask {
|
|
159
|
+
return try await self.handleTypeText(attachment)
|
|
160
|
+
}
|
|
161
|
+
} else if attachment.hasItemConformingToTypeIdentifier(kUTTypeMovie as String) {
|
|
162
|
+
taskGroup.addTask {
|
|
163
|
+
return try await self.handleTypeMovie(attachment)
|
|
164
|
+
}
|
|
165
|
+
} else if attachment.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
|
|
166
|
+
taskGroup.addTask {
|
|
167
|
+
return try await self.handleTypeImage(attachment, index)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
for try await item in taskGroup {
|
|
173
|
+
self.shareItems.append(item)
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
self.sendData()
|
|
178
|
+
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
@objc func openURL(_ url: URL) {
|
|
183
|
+
var responder: UIResponder? = self
|
|
184
|
+
while responder != nil {
|
|
185
|
+
if let application = responder as? UIApplication {
|
|
186
|
+
application.open(url, options: [:], completionHandler: nil)
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
responder = responder?.next
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
}
|
package/src/helpers/common.js
CHANGED
|
@@ -4,6 +4,7 @@ import { apiCall } from "./api";
|
|
|
4
4
|
import { Camera, CameraResultType } from "@capacitor/camera";
|
|
5
5
|
import { Geolocation } from "@capacitor/geolocation";
|
|
6
6
|
import { ScreenOrientation } from "@capacitor/screen-orientation";
|
|
7
|
+
import { SendIntent } from "send-intent";
|
|
7
8
|
|
|
8
9
|
const orientationChangeListeners = new Set();
|
|
9
10
|
|
|
@@ -80,13 +81,13 @@ export function clearTopAlerts() {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
export function errorAlert(error) {
|
|
84
|
+
console.error(error);
|
|
83
85
|
showAlerts([
|
|
84
86
|
{
|
|
85
87
|
type: "error",
|
|
86
88
|
msg: error.message ? error.message : "An error occured.",
|
|
87
89
|
},
|
|
88
90
|
]);
|
|
89
|
-
console.error(error);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
// TODO combine with loadEncodedFile
|
|
@@ -187,3 +188,34 @@ export function registerScreenOrientationListener(name, listener) {
|
|
|
187
188
|
export async function getScreenOrientation() {
|
|
188
189
|
return await ScreenOrientation.orientation();
|
|
189
190
|
}
|
|
191
|
+
|
|
192
|
+
export async function sendIntentCallback() {
|
|
193
|
+
console.log("sendIntentCallback");
|
|
194
|
+
try {
|
|
195
|
+
const received = await SendIntent.checkSendIntentReceived();
|
|
196
|
+
console.log("received: ", received);
|
|
197
|
+
if (received) {
|
|
198
|
+
const response = await apiCall({
|
|
199
|
+
method: "POST",
|
|
200
|
+
path: "/notifications/share-handler",
|
|
201
|
+
body: received,
|
|
202
|
+
});
|
|
203
|
+
console.log("Share data sent to server.");
|
|
204
|
+
console.log(response);
|
|
205
|
+
if (response.data.error) {
|
|
206
|
+
errorAlert(response.data.error);
|
|
207
|
+
} else {
|
|
208
|
+
showAlerts([
|
|
209
|
+
{
|
|
210
|
+
type: "success",
|
|
211
|
+
msg:
|
|
212
|
+
"Shared: " +
|
|
213
|
+
(received.title || received.text || received.url || ""),
|
|
214
|
+
},
|
|
215
|
+
]);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.log("Error in sendIntentCallback: ", error);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
@@ -228,7 +228,7 @@ export function isHtmlFile() {
|
|
|
228
228
|
return iframe.getAttribute("is-html-file") === "true";
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
-
async function reload() {
|
|
231
|
+
export async function reload() {
|
|
232
232
|
const currentRoute = currentLocation();
|
|
233
233
|
if (!currentRoute) await gotoEntryView();
|
|
234
234
|
await handleRoute(currentRoute, currentQuery(true));
|
|
@@ -336,12 +336,13 @@ export async function replaceIframeInnerContent(content) {
|
|
|
336
336
|
}
|
|
337
337
|
|
|
338
338
|
export function splitPathQuery(url) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
339
|
+
if (url === "/") return { path: "/", query: undefined, hash: undefined };
|
|
340
|
+
const urlObj =
|
|
341
|
+
url.startsWith("http://") || url.startsWith("https://")
|
|
342
|
+
? new URL(url)
|
|
343
|
+
: new URL(`http://${url}`);
|
|
344
|
+
const path = url.split("?")[0];
|
|
345
|
+
const query = urlObj.search?.substring(1);
|
|
346
|
+
const hash = urlObj.hash?.substring(1);
|
|
347
|
+
return { path, query, hash };
|
|
347
348
|
}
|
package/src/init.js
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
gotoEntryView,
|
|
23
23
|
addRoute,
|
|
24
24
|
} from "./helpers/navigation.js";
|
|
25
|
+
import { sendIntentCallback } from "./helpers/common.js";
|
|
25
26
|
|
|
26
27
|
import i18next from "i18next";
|
|
27
28
|
import i18nextSprintfPostProcessor from "i18next-sprintf-postprocessor";
|
|
@@ -319,6 +320,7 @@ export async function init({
|
|
|
319
320
|
|
|
320
321
|
state.mobileConfig.networkState = await Network.getStatus();
|
|
321
322
|
Network.addListener("networkStatusChange", networkChangeCallback);
|
|
323
|
+
|
|
322
324
|
const networkDisabled = state.mobileConfig.networkState === "none";
|
|
323
325
|
const jwt = state.mobileConfig.jwt;
|
|
324
326
|
const alerts = [];
|
|
@@ -365,6 +367,11 @@ export async function init({
|
|
|
365
367
|
});
|
|
366
368
|
}
|
|
367
369
|
}
|
|
370
|
+
if (state.mobileConfig.allowOfflineMode) {
|
|
371
|
+
await sendIntentCallback();
|
|
372
|
+
window.addEventListener("sendIntentReceived", sendIntentCallback);
|
|
373
|
+
}
|
|
374
|
+
|
|
368
375
|
let page = null;
|
|
369
376
|
if (!lastLocation) {
|
|
370
377
|
addRoute({ route: entryPoint, query: undefined });
|
|
@@ -311,10 +311,10 @@ function invalidate_pagings(currentQuery) {
|
|
|
311
311
|
async function set_state_fields(kvs, disablePjax, e) {
|
|
312
312
|
try {
|
|
313
313
|
showLoadSpinner();
|
|
314
|
-
|
|
314
|
+
const current = get_current_state_url(e);
|
|
315
315
|
let queryParams = [];
|
|
316
316
|
const { path, query } =
|
|
317
|
-
parent.saltcorn.mobileApp.navigation.splitPathQuery(
|
|
317
|
+
parent.saltcorn.mobileApp.navigation.splitPathQuery(current);
|
|
318
318
|
let currentQuery = query || {};
|
|
319
319
|
if (Object.keys(kvs).some((k) => !is_paging_param(k))) {
|
|
320
320
|
currentQuery = invalidate_pagings(currentQuery);
|
|
@@ -333,6 +333,8 @@ async function set_state_fields(kvs, disablePjax, e) {
|
|
|
333
333
|
if (disablePjax)
|
|
334
334
|
await parent.saltcorn.mobileApp.navigation.handleRoute(path, queryStr);
|
|
335
335
|
else await pjax_to(path, queryStr, e);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
336
338
|
} finally {
|
|
337
339
|
removeLoadSpinner();
|
|
338
340
|
}
|
|
@@ -376,32 +378,29 @@ async function pjax_to(href, query, e) {
|
|
|
376
378
|
}
|
|
377
379
|
}
|
|
378
380
|
|
|
379
|
-
async function set_state_field(key, value) {
|
|
381
|
+
async function set_state_field(key, value, e) {
|
|
380
382
|
try {
|
|
381
383
|
showLoadSpinner();
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
parent.saltcorn.mobileApp.navigation.currentLocation(),
|
|
389
|
-
query
|
|
390
|
-
);
|
|
384
|
+
const newhref = get_current_state_url(e);
|
|
385
|
+
const { path, query } =
|
|
386
|
+
parent.saltcorn.mobileApp.navigation.splitPathQuery(newhref);
|
|
387
|
+
await pjax_to(path, updateQueryStringParameter(query, key, value), e);
|
|
388
|
+
} catch (error) {
|
|
389
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
391
390
|
} finally {
|
|
392
391
|
removeLoadSpinner();
|
|
393
392
|
}
|
|
394
393
|
}
|
|
395
394
|
|
|
396
|
-
async function unset_state_field(key) {
|
|
395
|
+
async function unset_state_field(key, e) {
|
|
397
396
|
try {
|
|
398
397
|
showLoadSpinner();
|
|
399
|
-
const
|
|
400
|
-
const query =
|
|
401
|
-
parent.saltcorn.mobileApp.navigation.
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
398
|
+
const newhref = get_current_state_url(e);
|
|
399
|
+
const { path, query } =
|
|
400
|
+
parent.saltcorn.mobileApp.navigation.splitPathQuery(newhref);
|
|
401
|
+
await pjax_to(path, removeQueryStringParameter(query, key), e);
|
|
402
|
+
} catch (error) {
|
|
403
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
405
404
|
} finally {
|
|
406
405
|
removeLoadSpinner();
|
|
407
406
|
}
|
|
@@ -623,50 +622,58 @@ function openInAppBrowser(url, domId) {
|
|
|
623
622
|
}
|
|
624
623
|
}
|
|
625
624
|
|
|
626
|
-
async function select_id(id) {
|
|
625
|
+
async function select_id(id, e) {
|
|
627
626
|
try {
|
|
628
627
|
showLoadSpinner();
|
|
629
|
-
const
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
parent.saltcorn.mobileApp.navigation.currentLocation(),
|
|
636
|
-
newQuery
|
|
637
|
-
);
|
|
628
|
+
const newhref = get_current_state_url(e);
|
|
629
|
+
const { path, query } =
|
|
630
|
+
parent.saltcorn.mobileApp.navigation.splitPathQuery(newhref);
|
|
631
|
+
await pjax_to(path, updateQueryStringParameter(query, "id", id), e);
|
|
632
|
+
} catch (error) {
|
|
633
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
638
634
|
} finally {
|
|
639
635
|
removeLoadSpinner();
|
|
640
636
|
}
|
|
641
637
|
}
|
|
642
638
|
|
|
643
|
-
async function check_state_field(that) {
|
|
639
|
+
async function check_state_field(that, e) {
|
|
644
640
|
try {
|
|
645
641
|
showLoadSpinner();
|
|
642
|
+
const newhref = get_current_state_url(e);
|
|
643
|
+
const { path, query } =
|
|
644
|
+
parent.saltcorn.mobileApp.navigation.splitPathQuery(newhref);
|
|
645
|
+
const checked = that.checked;
|
|
646
646
|
const name = that.name;
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
await parent.saltcorn.mobileApp.navigation.handleRoute(
|
|
655
|
-
parent.saltcorn.mobileApp.navigation.currentLocation(),
|
|
656
|
-
newQuery
|
|
657
|
-
);
|
|
647
|
+
const value = encodeURIComponent(that.value);
|
|
648
|
+
const newQuery = checked
|
|
649
|
+
? updateQueryStringParameter(query, name, value)
|
|
650
|
+
: removeQueryStringParameter(query, name);
|
|
651
|
+
await pjax_to(path, newQuery, e);
|
|
652
|
+
} catch (error) {
|
|
653
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
658
654
|
} finally {
|
|
659
655
|
removeLoadSpinner();
|
|
660
656
|
}
|
|
661
657
|
}
|
|
662
658
|
|
|
663
|
-
async function clear_state() {
|
|
659
|
+
async function clear_state(omit_fields_str, e) {
|
|
664
660
|
try {
|
|
665
661
|
showLoadSpinner();
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
662
|
+
const newhref = get_current_state_url(e);
|
|
663
|
+
const { path, query, hash } =
|
|
664
|
+
parent.saltcorn.mobileApp.navigation.splitPathQuery(newhref);
|
|
665
|
+
let newQuery = "";
|
|
666
|
+
if (omit_fields_str) {
|
|
667
|
+
const omit_fields = omit_fields_str.split(",");
|
|
668
|
+
const params = new URLSearchParams(query);
|
|
669
|
+
for (const f of omit_fields) {
|
|
670
|
+
if (params.get(f))
|
|
671
|
+
updateQueryStringParameter(newQuery, f, params.get(f));
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
await pjax_to(path, newQuery, e);
|
|
675
|
+
} catch (error) {
|
|
676
|
+
parent.saltcorn.mobileApp.common.errorAlert(error);
|
|
670
677
|
} finally {
|
|
671
678
|
removeLoadSpinner();
|
|
672
679
|
}
|