WebForms Core (WFC) is a server-driven web development technology developed by Elanat. This package provides a Swift implementation of the WebForms class for WebForms Core, enabling Swift server applications to generate WebForms Core commands that are executed in the browser by WebFormsJS. It can be used with Swift web frameworks such as Vapor.
Add WebForms Core to your Swift project using Swift Package Manager.
In your Package.swift file, add WebForms Core to the dependencies section:
dependencies: [
.package(
url: "https://github.com/webforms-core/swift.git",
from: "2.2.0"
)
]Then add WebFormsCore to the target dependencies:
.product(
name: "WebFormsCore",
package: "swift"
)Import WebForms Core in your Swift file:
import Vapor
import WebFormsCoreYou can then use the WebForms class in your Vapor application.
WebForms Core uses WebFormsJS on the client side to execute the commands generated by the server.
The latest WebFormsJS Executor is available here:
- WebFormsJS on Elanat: https://elanat.net/webforms-js
- WebFormsJS on GitHub: https://github.com/webforms-core/WebFormsJS
The npm package is also available:
https://www.npmjs.com/package/webformsjs
Add WebFormsJS to your HTML page:
<script type="module" src="/script/web-forms.js"></script>The following example demonstrates how to use WebForms Core with the Vapor web framework. It shows both the initial page request and a subsequent form submission handled by the server.
import Vapor
import WebFormsCore
struct FormData: Content {
var txt_Name: String
var txt_BackgroundColor: String
var txt_FontSize: Int
}
func routes(_ app: Application) throws {
app.post { req -> Response in
guard let data = try? req.content.decode(FormData.self) else {
throw Abort(.badRequest)
}
let name = data.txt_Name
let backgroundColor = data.txt_BackgroundColor
let fontSize = data.txt_FontSize
let form = WebForms()
form.setFontSize(InputPlace.tag("form"), fontSize)
form.setBackgroundColor(InputPlace.tag("form"), backgroundColor)
form.setDisabled(InputPlace.name("btn_SetBodyValue"), true)
form.addTag(InputPlace.tag("form"), "h3")
form.setText(InputPlace.tag("h3"), "Welcome \(name)!")
var headers = HTTPHeaders()
headers.contentType = HTTPMediaType(
type: "text",
subType: "plain",
parameters: ["charset": "utf-8"]
)
return Response(
status: .ok,
headers: headers,
body: .init(string: form.response())
)
}
app.get { req in
var headers = HTTPHeaders()
headers.contentType = HTTPMediaType(
type: "text",
subType: "html",
parameters: ["charset": "utf-8"]
)
return Response(
status: .ok,
headers: headers,
body: .init(string: renderForm())
)
}
}
func renderForm() -> String {
return """
<!DOCTYPE html>
<html>
<head>
<title>Using WebForms Core</title>
<script type="module" src="/script/web-forms.js"></script>
</head>
<body>
<form method="post" action="/">
<label for="txt_Name">Your Name</label>
<input name="txt_Name" id="txt_Name" type="text" />
<br>
<label for="txt_FontSize">Set Font Size</label>
<input name="txt_FontSize" id="txt_FontSize" type="number" value="16" min="10" max="36" />
<br>
<label for="txt_BackgroundColor">Set Background Color</label>
<input name="txt_BackgroundColor" id="txt_BackgroundColor" type="text" />
<br>
<input name="btn_SetBodyValue" type="submit" value="Click to send data" />
</form>
</body>
</html>
"""
}
public func configure(_ app: Application) throws {
try routes(app)
}
@main
struct WebFormsApp {
static func main() async throws {
var env = try Environment.detect()
try LoggingSystem.bootstrap(from: &env)
let app = try await Application.make(env)
do {
try configure(app)
try await app.execute()
} catch {
app.logger.report(error: error)
try? await app.asyncShutdown()
throw error
}
try await app.asyncShutdown()
}
}A minimal Vapor project using WebForms Core can declare the dependencies as follows:
dependencies: [
.package(
url: "https://github.com/vapor/vapor.git",
from: "4.0.0"
),
.package(
url: "https://github.com/webforms-core/swift.git",
from: "2.2.0"
)
]Add WebFormsCore to the target dependencies:
.product(
name: "WebFormsCore",
package: "swift"
)When the application receives the initial GET request, the app.get route returns the complete HTML document generated by renderForm().
The HTML page includes the WebFormsJS Executor:
<script type="module" src="/script/web-forms.js"></script>When the user submits the form, the browser sends the form data to the POST route. Vapor decodes the submitted values into the FormData structure:
let name = data.txt_Name
let backgroundColor = data.txt_BackgroundColor
let fontSize = data.txt_FontSizeThe server then creates a WebForms instance and generates WebForms Core commands based on the submitted values:
let form = WebForms()These commands modify the existing HTML document in the browser. For example, the font size and background color of the form are changed, the submit button is disabled, and a new h3 element containing a personalized message is added.
The generated commands are returned by calling:
form.response()The response is then received by WebFormsJS, which executes the WebForms Core commands on the current HTML DOM.
Therefore, the initial request returns the complete HTML document, while subsequent interactions can return WebForms Core commands instead of sending the complete HTML document again.
When WebForms Core commands need to be sent together with the initial HTML document, you can use exportToHtmlComment() instead of response().
exportToHtmlComment() embeds the generated WebForms Core commands in an HTML comment. WebFormsJS detects these commands when the HTML document is loaded and executes them in the browser.
For example, a Vapor application can generate WebForms Core commands during the initial page load:
import Vapor
import WebFormsCore
func routes(_ app: Application) throws {
app.get { req in
let form = WebForms()
form.setBackgroundColor(
InputPlace.tag("body"),
"lightblue"
)
var headers = HTTPHeaders()
headers.contentType = HTTPMediaType(
type: "text",
subType: "html",
parameters: ["charset": "utf-8"]
)
let html = """
<!DOCTYPE html>
<html>
<head>
<title>WebForms Core</title>
<script type="module" src="/script/web-forms.js"></script>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
"""
return Response(
status: .ok,
headers: headers,
body: .init(
string: html + form.exportToHtmlComment()
)
)
}
}In this example, the generated commands are embedded directly in the HTML response as an HTML comment. When WebFormsJS loads, it detects the commands and executes them on the DOM. The background color of the page becomes light blue during the initial page load.
Use response() when returning WebForms Core commands as a response to a request, such as a form submission. Use exportToHtmlComment() when the commands need to be included directly in the HTML document, such as during the initial page load.
WFC is distributed under the MIT License.
Copyright © Elanat.
