Skip to content

Commit

Permalink
calendarProInput: parse value
Browse files Browse the repository at this point in the history
  • Loading branch information
pvictor committed Nov 13, 2024
1 parent fb4fcb0 commit 55362f4
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 10 deletions.
25 changes: 24 additions & 1 deletion R/calendar-pro-input.R
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,25 @@ html_dependency_calendar_pro <- function() {
#' @param weekNumbers With this parameter, you can decide whether to display week numbers in the calendar.
#' @param weekNumbersSelect If `TRUE` select the week when week number is clicked.
#' @param weekend This parameter allows you to highlight weekends in the calendar.
#' @param time This parameter enables time selection. You can also specify the time format using a boolean value or a number: 24-hour or 12-hour format.
#' @param timeValue Initial time value.
#' @param ... Other settings passed to Slim Select JAvaScript method.
#' @param positionToInput This parameter specifies the position of the calendar relative to input,
#' if the calendar is initialized with the input parameter. Possible values: 'auto' | 'center' | 'left' | 'right' | c('bottom' | 'top', 'center' | 'left' | 'right')
#' @param theme This parameter determines the theme of the calendar : 'light' or 'dark'.
#' @param placeholder A character string giving the user a hint as to what can be entered into the control.
#' @param input If `TRUE` (default), use an input and render calendar in a dropdown, otherwise calendar is rendered in the page.
#' @param inline Display calendar container inline.
#' @param parseValue Convert input value to date/datetime in server or not.
#'
#' @return
#' * UI: A `shiny.tag` object that can be used in a UI definition.
#' * server: a **character** vector of dates selected
#' @export
#'
#' @importFrom utils modifyList
#' @importFrom htmltools tags
#'
#' @example examples/calendar-pro.R
calendarProInput <- function(inputId,
label,
Expand All @@ -69,25 +75,41 @@ calendarProInput <- function(inputId,
weekNumbers = FALSE,
weekNumbersSelect = FALSE,
weekend = TRUE,
time = NULL,
timeValue = NULL,
...,
positionToInput = "auto",
theme = "light",
placeholder = NULL,
input = TRUE,
inline = FALSE,
parseValue = TRUE,
width = NULL) {
# selected <- restoreInput(id = inputId, default = selected)
type <- match.arg(type)
parseValue <- if (isTRUE(parseValue)) {
if (type %in% c("month", "year")) {
"calendarPro.monthyear"
} else {
"calendarPro.date"
}
} else {
"calendarPro.raw"
}
config <- list(
type = if (type == "range") "multiple" else type,
months = months,
jumpMonths = jumpMonths,
jumpToSelectedDate = jumpToSelectedDate,
toggleSelected = toggleSelected,
weekNumbersSelect = weekNumbersSelect,
...
parseValue = parseValue
)
config$input <- input
config$settings$selection$time <- time
config$settings$selected$time <- timeValue
if (!is.null(value))
value <- format(value, format = "%Y-%m-%d")
config$settings$selected$dates <- list1(value)
if (type == "multiple")
config$settings$selection$day <- "multiple"
Expand All @@ -105,6 +127,7 @@ calendarProInput <- function(inputId,
config$settings$visibility$weekNumbers <- weekNumbers
config$settings$visibility$weekend <- weekend
config$settings$visibility$positionToInput <- positionToInput
config <- modifyList(config, list(...))
tag_el <- if (isTRUE(input)) {
tags$input(
type = "text",
Expand Down
48 changes: 47 additions & 1 deletion R/onLoad.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#' @noRd
#'
.onLoad <- function(...) {
shiny::addResourcePath('shinyWidgets', system.file("assets", package = "shinyWidgets"))
shiny::addResourcePath("shinyWidgets", system.file("assets", package = "shinyWidgets"))
shiny::registerInputHandler("sw.numericRange", function(data, ...) {
if (is.null(data)) {
NULL
Expand Down Expand Up @@ -66,4 +66,50 @@
data
}
}, force = TRUE)
shiny::registerInputHandler("calendarPro.date", function(data, ...) {
if (length(data) < 1 || length(data$selectedDates) < 1)
return(NULL)
if (!is.null(data$selectedTime)) {
fmt <- if (grepl(pattern = "(A|P)M", x = data$selectedTime)) {
"%Y-%m-%d %I:%M %p"
} else {
"%Y-%m-%d %H:%M"
}
res <- try(as.POSIXct(
paste(unlist(data$selectedDates), data$selectedTime),
format = fmt
), silent = TRUE)
} else {
res <- try(as.Date(unlist(data$selectedDates)), silent = TRUE)
}
if (inherits(res, "try-error")) {
warning("calendarProInput: Failed to parse dates, try using parseValue = FALSE", call. = FALSE)
data
} else {
res
}
}, force = TRUE)
shiny::registerInputHandler("calendarPro.monthyear", function(data, ...) {
if (length(data) < 1)
return(NULL)
res <- try(as.Date(
paste(
data$selectedYear,
data$selectedMonth + 1,
"01",
sep = "-"
)
), silent = TRUE)
if (inherits(res, "try-error")) {
warning("calendarProInput: Failed to parse dates, try using parseValue = FALSE", call. = FALSE)
data
} else {
res
}
}, force = TRUE)
shiny::registerInputHandler("calendarPro.raw", function(data, ...) {
if (length(data) < 1)
return(NULL)
return(data)
}, force = TRUE)
}
103 changes: 103 additions & 0 deletions inst/examples/calendar-pro/value/app.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@

library(shiny)
library(shinyWidgets)

parseValue <- TRUE

ui <- fluidPage(
theme = bslib::bs_theme(5),
tags$h2("Calendar Pro Input"),
fluidRow(
column(
width = 6,
calendarProInput(
inputId = "cal1",
label = "Date selection:",
placeholder = "Select a date",
width = "100%",
parseValue = parseValue
),
verbatimTextOutput("res1"),

calendarProInput(
inputId = "cal3",
label = "Date selection (with default):",
value = Sys.Date() + 2,
placeholder = "Select a date",
width = "100%",
parseValue = parseValue
),
verbatimTextOutput("res3"),

calendarProInput(
inputId = "cal5",
label = "Month selection:",
placeholder = "Select a month",
type = "month",
width = "100%",
parseValue = parseValue
),
verbatimTextOutput("res5"),

calendarProInput(
inputId = "cal7",
label = "Year selection:",
placeholder = "Select a year",
# settings = list(selection = list(month = FALSE)),
type = "year",
width = "100%",
parseValue = parseValue
),
verbatimTextOutput("res7")
),
column(
width = 6,
calendarProInput(
inputId = "cal2",
label = "Multiple date selection:",
type = "multiple",
placeholder = "Select multiple date ",
width = "100%",
parseValue = parseValue
),
verbatimTextOutput("res2"),

calendarProInput(
inputId = "cal4",
label = "Datetime selection:",
placeholder = "Select date and time",
time = 12,
width = "100%",
parseValue = parseValue
),
verbatimTextOutput("res4"),

calendarProInput(
inputId = "cal6",
label = "Datetime selection (with default):",
value = Sys.Date(),
time = 24,
timeValue = "10:00",
placeholder = "Select date and time",
width = "100%",
parseValue = parseValue
),
verbatimTextOutput("res6")
)
)
)

server <- function(input, output, session) {

output$res1 <- renderPrint(str(input$cal1))
output$res2 <- renderPrint(str(input$cal2))
output$res3 <- renderPrint(str(input$cal3))
output$res4 <- renderPrint(str(input$cal4))
output$res5 <- renderPrint(str(input$cal5))
output$res6 <- renderPrint(str(input$cal6))
output$res7 <- renderPrint(str(input$cal7))

}

if (interactive())
shinyApp(ui, server)
2 changes: 1 addition & 1 deletion inst/packer/calendar-pro.js

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions man/calendarProInput.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 52 additions & 7 deletions srcjs/inputs/vanilla-calendar-pro.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,26 @@ function changeToInputMultiple(e, self) {
}
}


const pick = (obj, ...keys) => Object.fromEntries(
keys
.filter(key => key in obj)
.map(key => [key, obj[key]])
);

var calendarProBinding = new Shiny.InputBinding();
$.extend(calendarProBinding, {
store: [],
updateStore: (el, instance) => {
calendarProBinding.store[el.id] = instance;
},
value: [],
updateValue: (el, instance) => {
calendarProBinding.value[el.id] = instance;
updateValue: (el, value) => {
calendarProBinding.value[el.id] = value;
},
type: [],
updateType: (el, type) => {
calendarProBinding.type[el.id] = type;
},
find: scope => {
return $(scope).find(".vanilla-calendar-pro");
Expand All @@ -46,6 +57,9 @@ $.extend(calendarProBinding, {
},
setValue: (el, value) => {

},
getType: el => {
return calendarProBinding.type[el.id];
},
subscribe: (el, callback) => {
$(el).on("change.calendarProBinding", function(e) {
Expand All @@ -67,15 +81,40 @@ $.extend(calendarProBinding, {
config = JSON.parse(config.text);
if (!config.hasOwnProperty("actions"))
config.actions = {};
config.actions.clickDay = function(event, self) {
calendarProBinding.updateValue(el, self.selectedDates);
function updateValueOnChange(event, self) {
calendarProBinding.updateValue(
el,
pick(
self,
"selectedDates",
"selectedHolidays",
"selectedMonth",
"selectedYear",
"selectedHours",
"selectedMinutes",
"selectedTime",
"selectedKeeping",
),
);
$(el).trigger("change");
};
}
config.actions.clickDay = updateValueOnChange;
config.actions.clickMonth = updateValueOnChange;
config.actions.clickYear = updateValueOnChange;
config.actions.changeTime = updateValueOnChange;
if (config.weekNumbersSelect) {
config.actions.clickWeekNumber = function(event, number, days, year, self) {
self.settings.selected.dates = days.map((day) => day.dataset.calendarDay);
self.update({ dates: true });
calendarProBinding.updateValue(el, self.selectedDates);
calendarProBinding.updateValue(
el,
pick(
self,
"selectedDates", "selectedHolidays", "selectedMonth",
"selectedYear", "selectedHours", "selectedMinutes",
"selectedTime", "selectedKeeping"
)
);
$(el).trigger("change");
};
}
Expand All @@ -87,7 +126,13 @@ $.extend(calendarProBinding, {
const calendar = new VanillaCalendar(input, config);
calendar.init();
calendarProBinding.updateStore(el, calendar);
calendarProBinding.updateValue(el, config?.settings?.selected?.dates);
calendarProBinding.updateValue(el, {
selectedDates: config?.settings?.selected?.dates,
selectedMonth: config?.settings?.selected?.month,
selectedYear: config?.settings?.selected?.year,
selectedTime: config?.settings?.selected?.time
});
calendarProBinding.updateType(el, config.parseValue);
$(el).trigger("change");
}
});
Expand Down

0 comments on commit 55362f4

Please sign in to comment.