diff --git a/DESCRIPTION b/DESCRIPTION index c1a25f4..9a28d6b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,16 +1,17 @@ Package: shinyRatings Title: An intuitive way of providing star rating on a shiny app -Version: 0.0.1 +Version: 0.0.2 Authors@R: person("Ronak", "Shah", , "shahronak47@yahoo.in", role = c("aut", "cre")) Description: An intuitive way of providing star rating on a shiny app. License: MIT + file LICENSE Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.1 +RoxygenNote: 7.2.3 Suggests: covr, testthat (>= 3.0.0) Config/testthat/edition: 3 Imports: shiny, - htmltools + htmltools, + jsonlite diff --git a/NEWS.md b/NEWS.md index 71c935d..4ba1094 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +# shinyRatings 0.0.2 + +* Add a disabled argument in `shinyRatings` function. +* [Allow possibility of variable number of stars](https://github.com/shahronak47/shinyRatings/issues/9) +* [Add default value of starts selected](https://github.com/shahronak47/shinyRatings/issues/9) + # shinyRatings 0.0.1 * [Fix center alignment of all the elements](https://github.com/shahronak47/shinyRatings/issues/11) diff --git a/R/shinyRatings.R b/R/shinyRatings.R index 9032637..825a14c 100644 --- a/R/shinyRatings.R +++ b/R/shinyRatings.R @@ -1,7 +1,9 @@ #' Include ratings in shiny UI #' #' @param inputId The input slot that will be used to access the value of number of stars. -#' +#' @param no_of_stars Number of stars that you want to display on the UI. +#' @param default Number of stars selected by default. +#' @param disabled Keep number of stars as fixed? Disable the option of changing values #' @return Ratings to be added to UI definition #' @examples #' if(interactive()){ @@ -22,44 +24,55 @@ #' #' @export #' -shinyRatings <- function(inputId) { +shinyRatings <- function(inputId, no_of_stars = 5, default = no_of_stars, disabled = FALSE) { + do_checks(no_of_stars, default, disabled) + # Since in HTML 2 check box constitute of 1 star + calculate_def <- default * 2 htmltools::tags$html( htmltools::tags$head( htmltools::tags$link(type = "text/css", href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css", rel = "stylesheet"), htmltools::tags$link(type = "text/css", href = "files/style.css", rel = "stylesheet"), - htmltools::tags$script(src="files/shinyRatingsBinding.js"), + htmltools::tags$script(src="files/shinyRatingsBinding.js") ), htmltools::tags$body( shiny::div(id = inputId, class = "shinyRatings", - htmltools::HTML(ratings_html()) + htmltools::HTML(ratings_html(no_of_stars, disabled)), data = jsonlite::toJSON(list(n = calculate_def)) ) ) ) } #' @noRd -ratings_html <- function() { - ' -
' -} \ No newline at end of file +ratings_html <- function(n, disabled) { + half_num <- seq(0.5, n, 1) + full_num <- seq(1, n, 1) + half_num_chr <- sub('.', '', half_num, fixed = TRUE) + full_num_chr <- paste0(full_num, '0') + + dynamic_html <- paste0( + sprintf( + ' + + +', + half_num, half_num_chr, half_num_chr, half_num, full_num, full_num_chr, full_num_chr, full_num + ), collapse = '') + + if(isTRUE(disabled)) { + # Add disabled attribute to input elements + dynamic_html <- gsub('%s', dynamic_html) +} + +#' @noRd +do_checks <- function(no_of_stars, default, disabled) { + # no_of_stars should be a whole number or should end with .5 + stopifnot("no_of_stars can be a whole number or a number ending with .5" = no_of_stars %% 1 %in% c(0, .5)) + # default value should be a whole number or should end with .5 + stopifnot("default value can be a whole number or a number ending with .5" = default %% 1 %in% c(0, .5)) + # default value should not be greater than no_of_stars + stopifnot("default value can be greater than 0 and less than `no_of_stars`" = default > 0 && default <= no_of_stars) + # disabled can handle only logical values + stopifnot("disabled can take only logical values (TRUE/FALSE)" = is.logical(disabled)) +} diff --git a/inst/exdata/shinyRatingsBinding.js b/inst/exdata/shinyRatingsBinding.js index f60777e..4f13975 100644 --- a/inst/exdata/shinyRatingsBinding.js +++ b/inst/exdata/shinyRatingsBinding.js @@ -7,6 +7,20 @@ $.extend(shinyRatingsInputBinding, { return $(scope).find(".shinyRatings"); }, + initialize: function(el){ + /* Get default value */ + var data = JSON.parse(el.getAttribute('data')); + var n = data.n; + /* Manually set the check property to TRUE for default number of stars */ + var count = 0 + $(el).find("input").each(function(inputitem){ + count = count + 1 + if(count <= n) { + $(this).prop("checked", "true"); + } + }); + }, + getValue: function(el) { var rate_value = 0; $(el).find("input").each(function(inputitem){ @@ -14,16 +28,13 @@ $.extend(shinyRatingsInputBinding, { rate_value = parseFloat($(this).val()); } }); - if (rate_value == 0) { - rate_value = 5; - } return(rate_value) }, setValue: function(el, value) { el.value = value; }, - + subscribe: function(el, callback) { $(el).on('change.shinyRatings', function(event) { callback(false); diff --git a/man/shinyRatings.Rd b/man/shinyRatings.Rd index 7b2ab46..78d0564 100644 --- a/man/shinyRatings.Rd +++ b/man/shinyRatings.Rd @@ -4,10 +4,16 @@ \alias{shinyRatings} \title{Include ratings in shiny UI} \usage{ -shinyRatings(inputId) +shinyRatings(inputId, no_of_stars = 5, default = no_of_stars, disabled = FALSE) } \arguments{ \item{inputId}{The input slot that will be used to access the value of number of stars.} + +\item{no_of_stars}{Number of stars that you want to display on the UI.} + +\item{default}{Number of stars selected by default.} + +\item{disabled}{Keep number of stars as fixed? Disable the option of changing values} } \value{ Ratings to be added to UI definition diff --git a/tests/testthat/test-shinyRatings.R b/tests/testthat/test-shinyRatings.R index 21da980..7f892f7 100644 --- a/tests/testthat/test-shinyRatings.R +++ b/tests/testthat/test-shinyRatings.R @@ -1,9 +1,19 @@ test_that("shinyRatings works", { expect_s3_class(shinyRatings('star'), 'shiny.tag') + expect_s3_class(shinyRatings("star", no_of_stars = 5, default = 4), 'shiny.tag') + expect_s3_class(shinyRatings("star", no_of_stars = 5, disabled = TRUE), 'shiny.tag') }) test_that("ratings_html works", { - res <- ratings_html() + res <- ratings_html(5, disabled = FALSE) expect_type(res, 'character') expect_s3_class(htmltools::HTML(res), 'html') }) + + +test_that("shinyRatings returns error", { + expect_error(shinyRatings("star", default = 10), "default value can be greater than 0 and less than `no_of_stars`") + expect_error(shinyRatings("star", no_of_stars = 5.86), "no_of_stars can be a whole number or a number ending with .5") + expect_error(shinyRatings("star", default = 5.86), "default value can be a whole number or a number ending with .5") + expect_error(shinyRatings("star", disabled = 5.86), "disabled can take only logical values") +})