Version 3 #40
|
@ -60,7 +60,11 @@ module EditProfileViewModel =
|
||||||
FullTime = false
|
FullTime = false
|
||||||
Biography = ""
|
Biography = ""
|
||||||
Experience = None
|
Experience = None
|
||||||
Skills = [||]
|
Skills = [|
|
||||||
|
{ Id = "1"; Description = "test 1"; Notes = None }
|
||||||
|
{ Id = "3"; Description = "test 2"; Notes = Some "noted" }
|
||||||
|
{ Id = "4"; Description = "asfasdfa"; Notes = None }
|
||||||
|
|]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an instance of this form from the given profile
|
/// Create an instance of this form from the given profile
|
||||||
|
|
|
@ -7,12 +7,13 @@ open Giraffe.ViewEngine
|
||||||
open Giraffe.ViewEngine.Htmx
|
open Giraffe.ViewEngine.Htmx
|
||||||
open JobsJobsJobs.ViewModels
|
open JobsJobsJobs.ViewModels
|
||||||
|
|
||||||
|
/// Render the skill edit template and existing skills
|
||||||
let skillEdit (skills : SkillForm array) =
|
let skillEdit (skills : SkillForm array) =
|
||||||
let mapToInputs (idx : int) (skill : SkillForm) =
|
let mapToInputs (idx : int) (skill : SkillForm) =
|
||||||
div [ _class "row pb-3" ] [
|
div [ _id $"skillRow{skill.Id}"; _class "row pb-3" ] [
|
||||||
div [ _class "col-2 col-md-1 align-self-center" ] [
|
div [ _class "col-2 col-md-1 align-self-center" ] [
|
||||||
button [ _class "btn btn-sm btn-outline-danger rounded-pill"; _title "Delete"
|
button [ _class "btn btn-sm btn-outline-danger rounded-pill"; _title "Delete"
|
||||||
_onclick $"jjj.removeSkill('{skill.Id}')" ] [
|
_onclick $"jjj.profile.removeSkill('{skill.Id}')" ] [
|
||||||
rawText " − "
|
rawText " − "
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
@ -23,7 +24,8 @@ let skillEdit (skills : SkillForm array) =
|
||||||
_maxlength "200"; _value skill.Description; _required ]
|
_maxlength "200"; _value skill.Description; _required ]
|
||||||
label [ _class "jjj-label"; _for $"skillDesc{skill.Id}" ] [ rawText "Skill" ]
|
label [ _class "jjj-label"; _for $"skillDesc{skill.Id}" ] [ rawText "Skill" ]
|
||||||
]
|
]
|
||||||
div [ _class "form-text" ] [ rawText "A skill (language, design technique, process, etc.)" ]
|
if idx < 1 then
|
||||||
|
div [ _class "form-text" ] [ rawText "A skill (language, design technique, process, etc.)" ]
|
||||||
]
|
]
|
||||||
div [ _class "col-12 col-md-5" ] [
|
div [ _class "col-12 col-md-5" ] [
|
||||||
div [ _class "form-floating" ] [
|
div [ _class "form-floating" ] [
|
||||||
|
@ -33,7 +35,8 @@ let skillEdit (skills : SkillForm array) =
|
||||||
_value (defaultArg skill.Notes "") ]
|
_value (defaultArg skill.Notes "") ]
|
||||||
label [ _class "jjj-label"; _for $"skillNotes{skill.Id}" ] [ rawText "Notes" ]
|
label [ _class "jjj-label"; _for $"skillNotes{skill.Id}" ] [ rawText "Notes" ]
|
||||||
]
|
]
|
||||||
div [ _class "form-text" ] [ rawText "A further description of the skill" ]
|
if idx < 1 then
|
||||||
|
div [ _class "form-text" ] [ rawText "A further description of the skill" ]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
template [ _id "newSkill" ] [ mapToInputs -1 { Id = ""; Description = ""; Notes = None } ]
|
template [ _id "newSkill" ] [ mapToInputs -1 { Id = ""; Description = ""; Notes = None } ]
|
||||||
|
@ -97,7 +100,7 @@ let edit (m : EditProfileViewModel) continents isNew csrf =
|
||||||
hr []
|
hr []
|
||||||
h4 [ _class "pb-2" ] [
|
h4 [ _class "pb-2" ] [
|
||||||
rawText "Skills "
|
rawText "Skills "
|
||||||
button [ _class "btn btn-sm btn-outline-primary rounded-pill"; _onclick "jjj.addSkill" ] [
|
button [ _class "btn btn-sm btn-outline-primary rounded-pill"; _onclick "jjj.profile.addSkill()" ] [
|
||||||
rawText "Add a Skill"
|
rawText "Add a Skill"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
@ -140,4 +143,9 @@ let edit (m : EditProfileViewModel) continents isNew csrf =
|
||||||
rawText "(If you want to delete your profile, or your entire account, "
|
rawText "(If you want to delete your profile, or your entire account, "
|
||||||
a [ _href "/so-long/options" ] [ rawText "see your deletion options here" ]; rawText ".)"
|
a [ _href "/so-long/options" ] [ rawText "see your deletion options here" ]; rawText ".)"
|
||||||
]
|
]
|
||||||
|
script [] [
|
||||||
|
rawText """addEventListener("DOMContentLoaded", function () {"""
|
||||||
|
rawText $" jjj.profile.nextIndex = {m.Skills.Length} "
|
||||||
|
rawText "})"
|
||||||
|
]
|
||||||
]
|
]
|
||||||
|
|
|
@ -41,17 +41,73 @@ this.jjj = {
|
||||||
/**
|
/**
|
||||||
* The time zone of the current browser
|
* The time zone of the current browser
|
||||||
* @type {string}
|
* @type {string}
|
||||||
**/
|
*/
|
||||||
timeZone: undefined,
|
timeZone: undefined,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derive the time zone from the current browser
|
* Derive the time zone from the current browser
|
||||||
*/
|
*/
|
||||||
deriveTimeZone () {
|
deriveTimeZone () {
|
||||||
try {
|
try {
|
||||||
this.timeZone = (new Intl.DateTimeFormat()).resolvedOptions().timeZone
|
this.timeZone = (new Intl.DateTimeFormat()).resolvedOptions().timeZone
|
||||||
} catch (_) { }
|
} catch (_) { }
|
||||||
}
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Script for profile pages
|
||||||
|
*/
|
||||||
|
profile: {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The next index for a newly-added skill
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
nextIndex: 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a skill to the profile form
|
||||||
|
*/
|
||||||
|
addSkill() {
|
||||||
|
const newId = `new${this.nextIndex}`
|
||||||
|
|
||||||
|
/** @type {HTMLTemplateElement} */
|
||||||
|
const newSkillTemplate = document.getElementById("newSkill")
|
||||||
|
/** @type {HTMLDivElement} */
|
||||||
|
const newSkill = newSkillTemplate.content.firstElementChild.cloneNode(true)
|
||||||
|
newSkill.setAttribute("id", `skillRow${newId}`)
|
||||||
|
|
||||||
|
const cols = newSkill.children
|
||||||
|
// Button column
|
||||||
|
cols[0].querySelector("button").setAttribute("onclick", `jjj.profile.removeSkill('${newId}')`)
|
||||||
|
// Skill column
|
||||||
|
const skillField = cols[1].querySelector("input")
|
||||||
|
skillField.setAttribute("id", `skillDesc${newId}`)
|
||||||
|
skillField.setAttribute("name", `Skills[${this.nextIndex}].Description`)
|
||||||
|
cols[1].querySelector("label").setAttribute("for", `skillDesc${newId}`)
|
||||||
|
if (this.nextIndex > 0) cols[1].querySelector("div.form-text").remove()
|
||||||
|
// Notes column
|
||||||
|
const notesField = cols[2].querySelector("input")
|
||||||
|
notesField.setAttribute("id", `skillNotes${newId}`)
|
||||||
|
notesField.setAttribute("name", `Skills[${this.nextIndex}].Notes`)
|
||||||
|
cols[2].querySelector("label").setAttribute("for", `skillNotes${newId}`)
|
||||||
|
if (this.nextIndex > 0) cols[2].querySelector("div.form-text").remove()
|
||||||
|
|
||||||
|
// Add the row
|
||||||
|
const skills = document.querySelectorAll("div[id^=skillRow]")
|
||||||
|
const sibling = skills.length > 0 ? skills[skills.length - 1] : newSkillTemplate
|
||||||
|
sibling.insertAdjacentElement('afterend', newSkill)
|
||||||
|
|
||||||
|
this.nextIndex++
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a skill row from the profile form
|
||||||
|
* @param {string} id The ID of the skill row to remove
|
||||||
|
*/
|
||||||
|
removeSkill(id) {
|
||||||
|
document.getElementById(`skillRow${id}`).remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
htmx.on("htmx:configRequest", function (evt) {
|
htmx.on("htmx:configRequest", function (evt) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user