11 Commits

Author SHA1 Message Date
cb58262507 Moved to Giraffe View Engine 2022-02-22 15:22:32 +10:00
dredgy
b5a2514495 Merge pull request #5 from dredgy/npm_scripts
Npm scripts
2022-02-14 19:04:54 +10:00
a1d3ad19c3 Updated gitignore 2022-02-14 16:33:03 +10:00
300fb23905 Updated gitignore 2022-02-14 16:32:11 +10:00
6892b3d34c Restructured files, made build script 2022-02-14 16:31:08 +10:00
c73184808c Added solution 2022-02-14 16:06:08 +10:00
dredgy
c7f3d7d2fb Merge pull request #4 from dredgy/project-structure
Project structure
2022-02-13 19:35:26 +10:00
e3794fc222 Unversioned file was tracking 2022-02-13 19:35:02 +10:00
39dbba45f7 Separated models, controllers and routers 2022-02-13 19:33:50 +10:00
dredgy
6cbd670260 Merge pull request #3 from dredgy/order_screen
Join With Line function
2022-02-13 13:10:24 +10:00
dredgy
abfb2331ba Merge pull request #2 from dredgy/order_screen
Order screen
2022-01-23 18:18:06 +10:00
91 changed files with 678 additions and 1541 deletions

6
.gitignore vendored
View File

@@ -6,5 +6,7 @@
/tables/*
/Properties/
/.idea/
/wwwroot/scripts/js/
/wwwroot/styles/css/*
/wwwroot/scripts/*.js
/wwwroot/scripts/*.js.map
/wwwroot/styles/*
/Folder.DotSettings.user

15
Ajax/Controller.fs Normal file
View File

@@ -0,0 +1,15 @@
module DredgePos.Ajax.Controller
open DredgeFramework
open language
open Giraffe
let getLanguageVars = ajaxSuccess languageVars
let getKeyboardLayout (language: string) =
let layout = $"""wwwroot/languages/{language}/keyboardLayout.json"""
|> GetFileContents
map [
"status", "success"
"data", layout
] |> json

14
Ajax/Router.fs Normal file
View File

@@ -0,0 +1,14 @@
module DredgePos.Ajax.Router
open Saturn
open Giraffe
let pipeline = pipeline {
use_warbler
}
let router = router {
getf "/getKeyboardLayout/%s" Controller.getKeyboardLayout
get "/languageVars" (json Controller.getLanguageVars)
}

View File

@@ -0,0 +1,16 @@
module DredgePos.Authenticate.Controller
open DredgeFramework
open Microsoft.AspNetCore.Http
open DredgePos.Global.Controller
let loadAuthenticatePage =
let scripts = [|"dredgepos.authenticate.js"|] |> addDefaultScripts
let styles = [|"dredgepos.authenticate.css"|] |> addDefaultStyles
let metaTags = [|"viewport", "user-scalable = no, initial-scale=0.8,maximum-scale=0.8 ,shrink-to-fit=yes"|] |> addDefaultMetaTags
View.index scripts styles metaTags
let loginWithLoginCode (context: HttpContext) (login_code: int) =
if Model.clerkLogin login_code context then ajaxSuccess "success"
else ajaxFail "fail"

View File

@@ -1,13 +1,27 @@
module Session
module DredgePos.Authenticate.Model
open System
open DredgeFramework
open Dapper.FSharp
open Clerk
open DredgePos
open Thoth.Json.Net
open Types
let getClerkByLoginCode (loginCode: int) =
let clerk =
select {
table "clerks"
where (eq "clerk_login_code" loginCode)
take 1
}
|> db.Select<clerk>
|> EnumerableToArray
if (clerk |> length) > 0 then
Some (first clerk)
else
None
let deleteSession sessionId context =
delete {
table "sessions"
@@ -65,12 +79,10 @@ let sessionExists (sessionId: string) context =
let checkAuthentication clerk =
let existingClerk = getClerkByLoginCode clerk.clerk_login_code
if existingClerk.IsSome
&& existingClerk.Value.id = clerk.id
&& existingClerk.Value.clerk_name = clerk.clerk_name
&& existingClerk.Value.clerk_login_code = clerk.clerk_login_code
then true
else false
existingClerk.IsSome
&& existingClerk.Value.id = clerk.id
&& existingClerk.Value.clerk_name = clerk.clerk_name
&& existingClerk.Value.clerk_login_code = clerk.clerk_login_code
let getLoginCookie context = Browser.getCookie "dredgepos_clerk_logged_in" context

18
Authenticate/Router.fs Normal file
View File

@@ -0,0 +1,18 @@
module DredgePos.Authenticate.Router
open Saturn
open Giraffe
let homepage = (warbler (fun _ -> htmlView Controller.loadAuthenticatePage ))
let handlePostRoute<'a> handlerFunction post next ctx = json (handlerFunction ctx post) next ctx
let pipeline = pipeline{
use_warbler
}
let router = router {
pipe_through pipeline
get "/" homepage
get "" homepage
post "/authenticateClerk" (bindJson<int> (handlePostRoute Controller.loginWithLoginCode) )
}

10
Authenticate/View.fs Normal file
View File

@@ -0,0 +1,10 @@
module DredgePos.Authenticate.View
open DredgePos.Global.View
open Giraffe.ViewEngine
let content = div [_id "authenticator"] []
let index scripts styles metaTags = HtmlPage "Floorplan" (GetScripts scripts) (GetStyles styles) (GetMetaTags metaTags) [|content|]

View File

@@ -1,37 +0,0 @@
module Clerk
open Dapper.FSharp
open DredgeFramework
open DredgePos
open Thoth.Json.Net
open Types
let mutable loginCookie = ""
let clerk_decoder : Decoder<clerk> =
Decode.object
(fun get ->
{
id = get.Required.Field "clerk_id" Decode.int
clerk_name = get.Required.Field "clerk_name" Decode.string
clerk_login_code = get.Required.Field "clerk_login_code" Decode.int
clerk_usergroup = get.Required.Field "clerk_usergroup" Decode.int
})
type user = {clerk_name:string}
let getClerkByLoginCode (loginCode: int) =
let clerk =
select {
table "clerks"
where (eq "clerk_login_code" loginCode)
take 1
}
|> db.Select<clerk>
|> EnumerableToArray
if (clerk |> length) > 0 then
Some (first clerk)
else
None

View File

@@ -2,7 +2,6 @@
open System.Collections.Generic
open System.Globalization
open FSharp.Data.Sql
open System
open System.Drawing
open System.IO
@@ -35,8 +34,9 @@ let EnumerableToArray (enumerable: IEnumerable<'T>) = enumerable.ToArray()
let getFileExtension (file: string) = Path.GetExtension file
let GetFileContents (file: string) = File.ReadAllText file
let GetFileContents = File.ReadAllText
let GetFileName (file: string) = Path.GetFileName file
let FileExists = File.Exists
let length (variable: 'T[]) = variable.Length
let first (array: 'a[]) = array[0]

View File

@@ -10,8 +10,8 @@ open DredgeFramework
let currentTheme = "restaurant"
let getHTMLForFile file =
let stylePath = $"/styles/css/{file}"
let scriptPath = $"/scripts/js/{file}"
let stylePath = $"/styles/{file}"
let scriptPath = $"/scripts/{file}"
let fileExtension = file |> getFileExtension
let scriptFileExists = File.Exists ("wwwroot"+stylePath) || File.Exists("wwwroot"+scriptPath)
match scriptFileExists with
@@ -26,7 +26,7 @@ let getHTMLForFile file =
let ParseScriptsAndStylesheets files html =
let defaultScriptsAndStyles = ["dark.theme.css"; "../external/jquery.js" ; "dredgepos.core.js"; "keyboards.js";]
let defaultScriptsAndStyles = ["dark.theme.css"; "./external/jquery.js" ; "dredgepos.core.js"; "keyboards.js";]
let scriptsAndStylesheets = defaultScriptsAndStyles @ files
let scriptAndStylesheetHTML =
@@ -89,7 +89,7 @@ let ParseLanguageVariablesWithReplacements (string: string) =
))
let getTemplateFilePath templateName =
"wwwroot/themes/"+ currentTheme + "/" + templateName + ".tpl.htm"
"views/"+ currentTheme + "/" + templateName + ".tpl.htm"
let templateExists templateName =
templateName

View File

@@ -1,48 +0,0 @@
module Decorations
open System
open System.IO
open System.Text.RegularExpressions
open DredgeFramework
open Dapper.FSharp
open DredgePos
open Types
let decorationsInRoom (roomId: int) = Entity.GetAllByColumn "decoration_room" roomId
let getImageName (image: string, path: string) =
let imageName =
image
|> StringReplace "-" " "
|> StringReplace "_" " "
|> ToTitleCase
imageName, path
let isImageFile (fileName: string) = Regex.IsMatch(fileName |> ToLowerCase, @"^.+\.(jpg|jpeg|png|gif)$")
let getImageHTML (imageName: string, imageUrl: string) =
let vars = map [
"image_name", imageName
"image_url", imageUrl
]
Theme.loadTemplateWithVars "decoratorItem" vars
let GetFileNameWithoutExtension (path: string) =
let name = Path.GetFileNameWithoutExtension path
name, path |> Path.GetFileName
let getImageRowHtml (imagesInRow: string[]) =
let vars = map ["decorations", String.Join("", imagesInRow)]
Theme.loadTemplateWithVars "decoratorRow" vars
let generateDecorator () =
"wwwroot/images/decorations"
|> Directory.GetFiles
|> Array.filter isImageFile
|> Array.map GetFileNameWithoutExtension
|> Array.map getImageName
|> Array.map getImageHTML
|> Array.chunkBySize 4
|> Array.map getImageRowHtml
|> JoinArray ""

View File

@@ -5,23 +5,37 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Types.fs" />
<Compile Include="DredgeFramework.module.fs" />
<Compile Include="Browser.module.fs" />
<Compile Include="Database.module.fs" />
<Compile Include="GenericEntities.module.fs" />
<Compile Include="Language.module.fs" />
<Compile Include="Theme.module.fs" />
<Compile Include="Reservations.module.fs" />
<Compile Include="Floorplan.module.fs" />
<Compile Include="Core\Types.fs" />
<Compile Include="Core\DredgeFramework.module.fs" />
<Compile Include="Core\Browser.module.fs" />
<Compile Include="Core\Database.module.fs" />
<Compile Include="Core\GenericEntities.module.fs" />
<Compile Include="Core\Language.module.fs" />
<Compile Include="Core\Theme.module.fs" />
<Compile Include="Printer.module.fs" />
<Compile Include="Orders.module.fs" />
<Compile Include="OrderScreen.module.fs" />
<Compile Include="Decorations.module.fs" />
<Compile Include="Clerk.module.fs" />
<Compile Include="Session.module.fs" />
<Compile Include="PageController.fs" />
<Compile Include="AjaxController.fs" />
<Compile Include="Global\View.fs" />
<Compile Include="Global\Controller.fs" />
<Compile Include="Global\Router.fs" />
<Compile Include="Entities\Floorplan_Decorations\Model.fs" />
<Compile Include="Entities\Floorplan_Decorations\View.fs" />
<Compile Include="Entities\Floorplan_Decorations\Controller.fs" />
<Compile Include="Entities\Floorplan_Decorations\Router.fs" />
<Compile Include="Authenticate\Model.fs" />
<Compile Include="Authenticate\View.fs" />
<Compile Include="Authenticate\Controller.fs" />
<Compile Include="Authenticate\Router.fs" />
<Compile Include="Ajax\Controller.fs" />
<Compile Include="Ajax\Router.fs" />
<Compile Include="Floorplan\Model.fs" />
<Compile Include="Floorplan\View.fs" />
<Compile Include="Floorplan\Controller.fs" />
<Compile Include="Floorplan\Router.fs" />
<Compile Include="OrderScreen\Model.fs" />
<Compile Include="OrderScreen\Controller.fs" />
<Compile Include="OrderScreen\Router.fs" />
<Compile Include="Reservations\Model.fs" />
<Compile Include="Reservations\Controller.fs" />
<Compile Include="Reservations\Router.fs" />
<Compile Include="Program.fs" />
</ItemGroup>
@@ -38,27 +52,75 @@
<Content Remove="node_modules\**" />
<Content Remove="wwwroot\scripts\ts\test.ts" />
<Content Remove="languages\**" />
<Content Include="sass\dark.theme.sass">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="sass\dredgepos.authenticate.sass">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="sass\dredgepos.core.sass">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="sass\dredgepos.floorplan.sass">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="sass\dredgepos.keyboards.sass">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="sass\dredgepos.orderScreen.sass">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="typescript\dredgepos.authenticate.ts">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="typescript\dredgepos.core.ts">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="typescript\dredgepos.floorplan.ts">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="typescript\dredgepos.orderScreen.ts">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="typescript\dredgepos.tables.ts">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="typescript\keyboards.ts">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="typescript\types.ts">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="typescript\typings\currency.d.ts">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="typescript\typings\konva.d.ts">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Folder Include="wwwroot\styles" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="2.0.78" />
<PackageReference Include="Dapper.Contrib" Version="2.0.78" />
<PackageReference Include="Dapper.FSharp" Version="2.4.1" />
<PackageReference Include="FSharp.Data" Version="4.0.1" />
<PackageReference Include="Giraffe" Version="6.0.0-alpha-2" />
<PackageReference Include="Npgsql" Version="6.0.0" />
<PackageReference Include="Pluralize.NET.Core" Version="1.0.0" />
<PackageReference Include="Saturn" Version="0.15.0-preview03" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.0" />
<PackageReference Include="FSharp.Data.SqlClient" Version="2.1.0-beta1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0-preview.2.21154.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0-preview.2.21154.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MySql.Data" Version="8.0.23" />
<PackageReference Include="MySql.Data.EntityFrameworkCore" Version="8.0.22" />
<PackageReference Include="SQLProvider" Version="1.2.1" />
<PackageReference Include="Saturn" Version="0.15.0" />
<PackageReference Include="System.Drawing.Common" Version="6.0.0-preview.5.21301.5" />
<PackageReference Include="Thoth.Json.Net" Version="5.0.0" />
<PackageReference Update="FSharp.Core" Version="6.0.2-beta.21631.1" />
@@ -70,12 +132,10 @@
<Content Include="xslt\orderHtmltoXML.xslt" />
<Content Include="xslt\htmlToEscPos.xslt" />
<Content Include=".gitignore" />
<Folder Include="wwwroot\fonts" />
<Folder Include="wwwroot\styles\css" />
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="wwwroot\themes\default\index.tpl.html" />
<_ContentIncludedByDefault Remove="wwwroot\themes\default\index.tpl.html" />
<_ContentIncludedByDefault Remove="wwwroot\themes\default\scripts\global.js" />
<_ContentIncludedByDefault Remove="wwwroot\themes\default\scripts\index.js" />
<_ContentIncludedByDefault Remove="wwwroot\themes\default\styles\global.css" />

16
DredgePos.sln Normal file
View File

@@ -0,0 +1,16 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "DredgePos", "DredgePos.fsproj", "{3C52169C-8E40-472B-B87B-82F43F96BFB0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3C52169C-8E40-472B-B87B-82F43F96BFB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C52169C-8E40-472B-B87B-82F43F96BFB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C52169C-8E40-472B-B87B-82F43F96BFB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C52169C-8E40-472B-B87B-82F43F96BFB0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,13 @@
module DredgePos.Entities.Floorplan_Decorations.Controller
open System.IO
let generateDecorator () =
"wwwroot/images/decorations"
|> Directory.GetFiles
|> Array.filter Model.isImageFile
|> Array.map Model.GetFileNameWithoutExtension
|> Array.map Model.getImageName
|> Array.map View.decoratorItem
|> Array.chunkBySize 4
|> Array.map View.decoratorRow

View File

@@ -0,0 +1,24 @@
module DredgePos.Entities.Floorplan_Decorations.Model
open System
open System.IO
open System.Text.RegularExpressions
open DredgeFramework
let decorationsInRoom (roomId: int) = Entity.GetAllByColumn "decoration_room" roomId
let getImageName (image: string, path: string) =
let imageName =
image
|> StringReplace "-" " "
|> StringReplace "_" " "
|> ToTitleCase
imageName, path
let isImageFile (fileName: string) = Regex.IsMatch(fileName |> ToLowerCase, @"^.+\.(jpg|jpeg|png|gif)$")
let GetFileNameWithoutExtension (path: string) =
let name = Path.GetFileNameWithoutExtension path
name, path |> Path.GetFileName

View File

@@ -0,0 +1,2 @@
module DredgePos.Entities.Floorplan_Decorations.Router

View File

@@ -0,0 +1,24 @@
module DredgePos.Entities.Floorplan_Decorations.View
open Giraffe.ViewEngine
open DredgePos.Global.View
let decoratorItem (imageName, imageUrl) =
let image = attr "data-image"
div [_class "decoratorItem"; image imageUrl] [
a [_style $"background-image:url('/images/decorations/{imageUrl}')"] []
a [] [str imageName]
]
let decoratorRow decoratorItems = div [_class "decoratorRow"] [yield! decoratorItems]
let decorator (decorationRows: XmlNode[]) =
div [_id "decorator"] [
div [_id "decoratorHeader"] [
h2 [] [lang "choose_decoration"]
a [_class "posButton hideDecorator"] [str "×"]
]
div [_id "decoratorContent"] [
yield! decorationRows
]
]

View File

@@ -1,22 +1,24 @@
module AjaxController
module DredgePos.Floorplan.Controller
open DredgeFramework
open DredgePos
open DredgePos.Global.Controller
open DredgePos.Entities
open DredgePos.Types
open Floorplan
open Microsoft.AspNetCore.Http
open Reservations
open language
open Giraffe
open Types
open Microsoft.AspNetCore.Http
open Model
open System.IO
let loginWithLoginCode (context: HttpContext) (login_code: int) =
if Session.clerkLogin login_code context then ajaxSuccess "success"
else ajaxFail "fail"
let makeRoomButton (room: floorplan_room) =
let vars = map [
"roomId", room.id |> string
"roomName", room.room_name
]
let getLanguageVars = ajaxSuccess languageVars
Theme.loadTemplateWithVars "roomButton" vars
let getActiveTables venue = Floorplan.getActiveTables venue |> ajaxSuccess |> json
let getActiveTables venue = Model.getActiveTables venue |> ajaxSuccess |> json
let mergeTables (tables: floorplan_table[]) =
let status =
@@ -24,14 +26,14 @@ let mergeTables (tables: floorplan_table[]) =
let outputTables = map [
"parent", tables[0];
"child", tables[1];
"merged", getTable tables[0].table_number;
"merged", Model.getTable tables[0].table_number;
]
ajaxSuccess outputTables
else ajaxFail "Could Not Merge Tables"
status |> json
let unmergeTable tableNumber =
let unmerged = Floorplan.unmergeTable tableNumber
let unmerged = unmergeTable tableNumber
let unmergedTables =
match unmerged with
| Some (parent, child) ->
@@ -47,32 +49,13 @@ let getFloorplanData (id: int) =
{|
tables = tableList
decorations = Entity.GetAllInVenue<floorplan_decoration>
activeTableNumbers = Floorplan.getActiveTables (getCurrentVenue())
activeTableNumbers = Model.getActiveTables (getCurrentVenue())
rooms = Entity.GetAllInVenue<floorplan_room>
reservations = reservationList
|}
|> ajaxSuccess
|> json
let getOrderScreenData (tableNumber: int) =
{|
order_screen_pages = Entity.GetAllInVenue<order_screen_page_group>
sales_categories = Entity.GetAllInVenue<sales_category>
print_groups = Entity.GetAllInVenue<print_group>
custom_item = Entity.GetAllByColumn<item> "item_code" "OPEN000" |> first
table = getTable tableNumber
|}
|> ajaxSuccess
|> json
let getKeyboardLayout (language: string) =
let layout = $"""wwwroot/languages/{language}/keyboardLayout.json"""
|> GetFileContents
map [
"status", "success"
"data", layout
] |> json
let transformTable (table: floorplan_table) =
Entity.Update table
|> ajaxSuccess
@@ -90,7 +73,7 @@ let deleteTable (table: floorplan_table) =
table |> ajaxSuccess |> json
let transferTable (origin, destination) =
Floorplan.transferTable origin destination
transferTable origin destination
let data = map ["origin", getTable origin ; "destination", getTable destination]
ajaxSuccess data |> json
@@ -125,32 +108,12 @@ let DeleteDecoration (decorationToDelete: floorplan_decoration) =
|> ajaxSuccess
|> json
let newEmptyReservation (reservation: reservation) =
let newReservation = {reservation with
created_at = CurrentTime()
time = CurrentTime()
}
let loadFloorplanView (ctx: HttpContext) =
Authenticate.Model.RequireClerkAuthentication ctx
let roomMenu = Entity.GetAllInVenue<floorplan_room> |> Array.map View.roomButton
let currentClerk = Authenticate.Model.getCurrentClerk ctx
let styles = [|"dredgepos.floorplan.css"|] |> addDefaultStyles
let scripts = [|"./external/konva.min.js" ; "dredgepos.floorplan.js"|] |> addDefaultScripts
let metaTags = [|"viewport", "user-scalable = no, initial-scale=0.8,maximum-scale=0.8 ,shrink-to-fit=yes"|] |> addDefaultMetaTags
if reservation.floorplan_table_id > 0 then
let table = {(getTableById reservation.floorplan_table_id) with
status = 2
default_covers = reservation.covers}
updateTablePosition table |> ignore
let createdReservation = Floorplan.createEmptyReservation newReservation
ajaxSuccess createdReservation |> json
let updateReservation (reservation: reservation) = updateReservation reservation |> ajaxSuccess |> json
let unreserveTable (table: floorplan_table) =
let newTable = {table with status = 0}
updateTablePosition newTable |> ignore
DeleteReservation newTable.id
newTable |> ajaxSuccess |> json
let loadGrid (gridId: int) =
let grid = Entity.GetById<grid> gridId
let gridHtml = OrderScreen.loadGrid gridId
if gridHtml = "Error" then ajaxFail gridHtml
else ajaxSuccess {|grid=grid;gridHtml=gridHtml|}
|> json
View.index styles scripts metaTags currentClerk (Floorplan_Decorations.Controller.generateDecorator ()) roomMenu

View File

@@ -1,19 +1,12 @@
module Floorplan
module DredgePos.Floorplan.Model
open DredgePos
open DredgePos.Types
open Org.BouncyCastle.Asn1.X509
open Reservations
open System
open System.IO
open System.Xml.Linq
open DredgeFramework
open Dapper
open Dapper.FSharp
open Thoth.Json.Net
open Types
let activeTablePath = "tables/active/"
let getTableFile (tableNumber: int) =
@@ -281,13 +274,7 @@ let unmergeTable tableNumber = //Separates a merged table into itself and the la
Some (getTable currentTable.table_number, unmergedChild)
| Error _ -> None
let makeRoomButton (room: floorplan_room) =
let vars = map [
"roomId", room.id |> string
"roomName", room.room_name
]
Theme.loadTemplateWithVars "roomButton" vars
let getReservationList (tableList: floorplan_table[]) =
tableList |> Array.collect Entity.GetAllRelated<reservation, floorplan_table>
@@ -305,4 +292,4 @@ let newReservation name time covers =
Entity.Create reservation
let tableList () = Entity.GetAllInVenue<floorplan_table>
let tableList () = Entity.GetAllInVenue<floorplan_table>

25
Floorplan/Router.fs Normal file
View File

@@ -0,0 +1,25 @@
module DredgePos.Floorplan.Router
open DredgePos
open DredgePos.Global.Router
open DredgePos.Types
open Saturn
open Giraffe
let floorplan = (htmlViewWithContext Controller.loadFloorplanView)
let router = router {
pipe_through Ajax.Router.pipeline
get "" floorplan
get "/" floorplan
post "/mergeTables" (bindJson<floorplan_table[]> Controller.mergeTables)
post "/transformTable" (bindJson<floorplan_table> Controller.transformTable)
post "/createTable" (bindJson<floorplan_table> Controller.createTable)
post "/addDecoration" (bindJson<floorplan_decoration> Controller.AddDecoration)
post "/updateDecoration" (bindJson<floorplan_decoration> Controller.UpdateDecoration)
post "/deleteDecoration" (bindJson<floorplan_decoration> Controller.DeleteDecoration)
post "/deleteTable" (bindJson<floorplan_table> Controller.deleteTable)
getf "/getFloorplanData/%i" Controller.getFloorplanData
getf "/transferTable/%i/%i" Controller.transferTable
getf "/unmergeTable/%i" Controller.unmergeTable
}

88
Floorplan/View.fs Normal file
View File

@@ -0,0 +1,88 @@
module DredgePos.Floorplan.View
open DredgePos.Global
open DredgePos.Global.View
open DredgePos.Entities
open DredgePos.Types
open Giraffe.ViewEngine
open DredgeFramework
let VisibleInMode (value: string list) = value |> jsonEncode |> (attr "data-visible-in-mode")
let InvisibleInMode (value: string list) = value |> jsonEncode |> (attr "data-invisible-in-mode")
let ActiveInMode (value: string) = value |> (attr "data-active-in-mode")
let pageContainer (clerk: clerk) roomMenu =
let loggedInText = str (language.getAndReplace "logged_in_as" [clerk.clerk_name])
div [_id "pageContainer"] [
div [_id "floorplanLeftColumn"] [
div [_class "topCell"] [
a [_class "posHeader"] [loggedInText]
]
div [_class "middleCell"] []
div [_class "bottomCell"] []
]
div [_id "floorplanCenterColumn"] [
div [_class "topCell"] [
yield! roomMenu
]
div [_class "middleCell"] [
div [_id "floorplanCanvas"] []
div [_id "floorplanCanvas"] []
]
div [_class "bottomCell"] [
div [_class "editControls" ; VisibleInMode ["tableSelected"]] [
div [_class "posHeader currentTable"] [
b [_class "selectedTableNumber"] []
a [_class "reservationStatus"; VisibleInMode ["reservedTableSelected"]] []
small [_class "selectedTableCovers"] []
]
a [_class "posButton placeOrderButton"] [lang "order_table"]
a [_class "posButton reserveTableButton"; InvisibleInMode ["reservedTableSelected"; "activeTableSelected"]] [lang "reserve_table"]
a [_class "posButton unreserveTableButton"; VisibleInMode ["reservedTableSelected"]] [lang "unreserve_table"]
a [_class "posButton payTableButton"; VisibleInMode ["activeTableSelected"]] [lang "pay_table"]
a [_class "posButton viewTableButton"; VisibleInMode ["activeTableSelected"]] [lang "view_table"]
]
]
]
div [_id "floorplanRightColumn"] [
div [_class "topCell"] [
a [_class "posButton logOut"] [str "×"]
]
div [_class "middleCell"] [
a [_class "posButton editModeButton"] [lang "edit_floorplan"]
div [_class "floorplanControls useVisibility"; VisibleInMode ["edit"]] [
a [_class "posButton addTableButton"] [lang "add_table"]
a [_class "posButton addDecoration"] [lang "add_decoration"]
a [_class "posButton deleteDecoration useVisibility"; VisibleInMode ["decorationSelected"; "edit"] ] [lang "delete_decoration"]
a [_class "posButton deleteTableButton useVisibility"; VisibleInMode ["tableSelected"; "edit"]] [lang "delete_table"]
a [_class "posButton changeShapeButton useVisibility"; VisibleInMode ["tableSelected"; "edit"]] [lang "change_shape"]
]
div [_class "mergeControls useVisibility"; VisibleInMode ["tableSelected"]] [
a [_class "posButton mergeButton"; ActiveInMode "merge"] [lang "merge_table"]
a [_class "posButton unmergeButton"; VisibleInMode ["tableSelected"]] [lang "unmerge_table"]
a [_class "posButton transferTableButton" ; ActiveInMode "transfer" ; VisibleInMode ["activeTableSelected"]] [lang "transfer_table"]
]
]
div [_class "bottomCell"] []
]
]
let roomButton (room: floorplan_room) = a [_class "posButton roomButton"; Value (string room.id)] [str room.room_name ]
let index styles scripts tags clerk decoratorRows roomMenu =
[|
pageContainer clerk roomMenu
decoratorRows |> Floorplan_Decorations.View.decorator
|]
|> HtmlPage "Floorplan" (GetScripts scripts) (GetStyles styles) (GetMetaTags tags)

7
Global/Controller.fs Normal file
View File

@@ -0,0 +1,7 @@
module DredgePos.Global.Controller
open DredgeFramework
let addDefaultScripts scripts = scripts |> Array.append [|"./external/jquery.js" ; "dredgepos.core.js"; "keyboards.js";|]
let addDefaultStyles styles = styles |> Array.append [|"dark.theme.css";|]
let addDefaultMetaTags (tags: (string*string)[]) = tags |> Array.append [|"apple-mobile-web-app-capable", "yes"|]

11
Global/Router.fs Normal file
View File

@@ -0,0 +1,11 @@
module DredgePos.Global.Router
open Saturn
open Giraffe
let htmlViewWithContext func =
(fun ctx ->
func (snd ctx)
|> htmlView
)
|> warbler

109
Global/View.fs Normal file
View File

@@ -0,0 +1,109 @@
module DredgePos.Global.View
open Giraffe.ViewEngine
open DredgeFramework
let Value = attr "data-value"
let innerText = str
let lang key = language.get key |> str
let scriptToHTML (scriptFile: string) =
let scriptPath = $"/scripts/{scriptFile}"
match FileExists ("wwwroot" + scriptPath) with
| true -> script [_src scriptPath] []
| false -> comment $"[Missing script: {scriptFile}]"
let GetScripts (scripts: string[]) = scripts |> Array.map scriptToHTML
let styleToHTML (stylesheet:string) =
let stylePath = $"/styles/{stylesheet}"
match FileExists ("wwwroot" + stylePath) with
| true -> link [_rel "stylesheet" ; _href stylePath]
| false -> comment $"[Missing style: {stylesheet}]"
let GetStyles (scripts: string[]) = scripts |> Array.map styleToHTML
let tagToHtml (tag, content) = meta [_name tag; _content content]
let GetMetaTags (tags: (string * string)[]) = tags |> Array.map tagToHtml
let VirtualKeyboardRow numberOfButtons =
let buttons = Array.init numberOfButtons (fun _ -> a [] [])
div [_class "virtualKeyboardRow"] [
yield! buttons
]
let VirtualKeyboard =
div [_id "virtualKeyboard"] [
div [_class "headingRow"] [
h3 [_id "virtualKeyboardHeading"] []
a [_class "posButton closeKeyboards"] [str "X"]
]
input [_type "text"; _name "virtualKeyboardInput"; _id "virtualKeyboardInput"]
div [_id "virtualKeyboardButtons"] [
VirtualKeyboardRow 13
VirtualKeyboardRow 14
VirtualKeyboardRow 13
VirtualKeyboardRow 11
VirtualKeyboardRow 1
]
span [_class "forceFocus"] []
]
let VirtualNumpadButton (text: string) =
a [_href "#"; Value (text.ToLower()); _class "posButton virtualNumpadButton"] [str text]
let VirtualNumpadRow (buttons:string[]) =
div [_class "virtualNumpadRow"] [
yield! Array.map VirtualNumpadButton buttons
]
let VirtualNumpad =
div [_id "virtualNumpad"] [
div [_class "headingRow"] [
h3 [_id "virtualNumpadHeading"] []
a [_class "posButton closeKeyboards"] [str "X"]
]
div [_id "virtualNumpadInput"] []
div [_id "virtualNumpadButtons"] [
VirtualNumpadRow [|"1"; "2"; "3"|]
VirtualNumpadRow [|"4"; "5"; "6"|]
VirtualNumpadRow [|"7"; "8"; "9"|]
VirtualNumpadRow [|"0"; "."; "Clear"|]
VirtualNumpadRow [|"Submit"|]
]
]
let alert =
div [_id "alert"] [
div [_id "alertHeading"] []
div [_id "alertMessage"] []
div [_id "alertButtons"] [
a [_class "posButton"; _id "alertOk"] [lang "alert_ok"]
a [_class "posButton"; _id "alertYes"] [lang "alert_yes"]
a [_class "posButton"; _id "alertNo"] [lang "alert_no"]
]
]
let keyboards = [|
VirtualKeyboard
VirtualNumpad
alert
|]
let HtmlPage pageTitle scripts styles tags content =
html [] [
head [] [
title [] [innerText pageTitle]
link [_rel "manifest" ; _href "/manifest.webmanifest"]
yield! styles
yield! scripts
yield! tags
]
body [] [
yield! content
yield! keyboards
]
]
let HTMLPageWithScripts pageTitle scripts content = HtmlPage pageTitle scripts [||] content
let HTMLPageWithStyles pageTitle styles content = HtmlPage pageTitle [||] styles content
let HTMLPageWithNoScriptsOrStyles pageTitle content = HtmlPage pageTitle [||] [||] content

View File

@@ -1,46 +1,35 @@
module PageController
module DredgePos.OrderScreen.Controller
open System
open DredgePos.Types
open FSharp.Data
open Microsoft.AspNetCore.Http
open Floorplan
open Giraffe
open DredgePos
open DredgeFramework
open DredgePos.Types
open Giraffe
open Microsoft.AspNetCore.Http
let loadHomePage(): HttpHandler =
let variables = map ["title", "Log In"]
let scripts = ["dredgepos.authenticate.js"]
let styles = ["dredgepos.authenticate.css"]
let getOrderScreenData (tableNumber: int) =
{|
order_screen_pages = Entity.GetAllInVenue<order_screen_page_group>
sales_categories = Entity.GetAllInVenue<sales_category>
print_groups = Entity.GetAllInVenue<print_group>
custom_item = Entity.GetAllByColumn<item> "item_code" "OPEN000" |> first
table = Floorplan.Model.getTable tableNumber
|}
|> ajaxSuccess
|> json
Theme.loadTemplateWithVarsScriptsAndStyles "authenticate" variables scripts styles
|> htmlString
let loadFloorplan (ctx: HttpContext) : HttpHandler =
Session.RequireClerkAuthentication ctx
let roomMenu =
Entity.GetAllInVenue<floorplan_room>
|> Array.map makeRoomButton
|> joinWithNewLine
let variables = map [
"title", "Floorplan"
"roomMenu", roomMenu
"decorator", Decorations.generateDecorator()
]
let styles = ["dredgepos.floorplan.css"]
let scripts = ["../external/konva.min.js" ; "dredgepos.floorplan.js"]
let currentClerk = recordToMap <| Session.getCurrentClerk ctx
let arrays = map ["clerk", currentClerk]
htmlString <| Theme.loadTemplateWithVarsArraysScriptsAndStyles "floorplan" variables arrays scripts styles
let loadGrid (gridId: int) =
let grid = Entity.GetById<grid> gridId
let gridHtml = Model.loadGrid gridId
if gridHtml = "Error" then ajaxFail gridHtml
else ajaxSuccess {|grid=grid;gridHtml=gridHtml|}
|> json
let loadOrderScreen (ctx: HttpContext) (tableNumber: int) : HttpHandler =
Session.RequireClerkAuthentication ctx
Authenticate.Model.RequireClerkAuthentication ctx
let covers = if tableNumber > 0 then (getTable tableNumber).default_covers else 0
let table = Floorplan.Model.getTable tableNumber
let covers = if tableNumber > 0 then table.default_covers else 0
let coverString = language.getAndReplace "covers" [covers]
let changeCoverNumberButton = if tableNumber > 0 then Theme.loadTemplateWithVars "orderScreen/change_cover_number_button" (map ["covers", coverString]) else ""
@@ -51,7 +40,7 @@ let loadOrderScreen (ctx: HttpContext) (tableNumber: int) : HttpHandler =
let containerAttributes =
if tableNumber > 0 then
map ["data-table", jsonEncode (getTable tableNumber)]
map ["data-table", jsonEncode table]
|> Theme.htmlAttributes
else ""
@@ -67,8 +56,8 @@ let loadOrderScreen (ctx: HttpContext) (tableNumber: int) : HttpHandler =
|> joinWithNewLine
let grids =
OrderScreen.getAllPageGrids ()
|> Array.map OrderScreen.getPagesHTML
Model.getAllPageGrids ()
|> Array.map Model.getPagesHTML
|> joinWithNewLine
let coverSelectorButtons =
@@ -87,26 +76,14 @@ let loadOrderScreen (ctx: HttpContext) (tableNumber: int) : HttpHandler =
"orderNumber", orderNumber
"changeCoverNumberButton", changeCoverNumberButton
"covers", coverString
"salesCategoryOverrideButtons", OrderScreen.generateSalesCategoryOverrideButtons ()
"salesCategoryOverrideButtons", Model.generateSalesCategoryOverrideButtons ()
"coverSelectorButtons", coverSelectorButtons
]
let styles = ["dredgepos.orderScreen.css"]
let scripts = ["dredgepos.tables.js";"../external/currency.min.js";"dredgepos.orderScreen.js"; ]
let currentClerk = recordToMap <| Session.getCurrentClerk ctx
let scripts = ["dredgepos.tables.js";"./external/currency.min.js";"dredgepos.orderScreen.js"; ]
let currentClerk = recordToMap <| Authenticate.Model.getCurrentClerk ctx
let arrays = map ["clerk", currentClerk]
Theme.loadTemplateWithVarsArraysScriptsAndStyles "orderScreen" variables arrays scripts styles
|> htmlString
let getOpenTables() =
let rows = openTables()
rows |> jsonEncode
let mergeTables parent child =
mergeTables parent child |> ignore
"done"
let unmergeTables table =
unmergeTable table |> ignore
"done"

View File

@@ -1,4 +1,5 @@
module OrderScreen
module DredgePos.OrderScreen.Model
open DredgeFramework
open DredgePos
open DredgePos.Types
@@ -133,5 +134,3 @@ let getPagesHTML (gridInfo: grid * order_screen_page_group) =
renderGrid grid
|> renderPageGroup pageGroup

15
OrderScreen/Router.fs Normal file
View File

@@ -0,0 +1,15 @@
module DredgePos.OrderScreen.Router
open DredgePos
open DredgePos.Types
open Saturn
open Giraffe
let router = router {
pipe_through Ajax.Router.pipeline
getf "/getOrderScreenData/%i" Controller.getOrderScreenData
getf "/getGridHtml/%i" Controller.loadGrid
post "/updateCovers" (bindJson<floorplan_table> (fun table -> Entity.Update table |> Array.head |> DredgeFramework.ajaxSuccess |> json))
get "/" (warbler (fun ctx -> Controller.loadOrderScreen (snd ctx) 0))
getf "/%i" (fun number -> (warbler (fun ctx -> Controller.loadOrderScreen (snd ctx) number)))
}

View File

@@ -1,3 +0,0 @@
module Orders
let getHighestOrderNumber () = 6

View File

@@ -1,71 +1,26 @@
namespace WebApplication
namespace DredgePos
open DredgePos
open DredgePos.Types
open Microsoft.AspNetCore.Server.Kestrel.Core
open Reservations
open Saturn
open Giraffe
open Types
module Program =
let handlePostRoute<'a> handlerFunction post next ctx =
json (handlerFunction ctx post) next ctx
let browser = pipeline {
use_warbler
}
let floorplanRouter = router {
pipe_through browser
post "/authenticateClerk" (bindJson<int> (handlePostRoute AjaxController.loginWithLoginCode) )
post "/transformTable" (bindJson<floorplan_table> AjaxController.transformTable)
post "/createTable" (bindJson<floorplan_table> AjaxController.createTable)
post "/addDecoration" (bindJson<floorplan_decoration> AjaxController.AddDecoration)
post "/updateDecoration" (bindJson<floorplan_decoration> AjaxController.UpdateDecoration)
post "/deleteDecoration" (bindJson<floorplan_decoration> AjaxController.DeleteDecoration)
post "/deleteTable" (bindJson<floorplan_table> AjaxController.deleteTable)
post "/mergeTables" (bindJson<floorplan_table[]> AjaxController.mergeTables)
post "/newEmptyReservation" (bindJson<reservation> AjaxController.newEmptyReservation)
post "/updateReservation" (bindJson<reservation> AjaxController.updateReservation)
post "/getReservation" (bindJson<int> (fun reservation -> json <| GetReservationById reservation) )
post "/unreserveTable" (bindJson<floorplan_table> AjaxController.unreserveTable )
getf "/getKeyboardLayout/%s" AjaxController.getKeyboardLayout
get "/languageVars" (json <| AjaxController.getLanguageVars)
get "/getOpenTables" (json <| Floorplan.getActiveTables (DredgeFramework.getCurrentVenue()))
getf "/getFloorplanData/%i" AjaxController.getFloorplanData
getf "/tableIsOpen/%i" (fun tableNumber -> json <| Floorplan.tableNumberIsOpen tableNumber)
getf "/transferTable/%i/%i" AjaxController.transferTable
getf "/unmergeTable/%i" AjaxController.unmergeTable
getf "/tableExists/%i" (fun tableNumber -> json <| Floorplan.tableExists tableNumber)
}
let orderScreenRouter = router {
pipe_through browser
getf "/getOrderScreenData/%i" AjaxController.getOrderScreenData
getf "/getGridHtml/%i" AjaxController.loadGrid
post "/updateCovers" (bindJson<floorplan_table> (fun table -> Entity.Update table |> Array.head |> DredgeFramework.ajaxSuccess |> json))
}
let pageRouter = router {
pipe_through browser
let router = router {
pipe_through Ajax.Router.pipeline
not_found_handler (setStatusCode 404 >=> text "404")
get "/" (redirectTo true "/login")
get "/login" (warbler (fun _ -> PageController.loadHomePage() ))
get "/floorplan" (warbler (fun ctx -> PageController.loadFloorplan (snd ctx)))
get "/order" (warbler (fun ctx -> PageController.loadOrderScreen (snd ctx) 0))
getf "/order/%i" (fun number -> (warbler (fun ctx -> PageController.loadOrderScreen (snd ctx) number)))
forward "/ajax" floorplanRouter
forward "/orderScreen" orderScreenRouter
forward "/ajax" Ajax.Router.router
forward "/floorplan" DredgePos.Floorplan.Router.router
forward "/order" DredgePos.OrderScreen.Router.router
forward "/login" DredgePos.Authenticate.Router.router
forward "/reservations" DredgePos.Reservations.Router.router
}
let app = application {
use_mime_types [(".woff", "application/font-woff")]
use_static "wwwroot"
use_router pageRouter
use_router router
url "http://0.0.0.0:5001"
}
run app

View File

@@ -0,0 +1,29 @@
module DredgePos.Reservations.Controller
open DredgeFramework
open DredgePos
open DredgePos.Types
open Giraffe
let newEmptyReservation (reservation: reservation) =
let newReservation = {reservation with
created_at = CurrentTime()
time = CurrentTime()
}
if reservation.floorplan_table_id > 0 then
let table = {(Entity.GetById<floorplan_table> reservation.floorplan_table_id) with
status = 2
default_covers = reservation.covers}
Floorplan.Model.updateTablePosition table |> ignore
let createdReservation = Floorplan.Model.createEmptyReservation newReservation
ajaxSuccess createdReservation |> json
let updateReservation (reservation: reservation) = Model.updateReservation reservation |> ajaxSuccess |> json
let unreserveTable (table: floorplan_table) =
let newTable = {table with status = 0}
Floorplan.Model.updateTablePosition newTable |> ignore
Model.DeleteReservation newTable.id
newTable |> ajaxSuccess |> json

View File

@@ -1,19 +1,10 @@
module Reservations
module DredgePos.Reservations.Model
open System
open DredgeFramework
open Dapper.FSharp
open DredgePos
open Types
let GetReservationById (id: int) =
select {
table "reservations"
where (eq "id" id)
}
|> db.Select<reservation>
|> first
let updateReservation (reservation: reservation) =
update{
table "reservations"
@@ -25,5 +16,5 @@ let updateReservation (reservation: reservation) =
let DeleteReservation (tableId: int) =
delete {
table "reservations"
where (eq "reservation_table_id" tableId)
where (eq "floorplan_table_id" tableId)
} |> db.Delete |> ignore

13
Reservations/Router.fs Normal file
View File

@@ -0,0 +1,13 @@
module DredgePos.Reservations.Router
open DredgePos
open DredgePos.Types
open Saturn
open Giraffe
let router = router {
pipe_through Ajax.Router.pipeline
post "/newEmptyReservation" (bindJson<reservation> Controller.newEmptyReservation)
post "/updateReservation" (bindJson<reservation> Controller.updateReservation)
post "/unreserveTable" (bindJson<floorplan_table> Controller.unreserveTable )
}

5
package-lock.json generated
View File

@@ -578,6 +578,11 @@
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
},
"tsc": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/tsc/-/tsc-2.0.4.tgz",
"integrity": "sha512-fzoSieZI5KKJVBYGvwbVZs/J5za84f2lSTLPYf6AGiIf43tZ3GNrI1QzTLcjtyDDP4aLxd46RTZq1nQxe7+k5Q=="
},
"typescript": {
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",

View File

@@ -7,9 +7,15 @@
"currency.js": "^2.0.4",
"konva": "^8.2.2",
"sass": "^1.43.4",
"tsc": "^2.0.4",
"typescript": "^4.4.4"
},
"description": "",
"license": "",
"repository": ""
"repository": "",
"scripts": {
"sass": "sass sass:wwwroot/styles",
"typescript": "tsc",
"build": "npm run sass && npm run typescript"
}
}

View File

@@ -7,12 +7,12 @@
"noImplicitAny":true,
"removeComments":false,
"preserveConstEnums":true,
"outDir":"../js",
"outDir":"wwwroot/scripts",
"target":"ES2016",
"sourceMap":true,
"moduleResolution": "node"
},
"include":[
"*"
"typescript"
]
}

View File

@@ -1,9 +1,9 @@
let showLoginBox = () => showVirtualNumpad('Enter Login Code', 6, true, false, false, authenticate)
let authenticate = (input : string) => {
let login = ajaxSync('/ajax/authenticateClerk', input)
let login = ajaxSync('/login/authenticateClerk', input)
if(login === 'success'){
location.assign('/floorplan')
location.assign('/floorplan/')
}
else
showLoginBox()

View File

@@ -50,7 +50,7 @@ const Floorplan: floorplan = {
selectedDecorationId: 0
};
$(() => ajax('/ajax/getFloorplanData/1', null, 'get', setupFloorplan, null, null) )
$(() => ajax('/floorplan/getFloorplanData/1', null, 'get', setupFloorplan, null, null) )
const setupFloorplanEvents = () => {
@@ -173,7 +173,7 @@ const createTableShape = (table: floorplan_table) => {
stroke: "black",
strokeWidth: 4,
draggable: false,
listening: true
listening: true,
});
break;
default:
@@ -276,7 +276,7 @@ const saveTable = (tableToUpdate: floorplan_table) => {
tables.push(tableToUpdate)
Floorplan.tables = tables
ajax("/ajax/transformTable", tableToUpdate, 'post', null,null,null)
ajax("/floorplan/transformTable", tableToUpdate, 'post', null,null,null)
}
const setTransformerNodes = (nodes: Konva.Shape[]) => {
@@ -347,7 +347,7 @@ const createEmptyReservation = (covers: number) => {
time: 0,
}
ajax('/ajax/newEmptyReservation', newReservation,'post', emptyReservationCreated, null, null )
ajax('/reservations/newEmptyReservation', newReservation,'post', emptyReservationCreated, null, null )
}
const emptyReservationCreated = (reservation: reservation) => {
@@ -366,7 +366,7 @@ const addReservationName = (name: string) => {
hideVirtualKeyboard()
const reservation = Floorplan.reservations.filter(reservation => reservation.floorplan_table_id == getSelectedTableData().id)[0]
reservation.name = name
ajax('/ajax/updateReservation', reservation, 'post', reservationNameAdded, null, null)
ajax('/reservations/updateReservation', reservation, 'post', reservationNameAdded, null, null)
}
const reservationNameAdded = (updatedReservation: reservation) => {
@@ -386,7 +386,7 @@ const updateTableData = (tableToRemove: floorplan_table) => {
const unreserveTable = () => {
const selectedTable = getSelectedTableData()
selectedTable.status = 0
ajax('/ajax/unreserveTable', selectedTable, 'post', tableUnreserved, null, null)
ajax('/reservations/unreserveTable', selectedTable, 'post', tableUnreserved, null, null)
}
const tableUnreserved = (table: floorplan_table) => {
@@ -500,7 +500,7 @@ const createDecorationShape = (decoration:decoration, select?: boolean) => {
}
}
decorationShape.src = 'images/decorations/' + decoration.decoration_image
decorationShape.src = '/images/decorations/' + decoration.decoration_image
}
const setupDecorationEvents = (decorationShape: Konva.Image) => {
@@ -567,7 +567,7 @@ const saveDecoration = (decorationToUpdate: decoration) => {
decorations.push(decorationToUpdate)
Floorplan.decorations = decorations
ajax("/ajax/updateDecoration", decorationToUpdate, 'post', null,null,null)
ajax("/floorplan/updateDecoration", decorationToUpdate, 'post', null,null,null)
}
const showDecorator = () => $('#decorator').css('display', 'flex')
@@ -588,7 +588,7 @@ const addDecoration = (e: Event) => {
venue_id: Floorplan.currentRoom.venue_id
}
ajax('/ajax/addDecoration', newDecoration, 'post', decorationAdded, null, null)
ajax('/floorplan/addDecoration', newDecoration, 'post', decorationAdded, null, null)
}
const decorationAdded = (decoration: decoration) => {
@@ -600,7 +600,7 @@ const decorationAdded = (decoration: decoration) => {
const deleteDecoration = () => ajax(
'/ajax/deleteDecoration',
'/floorplan/deleteDecoration',
getDecorationDataById(Floorplan.selectedDecorationId),
'post', decorationDeleted, null, null)
@@ -616,7 +616,7 @@ const setRoomBackground = (roomToLoad: room) => {
const height = Floorplan.floorplanDiv.height()
if(roomToLoad.background_image) {
Floorplan.floorplanDiv.css("background-image", `url(images/rooms/${roomToLoad?.background_image})`)
Floorplan.floorplanDiv.css("background-image", `url(/images/rooms/${roomToLoad?.background_image})`)
Floorplan.floorplanDiv.css("background-size", `${width}px ${height}px`)
}
}
@@ -735,7 +735,7 @@ const addTable = (tableNumber: number) => {
venue_id: 1
};
ajax('/ajax/createTable', newTable, 'post', tableAdded, tableNotAdded, null)
ajax('/floorplan/createTable', newTable, 'post', tableAdded, tableNotAdded, null)
}
const tableAdded = (table: floorplan_table) => {
@@ -763,7 +763,7 @@ const deleteTable = (tableNumber: number) => {
return false
}
ajax(`/ajax/deleteTable`, tableToDelete, 'post', tableDeleted, null, null);
ajax(`/floorplan/deleteTable`, tableToDelete, 'post', tableDeleted, null, null);
}
const tableDeleted = (deletedTable: floorplan_table) => {
@@ -782,7 +782,7 @@ const mergeTables = (table1: floorplan_table, table2: floorplan_table ) => {
posAlert(lang('error_self_merge'))
return false;
}
ajax('/ajax/mergeTables', [table1, table2], 'post', tablesMerged, null, null)
ajax('/floorplan/mergeTables', [table1, table2], 'post', tablesMerged, null, null)
}
const tablesMerged = (tables: Record<'child'|'parent'|'merged', floorplan_table>) => {
@@ -795,7 +795,7 @@ const tablesMerged = (tables: Record<'child'|'parent'|'merged', floorplan_table>
tableGroup.draggable(true)
}
const unmergeTable = () => ajax(`/ajax/unmergeTable/${Floorplan.selectedTableNumber}`, null, 'get', tablesUnmerged, null, null)
const unmergeTable = () => ajax(`/floorplan/unmergeTable/${Floorplan.selectedTableNumber}`, null, 'get', tablesUnmerged, null, null)
const tablesUnmerged = (tables: Record<'child'|'parent', floorplan_table>) => {
const parentTable = tables['parent']
@@ -815,7 +815,7 @@ const transferTables = (origin: floorplan_table, destination: floorplan_table) =
return
}
ajax(`/ajax/transferTable/${origin.table_number}/${destination.table_number}`, null, 'get', tableTransferred, null, null)
ajax(`/floorplan/transferTable/${origin.table_number}/${destination.table_number}`, null, 'get', tableTransferred, null, null)
}
const tableTransferred = (tables: Record<"origin"|"destination", floorplan_table>) => {

View File

@@ -303,7 +303,7 @@ const itemButtonClicked = (e: JQuery.TriggeredEvent) => {
const gridButtonClicked = (e: JQuery.TriggeredEvent) => {
const button = $(e.target).closest('.posButton')
const grid : number = button.data('grid')
ajax(`/orderScreen/getGridHtml/${grid}`, null, null,gridHtmlGenerated, null, null)
ajax(`/order/getGridHtml/${grid}`, null, null,gridHtmlGenerated, null, null)
}
@@ -571,7 +571,7 @@ const changeCoverNumberPromptSubmitted = (value: string) => updateCoverNumbers(N
const updateCoverNumbers = (covers: number) => {
let newTable = Object.assign({}, OrderScreen.table)
newTable.default_covers = covers
ajax('/orderScreen/updateCovers', newTable, 'post', coverNumbersUpdated, null, null)
ajax('/order/updateCovers', newTable, 'post', coverNumbersUpdated, null, null)
}
const coverNumbersUpdated = (newTable: floorplan_table) => {
@@ -600,5 +600,5 @@ const generateCoverSelector = () => {
$(() => {
OrderScreen.table = $('#pageContainer').data('table') || null
ajax('/orderScreen/getOrderScreenData/1', null, 'get', setupOrderScreen, null, null)
ajax('/order/getOrderScreenData/1', null, 'get', setupOrderScreen, null, null)
})

View File

@@ -228,7 +228,6 @@ let showVirtualNumpad = (heading: string, maxlength = 4, isPassword: boolean, al
index = index + 1
let currentRow : string[] = layoutToLoad[`row${index}${modifier}`]
$(row).children('a').each((keyIndex, button) => {
let key = $(button);
let keyValue: string = currentRow[keyIndex];

View File

@@ -1,6 +0,0 @@
{
"name": "ts",
"version": "1.0.0",
"dependencies": {
}
}

View File

@@ -1,9 +0,0 @@
<div id="alert" >
<div id="alertHeading"></div>
<div id="alertMessage"></div>
<div id="alertButtons">
<a class="posButton" id="alertOk"><!--[lang:alert_ok]--></a>
<a class="posButton" id="alertYes"><!--[lang:alert_yes]--></a>
<a class="posButton" id="alertNo"><!--[lang:alert_no]--></a>
</div>
</div>

View File

@@ -1,15 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title><!--[var:title]--></title>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name = "viewport" content = "user-scalable = no, initial-scale=0.8,maximum-scale=0.8 ,shrink-to-fit=yes" />
<link rel="manifest" href="/manifest.webmanifest">
</head>
<body>
<div id="authenticator">
</div>
<!--[template:keyboards]-->
</body>
</html>

View File

@@ -1,113 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>DredgePOS</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="stylesheet" type="text/css" href="themes/restaurant/theme.css?id=ax" media="screen" />
<link rel="stylesheet" type="text/css" href="themes/restaurant/paymentSplitter.css?id=ax" media="screen" />
<meta name = "viewport" content = "width=1280, initial-scale = 0.8, user-scalable = no, shrink-to-fit=no" />
<script type="text/javascript" src="currency.min.js"></script>
<script type="text/javascript" src="posFunctions.js"></script>
<script type="text/javascript" src="paymentFunctions.js"></script>
</head>
<body class="darkMode">
<div id="pageContainer">
<div id="flexWrapper">
<div id="header">
<h1>Paying Table</h2>
</div>
<div id="stucture">
<div id="leftColumn">
<h2>Whole Table</h2>
<table id="first" cellspacing="0">
<thead>
<th class="hide">Item Code</th>
<th>Qty</th>
<th>Item</th>
<th class="hide">Unit Price</th>
<th class="hide">Print Group</th>
<th class="totalpriceCell">Total Price</th>
<th class="hide">Cover</th>
<th class="clerkCell">Clerk</th>
<th class="hide">Selected Qty</th>
<th class="hide">Original Qty</th>
<th class="hide">Category</th>
<th class="hide">Department</th>
<th class="hide"><!--[lang:has_split_header]--></th>
<th class="hide"><!--[lang:orig_tprice_header]--></th>
</thead>
<tbody>
<!--[var:tableHTML]-->
</tbody>
</table>
</div>
<div id="controlColumn">
<a class="posButton" onclick="moveItems('#first', '#second')">&gt;</a>
<a class="posButton" onclick="moveItems('#second', '#first')">&lt;</a>
</div>
<div id="centerColumn">
<h2>Partial Table</h2>
<table id="second" cellspacing="0">
<thead>
<th class="hide">Item Code</th>
<th>Qty</th>
<th>Item</th>
<th class="hide">Unit Price</th>
<th class="hide">Print Group</th>
<th class="totalpriceCell">Total Price</th>
<th class="hide">Cover</th>
<th class="clerkCell hide">Clerk</th>
<th class="hide">Selected Qty</th>
<th class="hide">Category</th>
<th class="hide">Department</th>
<th class="hide"><!--[lang:has_split_header]--></th>
<th class="hide"><!--[lang:orig_tprice_header]--></th>
</thead>
<tbody>
</tbody>
</table>
</div>
<div id="rightColumn">
<h2>Controls</h2>
<div id="rightColumnContainer">
<a class="posButton heading" onclick="">Selection Tools</a>
<a class="posButton qtySelector" onclick="overrideQuantitySelect()">Select Quantity</a>
<a class="posButton" onclick="overrideQuantitySelect()">Select Amount</a>
<a class="selectDepartment posButton">Select By Department</a>
<a class="selectCategory posButton">Select By Category</a>
<a class="selectCovers posButton">Select by Cover #</a>
<a class="selectPrintGroup posButton">Select by Printed With</a>
<a class="selectAll posButton">Select All</a>
<a class="posButton heading">Select By Fraction</a>
<a class="posButton selectFraction" data-value="2">Select 12</a>
<a class="posButton selectFraction" data-value="3">Select 13</a>
<a class="posButton selectFraction" data-value="4">Select 14</a>
<a class="posButton selectFraction" data-value="5">Select 15</a>
<a class="posButton selectFraction" data-value="6">Select 16</a>
<a class="posButton selectFraction" data-value="7">Select 17</a>
<a class="posButton selectFraction" data-value="8">Select 18</a>
<a class="posButton selectFraction" data-value="<!--[var:uniqueCovers]-->" posButton">Select 1covers</a>
<a class="posButton heading" onclick="loadScreen('tableMap')">Exit</a>
</div>
</div>
</div>
</div>
</div>
<div id="coverControls" class="popupBox"><!--[var:coverButtons]--></div>
<div id="departmentControl" class="popupBox"><!--[var:departmentButtons]--></div>
<div id="categoryControl" class="popupBox"><!--[var:categoryButtons]--></div>
<div id="printGroupControl" class="popupBox"><!--[var:printGroupButtons]--></div>
<!--[template:keyboards]-->
<script type="text/javascript">
$(document).ready( function () {
covers = '<!--[var:covers]-->'
dredgePosSetup('#pageContainer');
setupPaymentSplitter();
} );
</script>
</body>
</html>

View File

@@ -1,14 +0,0 @@
<div class="itemCellWrapper">
<div
class="definedButton item <!--[arr:item|button_classes]--> posButton"
data-type="<!--[arr:item|type]-->"
data-id="<!--[arr:item|itemid]-->"
data-grid="<!--[arr:item|button_grid_id]-->"
data-name="<!--[arr:item|itemname]-->"
data-price="<!--[arr:item|price]-->"
data-category="<!--[arr:item|c_name]-->"
data-department="<!--[arr:item|dep_name]-->"
data-printgroup="<!--[arr:item|pg_name]-->">
<a><!--[arr:item|itemname]--></a>
</div>
</div>

View File

@@ -1,14 +0,0 @@
<div class="itemCellWrapper"> <div
class="definedButton item hasImage <!--[arr:item|button_classes]--> posButton"
data-type="<!--[arr:item|type]-->"
data-id="<!--[arr:item|itemid]-->"
data-name="<!--[arr:item|itemname]-->"
data-price="<!--[arr:item|price]-->"
data-grid="<!--[arr:item|button_grid_id]-->"
data-category="<!--[arr:item|c_name]-->"
data-department="<!--[arr:item|dep_name]-->"
data-printgroup="<!--[arr:item|pg_name]-->">
<a style="background-image:url('images/<!--[arr:item|image]-->')"></a>
<a><!--[arr:item|itemname]--></a>
</div></div>

View File

@@ -1,67 +0,0 @@
<div class="itemPage">
<table cellspacing="0" cellpadding="0">
<tr>
<td><!--[button:CRAFTBEER001]--></td>
<td><!--[button:CRAFTBEER002]--></td>
<td><!--[button:CRAFTBEER003]--></td>
<td><!--[button:CRAFTBEER004]--></td>
<td><!--[button:CRAFTBEER005]--></td>
<td><!--[button:CRAFTBEER006]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:CRAFTBEER007]--></td>
<td><!--[button:CRAFTBEER008]--></td>
<td><!--[button:CRAFTBEER009]--></td>
<td><!--[button:CRAFTBEER010]--></td>
<td><!--[button:CRAFTBEER012]--></td>
<td><!--[button:INSTRUCTION005]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td><!--[button:INSTRUCTION006]--></td>
</tr>
<tr>
<td><!--[button:CRAFTBEER013]--></td>
<td><!--[button:CRAFTBEER014]--></td>
<td><!--[button:CRAFTBEER015]--></td>
<td><!--[button:CRAFTBEER016]--></td>
<td><!--[button:CRAFTBEER017]--></td>
<td><!--[button:CRAFTBEER018]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:CRAFTBEER019]--></td>
<td><!--[button:CRAFTBEER020]--></td>
<td><!--[button:CRAFTBEER021]--></td>
<td><!--[button:CRAFTBEER022]--></td>
<td><!--[button:CRAFTBEER023]--></td>
<td><!--[button:CRAFTBEER024]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table></div>

View File

@@ -1,67 +0,0 @@
<div class="itemPage">
<table cellspacing="0" cellpadding="0">
<tr>
<td><!--[button:CRAFTBEER025]--></td>
<td><!--[button:CRAFTBEER026]--></td>
<td><!--[button:CRAFTBEER027]--></td>
<td><!--[button:CRAFTBEER028]--></td>
<td><!--[button:CRAFTBEER029]--></td>
<td><!--[button:CRAFTBEER030]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:CRAFTBEER031]--></td>
<td><!--[button:CRAFTBEER032]--></td>
<td><!--[button:CRAFTBEER033]--></td>
<td><!--[button:CRAFTBEER034]--></td>
<td><!--[button:CRAFTBEER035]--></td>
<td><!--[button:CRAFTBEER036]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:CRAFTBEER037]--></td>
<td><!--[button:CRAFTBEER038]--></td>
<td><!--[button:CRAFTBEER039]--></td>
<td><!--[button:CRAFTBEER040]--></td>
<td><!--[button:CRAFTBEER041]--></td>
<td><!--[button:CRAFTBEER042]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:CRAFTBEER043]--></td>
<td><!--[button:CRAFTBEER044]--></td>
<td><!--[button:CRAFTBEER045]--></td>
<td><!--[button:CRAFTBEER046]--></td>
<td><!--[button:CRAFTBEER047]--></td>
<td><!--[button:CRAFTBEER048]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table></div>

View File

@@ -1,66 +0,0 @@
<div class="itemPage"><table cellspacing="0" cellpadding="0">
<tr>
<td><!--[button:DESSERT001]--></td>
<td></td>
<td><!--[button:DESSERT002]--></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td><!--[button:DESSERT004]--></td>
<td></td>
<td><!--[button:DESSERT003]--></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table></div>

View File

@@ -1,67 +0,0 @@
<div class="itemPage"><table cellspacing="0" cellpadding="0">
<tr>
<td><!--[button:MAIN001]--></td>
<td></td>
<td><!--[button:MAIN003]--></td>
<td></td>
<td><!--[button:MAIN004]--></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:MAIN005]--></td>
<td></td>
<td><!--[button:MAIN006]--></td>
<td></td>
<td><!--[button:MAIN007]--></td>
<td></td>
</td>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table></div>

View File

@@ -1,68 +0,0 @@
<div class="itemPage">
<table cellspacing="0" cellpadding="0">
<tr>
<td><!--[button:STARTER001]--></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:STARTER002]--></td>
<td></td>
<td><!--[button:DIP002]--></td>
<td><!--[button:DIP003]--></td>
<td><!--[button:DIP004]--></td>
<td><!--[button:DIP005]--></td>
</tr>
<tr>
<td><!--[button:STARTER003]--></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:STARTER004]--></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:STARTER005]--></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table></div>

View File

@@ -1,67 +0,0 @@
<div class="itemPage"><table cellspacing="0" cellpadding="0">
<tr>
<td></td>
<td></td>
<td><!--[button:WINE002]--></td>
<td><!--[button:WINE001]--></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td><!--[button:WINE004]--></td>
<td><!--[button:WINE003]--></td>
<td></td>
<td></td>
</td>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table></div>

View File

@@ -1,3 +0,0 @@
<a onclick="loadCategory('<!--[arr:cat|c_name]-->')" class="posButton categoryButton">
<!--[arr:cat|c_name]-->
</a>

View File

@@ -1,5 +0,0 @@
<!--[categoryButton:1]-->
<!--[categoryButton:2]-->
<!--[categoryButton:4]-->
<!--[categoryButton:3]-->
<!--[categoryButton:5]-->

View File

@@ -1,3 +0,0 @@
<a class="posButton <!--[var:classes]-->" <!--[var: attributes]-->>
<!--[var:text]-->
</a>

View File

@@ -1,4 +0,0 @@
<div class="decoratorItem" data-image="<!--[var:image_url]-->">
<a style="background-image:url('images/decorations/<!--[var:image_url]-->')"></a>
<a><!--[var:image_name]--></a>
</div>

View File

@@ -1,3 +0,0 @@
<div class="decoratorRow">
<!--[var:decorations]-->
</div>

View File

@@ -1,79 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>DredgePOS</title>
<script src="https://unpkg.com/current-device/umd/current-device.min.js"></script>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name = "viewport" content = "user-scalable = no, initial-scale=0.8,maximum-scale=0.8 ,shrink-to-fit=yes" />
<link rel="manifest" href="/manifest.webmanifest">
</head>
<body class="darkMode">
<div id="pageContainer">
<div id="floorplanLeftColumn">
<div class="topCell">
<a class="posHeader">Logged in as <!--[arr:clerk|clerk_name]--></a>
</div>
<div class="middleCell">
</div>
<div class="bottomCell">
</div>
</div>
<div id="floorplanCenterColumn">
<div class="topCell">
<!--[var:roomMenu]-->
</div>
<div class="middleCell">
<div id="floorplanCanvas"></div>
</div>
<div class="bottomCell">
<div class="editControls" data-visible-in-mode='["tableSelected"]'>
<div class="posHeader currentTable">
<b class="selectedTableNumber"></b>
<a class="reservationStatus" data-visible-in-mode='["reservedTableSelected"]'></a>
<small class="selectedTableCovers"></small>
</div>
<a class="posButton placeOrderButton"><!--[lang:order_table]--></a>
<a class="posButton reserveTableButton" data-invisible-in-mode='["reservedTableSelected", "activeTableSelected"]'><!--[lang:reserve_table]--></a>
<a class="posButton unreserveTableButton" data-visible-in-mode='["reservedTableSelected"]'><!--[lang:unreserve_table]--></a>
<a class="posButton payTableButton" data-visible-in-mode='["activeTableSelected"]'><!--[lang:pay_table]--></a>
<a class="posButton viewTableButton" data-visible-in-mode='["activeTableSelected"]'><!--[lang:view_table]--></a>
</div>
</div>
</div>
<div id="floorplanRightColumn">
<div class="topCell">
<a class="posButton logOut" onclick="logout()">×</a>
</div>
<div class="middleCell">
<a class="posButton editModeButton"><!--[lang:edit_floorplan]--></a>
<div class="floorplanControls useVisibility" data-visible-in-mode='["edit"]'>
<a class="posButton addTableButton" ><!--[lang:add_table]--></a>
<a class="posButton addDecoration"><!--[lang:add_decoration]--></a>
<a class="posButton deleteDecoration useVisibility" data-visible-in-mode='["decorationSelected", "edit"]'><!--[lang:delete_decoration]--></a>
<a class="posButton deleteTableButton useVisibility" data-visible-in-mode='["tableSelected", "edit"]'><!--[lang:delete_table]--></a>
<a class="posButton changeShapeButton useVisibility" data-visible-in-mode='["tableSelected", "edit"]'><!--[lang:change_shape]--></a>
</div>
<div class="mergeControls useVisibility" data-visible-in-mode='["tableSelected"]'>
<a class="posButton mergeButton" data-active-in-mode="merge"><!--[lang:merge_table]--></a>
<a class="posButton unmergeButton" data-visible-in-mode='["tableSelected"]'><!--[lang:unmerge_table]--></a>
<a class="transferTableButton posButton" data-active-in-mode="transfer" data-visible-in-mode='["activeTableSelected"]'><!--[lang:transfer_table]--></a>
</div>
</div>
<div class="bottomCell">
</div>
</div>
</div>
<!--[template:keyboards]-->
<div id="decorator">
<div id="decoratorHeader">
<h2><!--[lang:choose_decoration]--></h2>
<a class="posButton" onclick="$('#decorator').css('display','none')">×</a>
</div>
<div id="decoratorContent"><!--[var:decorator]--></div>
</div>
</body>
</html>

View File

@@ -1,3 +0,0 @@
<!--[template:alert]-->
<!--[template:virtualNumpad]-->
<!--[template:virtualKeyboard]-->

View File

@@ -1 +0,0 @@
<b>OrderBox Loaded</b>

View File

@@ -1,21 +0,0 @@
<table cellspacing="0" id="orderBox" data-tablenumber="<!--[var:tableNumber]-->" data-covers="<!--[var:covers]-->" data-clerk="<!--[arr:clerk|clerk_name]-->" class="">
<thead>
<tr>
<th class="idCell hide"><!--[lang:id_header]--></th>
<th class="qtyCell"><!--[lang:qty_header]--></th>
<th class="itemCell"><!--[lang:item_header]--></th>
<th class="totalPriceCell"><!--[lang:total_price_header]--></th>
<th class="printGroupCell"><!--[lang:printgroup_header]--></th>
<th class="unitPriceCell hide"><!--[lang:individual_price_header]--></th>
<th class="sortkeyCell hide"><!--[lang:sortkey_header]--></th>
<th class="typeCell hide"><!--[lang:type_header]--></th>
<th class="coverCell hide"><!--[lang:cover_header]--></th>
<th class="departmentCell hide"><!--[lang:department_header]--></th>
<th class="categoryCell hide"><!--[lang:category_header]--></th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
</tfoot>
</table>

View File

@@ -1,107 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>DredgePOS</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="stylesheet" type="text/css" href="themes/restaurant/theme.css?id=ax" media="screen" />
<link rel="stylesheet" type="text/css" href="themes/restaurant/screen.css?id=ax" media="screen" />
<meta name = "viewport" content = "width=1280, initial-scale = 0.8, user-scalable = no, shrink-to-fit=no" />
<script type="text/javascript" src="posFunctions.js"></script>
</head>
<body class="darkMode">
<div id="pageContainer">
<div id="leftColumn">
<div id="tableDetails">
<h2><span id="activeTable"><!--[var:activeTable]--></span></h2>
<p class="posButton coverNumbers"><span id="covers"><!--[var:covers]--></span> covers </p>
<p class="clerk"><!--[var:loggedInAs]--></p>
</div>
<div id="orderBoxContainer">
<!--[template:orderBoxTable]-->
</div>
<div id="leftColumnFooter">
<p class="messageBox"></p>
<h2>Total Price: &nbsp; &nbsp;<span class="orderBoxTotals">$0.00</span></h2>
<p class="selectedTotal">($0.00 Selected)</p>
</div>
</div>
<div id="rightColumn">
<div id="topHalf">
<div id="courseSelect" class="posButtonGroup">
<h2><!--[lang:print_with]--></h2>
<a onclick="setPrintGroupOverride(false, this)" class="toggle default posButton active"><!--[lang:print_with_category|default]--></a>
<a onclick="setPrintGroupOverride('Starters',this)" class="posButton toggle"><!--[lang:print_with_category|Starters]--></a>
<a onclick="setPrintGroupOverride('Mains',this)" class="posButton toggle"><!--[lang:print_with_category|Mains]--></a>
<a onclick="setPrintGroupOverride('Desserts',this)" class="posButton toggle"><!--[lang:print_with_category|Desserts]--></a>
<a onclick="setPrintGroupOverride('Drinks',this)" class="posButton toggle"><!--[lang:print_with_category|Drinks]--></a>
</div>
<div id="functions">
<h2><!--[lang:functions_header]--></h2>
<a onclick="loadScreen('tableMap')" class="posButton"><!--[lang:close_order_function]--></a>
<a class="posButton accumulateButton"><!--[lang:accumulate_function]--></a>
<a class="posButton void"><!--[lang:void]--></a>
<a class="posButton"><!--[lang:pay_function]--></a>
<a class="posButton saveOrder"><!--[lang:print_function]--></a>
</div>
<div id="positionControl">
<a class="posButton freeText" data-type="instruction" data-id="freetext"
data-name=""
data-price="0"
data-category="0"
data-department="0"
data-printgroup="0"><!--[lang:freetext_button]--></a>
<div type="text" class="positionInput"><!--[lang:select_covers]--></div>
<div id="positions">
</div>
</form>
</div>
<div id="topNumPad" class="numPad">
<a class="posButton numberButton">1</a>
<a class="posButton numberButton">2</a>
<a class="posButton numberButton">3</a>
<a class="posButton numberButton">4</a>
<a class="posButton numberButton">5</a>
<a class="posButton numberButton">6</a>
<a class="posButton numberButton">7</a>
<a class="posButton numberButton">8</a>
<a class="posButton numberButton">9</a>
<a class="posButton numberButton">0</a>
<a class="posButton numberButton">.</a>
<a class="posButton multiplier">×</a>
</div>
</div>
<div id="bottomHalf">
<!--[template:categoryMenu]-->
<div id="itemGrid">
<div id="itemWrapper">
<!--[template:categories/StartersPage1]-->
</div>
</div>
<div id="innerNavigation">
<a class="posButton" onclick="scrollPage('left')">&lt;</a>
<a class="posButton" onclick="scrollPage('right')">&gt;</a>
</div>
</div>
</div>
</div>
<!--[template:keyboards]-->
<script type="text/javascript">
$(document).ready( function () {
//Base grid width must be defined for multipage functionality to work.
baseGridWidth = 850;
dredgePosSetup();
$("#orderBox tbody tr").on( 'click', function ( e ) {
selectRow($(this));
} )
} );
</script>
</body>
</html>

View File

@@ -1,84 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>DredgePOS</title>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name = "viewport" content = "user-scalable = no ,shrink-to-fit=yes" />
<link rel="manifest" href="/manifest.webmanifest">
</head>
<body>
<div id="pageContainer" <!--[var: containerAttributes]-->>
<div id="leftColumn">
<h1 class="tableHeading"><!--[var: orderNumber]--></h1>
<div class="tableInfo">
<!--[var: changeCoverNumberButton]-->
<a class="posButton">Logged in as <!--[arr:clerk|clerk_name]--></a>
</div>
<div class="orderBox">
<table class="orderBoxTable">
<thead>
<tr>
<th class="orderBoxCell qtyCell"><!--[lang:qty_header]--></th>
<th class="orderBoxCell itemIdCell hidden"><!--[lang:id_header]--></th>
<th class="orderBoxCell itemCell"><!--[lang:item_header]--></th>
<th class="orderBoxCell unitPriceCell hidden"><!--[lang:price_header]--></th>
<th class="orderBoxCell totalPriceCell"><!--[lang:total_price_header]--></th>
<th class="orderBoxCell printGroupCell"><!--[lang:printgroup_header]--></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div class="orderBoxInfo">
<span class="voidModeWarning" data-visible-in-mode='["void"]'><!--[lang:void_mode]--></span>
</div>
<div class="orderBoxFooter">
<span class="orderBoxTotal"><!--[lang:totalPrice|0.00]--></span>
<small class="orderBoxSelectedTotal"><!--[lang:selectedPrice|0.00]--></small>
</div>
</div>
<div id="rightColumn">
<div id="topHalf">
<div class="functionButtons">
<div class="printGroupButtons toggleGroup">
<input type="hidden" name="print_override" class="value" />
<!--[var:salesCategoryOverrideButtons]-->
</div>
<div class="functionColumn">
<a class="posButton accumulateButton" data-active-in-mode="accumulate"><!--[lang:accumulate_function]--></a>
<a class="showCoverSelectorButton posButton"><!--[lang:select_covers]--></a>
</div>
<div class="functionColumn">
<a class="posButton voidButton" data-active-in-mode="void"><!--[lang:void]--></a>
<a class="posButton openItemButton"><!--[lang:custom_item_button]--></a>
<a class="freetextButton posButton"><!--[lang:freetext_button]--></a>
<a class="numpadButton posButton"><!--[lang:numpad_button]--></a>
</div>
<div class="functionColumn">
<a class="posButton"><!--[lang:pay_function]--></a>
<a class="posButton"><!--[lang:print_function]--></a>
</div>
</div>
</div>
<div id="pageList">
<!--[var:categoryList]-->
</div>
<div id="pageGroupContainer">
<!--[var:pageGroups]-->
</div>
<div class="pageNavigation">
<a class="posButton prevButton"><!--[lang:prev_page]--></a>
<a class="posButton nextButton"><!--[lang:next_page]--></a>
</div>
</div>
</div>
<!--[template:keyboards]-->
<!--[template:orderScreen/grid_container]-->
<!--[template:orderScreen/cover_selector]-->
<template id="posButtonTemplate">
<!--[template:components/posButton]-->
</template>
</body>
</html>

View File

@@ -1 +0,0 @@
<span class="buttonImg" style="background-image:url(/images/items/<!--[var:image]-->);"></span>

View File

@@ -1 +0,0 @@
<a href="#" class="posButton changeCoverNumberButton"><!--[var:covers]--></a>

View File

@@ -1,3 +0,0 @@
<div class="coverSelector">
<!--[var:coverSelectorButtons]-->
</div>

View File

@@ -1,6 +0,0 @@
<a href="#" class="posButton <!--[var:extra_classes]-->"
data-primary-action="<!--[var:primary_action]-->"
data-secondary-action="<!--[var:secondary_action]-->" <!--[var: extra_data]--> <!--[var: extra_styles]-->>
<!--[var:image]-->
<span class="text"><!--[var:text]--></span>
</a>

View File

@@ -1,13 +0,0 @@
<div class="gridContainer">
<div class="gridContainerHeader">
<span></span>
<div class="posButton closeGrid">×</div>
</div>
<div class="gridContainerGrid">
<div class="pageGroup"></div>
</div>
<div class="pageNavigation">
<a class="posButton prevButton"><!--[lang:prev_page]--></a>
<a class="posButton nextButton"><!--[lang:next_page]--></a>
</div>
</div>

View File

@@ -1,6 +0,0 @@
<div class="gridPage" style="
grid-template-columns: repeat(<!--[var:cols]-->, 1fr);
grid-template-rows: repeat(<!--[var:rows]-->, 1fr);
">
<!--[var:pageButtons]-->
</div>

View File

@@ -1,3 +0,0 @@
<div class="pageGroup" data-page-group-id="<!--[var:page_group_id]-->">
<!--[var:pages]-->
</div>

View File

@@ -1,3 +0,0 @@
<a data-page-group-id="<!--[arr:page|id]-->" class="posButton loadPageGroup">
<!--[arr:page|label]-->
</a>

View File

@@ -1,157 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>DredgePOS</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://unpkg.com/current-device/umd/current-device.min.js"></script>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="stylesheet" type="text/css" href="themes/restaurant/theme.css?id=ax" media="screen" />
<link rel="stylesheet" type="text/css" href="themes/restaurant/paymentSplitter.css?id=ax" media="screen" />
<meta name = "viewport" content = "user-scalable = no, initial-scale=0.8 ,shrink-to-fit=yes" />
<script type="text/javascript" src="currency.min.js"></script>
<script type="text/javascript" src="posFunctions.js"></script>
<script type="text/javascript" src="paymentFunctions.js"></script>
</head>
<body class="darkMode" data-tablenumber="<!--[var:activeTable]-->">
<div id="pageContainer">
<div id="flexWrapper">
<div id="header">
<a class="posButton"><!--[var:loggedInAs]--></a>
<h1><!--[lang:paying_table|<!--[var:activeTable]-->]--></h1>
<a class="posButton exit" onclick="loadScreen('tableMap')">×</a>
</div>
<div id="pageStructure">
<div id="leftColumn">
<h2>Whole Table</h2>
<div class="tableWrapper">
<table id="first" cellspacing="0">
<thead>
<th class="hide"><!--[lang:id_header]--></th>
<th><!--[lang:qty_header]--></th>
<th><!--[lang:item_header]--></th>
<th class="hide"><!--[lang:individual_price_header]--></th>
<th class="hide"><!--[lang:printgroup_header]--></th>
<th class="totalpriceCell"><!--[lang:total_price_header]--></th>
<th class="hide"><!--[lang:cover_header]--></th>
<th class="clerkCell"><!--[lang:clerk_header]--></th>
<th class="hide"><!--[lang:orig_qty_header]--></th>
<th class="hide"><!--[lang:category_header]--></th>
<th class="hide"><!--[lang:department_header]--></th>
<th class="hide"><!--[lang:orig_tprice_header]--></th>
</thead>
<tbody>
<!--[var:tableHTML]-->
</tbody>
</table>
</div>
<div class="tableFooter">
<div class="totalsRow">
<h3 class="firstTotal"></h3>
<p class="firstSelectedTotal"></p>
</div>
<div class="controlRow">
<a class="posButton payAll"><!--[lang:pay_all]--></a>
</div>
</div>
</div>
<div id="controlColumn">
<a class="posButton" onclick="moveItems('#first', '#second')">&gt;</a>
<a class="posButton" onclick="moveItems('#second', '#first')">&lt;</a>
</div>
<div id="centerColumn">
<h2>Partial Table</h2>
<div class="tableWrapper">
<table id="second" cellspacing="0">
<thead>
<th class="hide"><!--[lang:id_header]--></th>
<th><!--[lang:qty_header]--></th>
<th><!--[lang:item_header]--></th>
<th class="hide"><!--[lang:individual_price_header]--></th>
<th class="hide"><!--[lang:printgroup_header]--></th>
<th class="totalpriceCell"><!--[lang:total_price_header]--></th>
<th class="hide"><!--[lang:cover_header]--></th>
<th class="clerkCell"><!--[lang:clerk_header]--></th>
<th class="hide"><!--[lang:orig_qty_header]--></th>
<th class="hide"><!--[lang:category_header]--></th>
<th class="hide"><!--[lang:department_header]--></th>
<th class="hide"><!--[lang:orig_tprice_header]--></th>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="tableFooter">
<div class="totalsRow">
<h3 class="secondTotal"></h3>
<p class="secondSelectedTotal"></p>
</div>
<div class="controlRow">
<a class="posButton payPartial"><!--[lang:pay_table]--></a>
<a class="posButton transferPartial">Transfer to Another Table</a>
<a class="posButton selectAllSecond">Select All</a>
</div>
</div>
</div>
<div id="rightColumn">
<h2>Controls</h2>
<div id="rightColumnContainer">
<div class="row">
<a class="heading" onclick="">Selection Tools</a>
</div>
<div class="row">
<a class="posButton qtySelector">Select Quantity</a>
<a class="posButton selectAmount">Select Amount</a>
</div>
<div class="row">
<a class="selectDepartment posButton">Select By Department</a>
<a class="selectCategory posButton">Select By Category</a>
</div>
<div class="row">
<a class="selectCovers posButton">Select by Cover #</a>
<a class="selectPrintGroup posButton">Select by Printed With</a>
</div>
<div class="row">
<a class="selectAll posButton">Select All</a>
</div>
<div class="row">
<a class="heading">Select By Fraction</a>
</div>
<div class="row">
<a class="posButton selectFraction" data-value="2">Select 12</a>
<a class="posButton selectFraction" data-value="3">Select 13</a>
</div>
<div class="row">
<a class="posButton selectFraction" data-value="4">Select 14</a>
<a class="posButton selectFraction" data-value="5">Select 15</a>
</div>
<div class="row">
<a class="posButton selectFraction" data-value="6">Select 16</a>
<a class="posButton selectFraction" data-value="7">Select 17</a>
</div>
<div class="row">
<a class="posButton selectFraction" data-value="8">Select 18</a>
<a class="posButton selectFraction" data-value="<!--[var:covers]-->">Select 1covers</a>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="coverControls" class="popupBox"><!--[var:coverButtons]--></div>
<div id="departmentControl" class="popupBox"><!--[var:departmentButtons]--></div>
<div id="categoryControl" class="popupBox"><!--[var:categoryButtons]--></div>
<div id="printGroupControl" class="popupBox"><!--[var:printGroupButtons]--></div>
<!--[template:keyboards]-->
<script type="text/javascript">
$(document).ready( function () {
covers = '<!--[var:covers]-->'
dredgePosSetup('#pageContainer');
setupPaymentSplitter();
} );
</script>
</body>
</html>

View File

@@ -1 +0,0 @@
<a data-value="<!--[var:value]-->" class="posButton <!--[var:class]-->"><!--[var:text]--></a>

View File

@@ -1 +0,0 @@
<a class="posButton roomButton" data-value="<!--[var:roomId]-->"><!--[var:roomName]--></a>

View File

@@ -1,71 +0,0 @@
<div id="virtualKeyboard">
<div class="headingRow">
<h3 id="virtualKeyboardHeading"></h3>
<a class="posButton closeKeyboards">X</a>
</div>
<input type="text" name="virtualKeyboardInput" id="virtualKeyboardInput" />
<div id="virtualKeyboardButtons">
<div class="virtualKeyboardRow">
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
</div>
<div class="virtualKeyboardRow">
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
</div>
<div class="virtualKeyboardRow">
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
</div>
<div class="virtualKeyboardRow">
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
</div>
<div class="virtualKeyboardRow">
<a></a>
</div>
<span class="forceFocus"></span>
</div>
</div>

View File

@@ -1,28 +0,0 @@
<div id="virtualNumpad">
<div class="headingRow">
<h3 id="virtualNumpadHeading"></h3>
<a class="posButton closeKeyboards">X</a>
</div>
<div id="virtualNumpadInput"></div>
<div id="virtualNumpadButtons">
<div class="virtualNumpadRow">
<a href="#" data-value="1" class="posButton virtualNumpadButton">1</a>
<a href="#" data-value="2" class="posButton virtualNumpadButton">2</a>
<a href="#" data-value="3" class="posButton virtualNumpadButton">3</a>
</div><div class="virtualNumpadRow">
<a href="#" data-value="4" class="posButton virtualNumpadButton">4</a>
<a href="#" data-value="5" class="posButton virtualNumpadButton">5</a>
<a href="#" data-value="6" class="posButton virtualNumpadButton">6</a>
</div><div class="virtualNumpadRow">
<a href="#" data-value="7" class="posButton virtualNumpadButton">7</a>
<a href="#" data-value="8" class="posButton virtualNumpadButton">8</a>
<a href="#" data-value="9" class="posButton virtualNumpadButton">9</a>
</div><div class="virtualNumpadRow">
<a href="#" data-value="0" class="posButton virtualNumpadButton">0</a>
<a href="#" data-value="." class="posButton virtualNumpadButton">.</a>
<a href="#" data-value="clear" class="posButton virtualNumpadButton virtualNumpadClear">Clear</a>
</div><div class="virtualNumpadRow">
<a href="#" data-value="submit" class="posButton virtualNumpadButton virtualNumpadSubmit">Enter</a>
</div>
</div>
</div>