CopyPastor

Detecting plagiarism made easy.

Score: 0.8018841743469238; Reported for: String similarity Open both answers

Possible Plagiarism

Reposted on 2022-05-14
by Kat

Original Post

Original - Posted on 2022-04-23
by Kat



            
Present in both answers; Present only in the new answer; Present only in the old answer;

Here's what I've got:
* save with custom name * retrieve by name * retrieve by radio button * delete by button
You may want to adjust the size or position of the radio button container. It depends on how you use it. Right now the container will continue to grow (up to a point) as you add more content.
This still uses the file or webpage name, so if you have more than one spreadsheet, you'll be able to save and keep the configurations separated.
The YAML, options, CSS, libraries, and sample data.
--- title: "testing rpivotTable cookie-ishness" author: "me" date: '2022-05-12' output: html_document ---
```{r setup, include=FALSE} knitr::opts_chunk$set(echo = FALSE) ```
<style> body { /*push content away from far right and left edges*/ margin-right: 2%; margin-left: 2%; } .main-container { max-width: unset; } .btn { /*Added other buttons*/ vertical-align: middle; -moz-box-shadow: 0px 10px 14px -7px #000000; -webkit-box-shadow: 0px 10px 14px -7px #000000; box-shadow: 0px 10px 14px -7px #000000; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; border: .5px solid black; display: inline-block; font-size: 1.15em; /*Changed from 1.3em*/ padding: .3em 0px; width: 20em; /*Changed from 18em*/ text-decoration: none; /*no underline!!*/ cursor: pointer; } .btn:active { /*simulate movement; added other buttons*/ position: relative; top: 1px; } </style>
```{r data,include=F} # devtools::install_github("fraupflaume/rpivotTable") library(rpivotTable) library(tidyverse) data(mtcars) ```
The buttons (not radio) and `rpivotTable`.

## Make it Interesting...or not Do you want to save or restore the previously saved pivot tables' configuration? <a id='saveNamed' class='btn' style="background-color:#003b70;color:white;">Save Configuration by Name</a> <a id='restoNamed' class='btn' style="background-color:#b21e29;color:white;">Restore Configuration with Custom Name</a> <a id='remoSaved' class='btn' style="background-color:black;color:white;">Remove Saved Configuration</a> ```{r showMe, echo=FALSE, fig.show="hold"} rpivotTable(mtcars, rows="am", cols = c("cyl"), width = "90%", height = "40%", subtotals = TRUE, rendererOptions = list( c3 = list(legend = list(show = FALSE), data = list(labels = TRUE), options = list(responsive = TRUE, maintainAspectRatio = FALSE), size = list(width = "600", height = "500")), d3 = list(size = list(width = "500", height = "500")) )) ```
The remaining code is Javascript. This creates the events, saves, retrieves, and deletes configurations, and creates the radio buttons.
```{r listenOrElse,results="asis",engine="js"} // for ONE TABLE setTimeout(function(){ // add to buttons radioStar(); // <= added in v3 document.querySelector('a#saveNamed').addEventListener('click', savoring); document.querySelector('a#restoNamed').addEventListener('click', giveItBack); document.querySelector('a#remoSaved').addEventListener('click', remIt); // removing configs function savoring() { // function to save el = document.querySelector('.rpivotTable'); msg = "Choose a name for the configuration that you are saving."; inName = prompt(msg, ['Enter a name with no spaces or special characters']) if(inName === null) {return;}; // they changed their mind; nothing saved inName = inName.replace(/[^a-z0-9.]/gi, ''); // validate string path = window.location.pathname.split("/").pop().split(".").slice()[0]; //filename elId = el.getAttribute("id"); stringy = $('#' + elId).data("pivotUIOptions"); // collect rows/col filters delete stringy['aggregators']; // remove not-parse-friendly keys delete stringy['renderers']; stringy2 = JSON.stringify(stringy); // one key:value pair for storage window.localStorage.setItem(path + '_' + inName, stringy2); // STORE it! radBuilder(inName); // <= added in v3; mod v4; add radio btn for new saved name }; function giveItBack() { // function to regurgitate //el = document.querySelector('.rpivotTable'); msg = "Enter the name of the configuration you would like to retrieve."; confName = prompt(msg, ["Enter a name with no spaces or special characters"]); if(confName === null) {return;}; confName = confName.replace(/[^a-z0-9.]/gi, ''); // validate string retriever(confName); } function retriever(confName) { // <= added in v3 console.log("I'm listening! I swear!"); el = document.querySelector('.rpivotTable'); ods = [...el.ownerDocument.scripts]; // make it an array path = window.location.pathname.split("/").pop().split(".").slice()[0]; //filename elId = el.getAttribute("id"); where = ods.filter(function(ods){ // filter scripts for data return ods.dataset['for'] === elId; })[0].innerHTML; where2 = JSON.parse(where).x.data; // format data for pivotUI() where3 = HTMLWidgets.dataframeToD3(where2); // ...still formatting if(window.localStorage.getItem(path + '_' + confName) === null) { // alert len = window.localStorage.length var str; for(i = 0; i < len; i++) { w = window.localStorage.key(i); w2 = w.split("_").pop(); // remove file/page name <= changed in v3 str = str + w2 + '\n'; // make one long string of names } str2 = "WARNING: There is no saved pivot table configuration with the name " + confName + '.'; str2 += " Here is a list of the configuration names that are currently stored for this page:\n"; str2 += str; alert(str2); // next step is a change in v3 giveItBack(); // when unmatched name is chosen instead of re-prompting send them back } gimme = window.localStorage.getItem(path + '_' + confName); // get storage gimmeMore = JSON.parse(gimme); // prepare for recall if(where.includes('"subtotals":true')){ // is the option 'subtotal' used? gimmeMore.renderers = $.pivotUtilities.subtotal_renderers; gimmeMore.dataClass = $.pivotUtilities.SubtotalPivotData; }; if(where.includes('"tsv":true')){ // is the option 'tsv' used? gimmeMore.renderers = $.extend(gimmeMore.renderers, $.pivotUtilities.export_renderers); }; if(where.includes('sortAs')){ // passed as a function, they will get lost in save & retrieve stringy = $('#' + elId).data("pivotUIOptions").sorters; gimmeMore.sorters = stringy; }; $('#' + elId).pivotUI(where3, gimmeMore, true, "en"); // put it back! } function remIt(){ el = document.querySelector('.rpivotTable'); msg = "Identify the configuration for removal."; remName = prompt(msg, ['Enter a name with no spaces or special characters']) if(remName === null) {return;}; // they changed their mind; nothing saved remName = remName.replace(/[^a-z0-9.]/gi, ''); // validate string path = window.location.pathname.split("/").pop().split(".").slice()[0]; //filename window.localStorage.removeItem(path + '_' + remName); rgetter = document.querySelector('#' + remName).parentNode; rgetter.remove(); } function radioStar() { // create container *once*; size may have to be adjusted if(document.querySelector('#radIsland') == null) { // if an alert doesn't exist // one time = create island for radio buttons contLabel = document.createElement('div'); contLabel.setAttribute( 'style', 'font-size: 1.2em; font-face: bold; color: #003b70; display: flex; flex-flow: wrap row;'); contLabel.textContent = 'Choose from the available check points:'; configCont = document.createElement('div'); configCont.id = 'radIsland'; configCont.setAttribute( 'style', 'border: 1px solid #003b70; min-width: 11em; width: auto; max-width: 55em; min-height: 10em; height: auto; border-radius: .5em; color: #003b70; display: flex; flex-flow: wrap row;' ); pEl = document.querySelector('.rpivotTable').parentNode; pEl.prepend(configCont); // but box above rpivottable pEl.prepend(contLabel); // put the label on top } radCreation(); } function radCreation(){ // if island exists then move on // create radio buttons; when savoring runs, radio buttons need to be rebuilt/validated? var wk, rB, rLab, desc, newL, rCont, path, len; path = window.location.pathname.split("/").pop().split(".").slice()[0]; //filename len = window.localStorage.length for(i = 0; i < len; i++) { wk = window.localStorage.key(i); ind = wk.lastIndexOf('_'); wkFile = wk.substr(0, ind); // remove file/page name and table number chName = wk.split("_").pop(); // user chosen name if(wkFile === path) { // only show radio if file names match radBuilder(chName); } } } function radBuilder(chName){ console.log('building a button'); rB = document.createElement('input'); rB.type = 'radio'; rB.name = 'rBtn'; // only one radio w/ same name can be selected at once rB.id = chName; // id's have to be unique for rad groups rB.value = chName; rB.setAttribute( 'style', 'margin: 2px;'); rB.addEventListener('click', function(){ retriever(this.value) }); rLab = document.createElement('label'); rLab.htmlFor = chName; desc = document.createTextNode(chName); rLab.appendChild(desc); newL = document.createElement('br'); fItem = document.createElement('div'); fItem.setAttribute( 'style', 'width: 10em; height: 1.1em; margin: auto;'); fItem.appendChild(rB); fItem.appendChild(rLab); fItem.appendChild(newL); rCont = document.getElementById('radIsland'); rCont.appendChild(fItem); } }, 500); ```
[![enter image description here][1]][1] [![enter image description here][2]][2] [![enter image description here][3]][3] [![enter image description here][4]][4]
### If you remove a configuration, the radio button goes away, as well. [![enter image description here][5]][5] [![enter image description here][6]][6]

### Saving a configuration will add a radio button for that configuration at that time
[![enter image description here][7]][7] [![enter image description here][8]][8]
### You can add as many configurations as you would like.
[![enter image description here][9]][9]
### Just select a new radio to change to a different configuration.
[![enter image description here][10]][10]

[1]: https://i.stack.imgur.com/FKYMu.png [2]: https://i.stack.imgur.com/k9y37.png [3]: https://i.stack.imgur.com/EAu2l.png [4]: https://i.stack.imgur.com/OfFYI.png [5]: https://i.stack.imgur.com/BziNl.png [6]: https://i.stack.imgur.com/fLy6v.png [7]: https://i.stack.imgur.com/25uPp.png [8]: https://i.stack.imgur.com/hdrAy.png [9]: https://i.stack.imgur.com/20lRo.png [10]: https://i.stack.imgur.com/XUmxk.png
This one took a while. I used local storage. I've got a lot of styling here, but it's unnecessary. I used the output of `flexdashboard`, since that tends to cause me the most problems with JS.
<style> body { /*push content away from far right and left edges*/ margin-right: 2%; margin-left: 2%; } .rpivotTable { overflow:auto; resize: both; box-shadow: 0 22px 70px 4px rgba(0,0,0,0.56); -moz-box-shadow: 0 22px 70px 4px rgba(0,0,0,0.56); -webkit-box-shadow: 0 22px 70px 4px rgba(0,0,0,0.56); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; border: 1px solid white; padding: 5px; margin: 5px 20px 50px 5px; } .btn { vertical-align: middle; -moz-box-shadow: 0px 10px 14px -7px #000000; -webkit-box-shadow: 0px 10px 14px -7px #000000; box-shadow: 0px 10px 14px -7px #000000; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; border: .5px solid black; display: inline-block; font-size: 1.3em; padding: .3em 0px; width: 18em; text-decoration: none; /*no underline!!*/ cursor: pointer; } .btn:active { /*simulate movement*/ position: relative; top: 1px; } </style>
I've used the content that I've found in other questions.
## R Markdown <div style="margin-right:5%;"> `r stringi::stri_rand_lipsum(10)` </div> ```{r cars} library(rpivotTable) data(mtcars) names(mtcars)[10] <- "George.Dontas" ``` Here is the **first** Div. ## Including Plots Do you want to save or restore the previously saved pivot tables' configuration? <a id='saveBtn' class='btn' style="background-color:#003b70;color:white;">Save Current Configuration</a> <a id='restoBtn' class='btn' style="background-color:#b21e29;color:white;">Restore Previous Configuration</a> ```{r pressure, echo=FALSE, fig.show="hold"} rpivotTable(mtcars,rows="George.Dontas", cols=c("cyl","carb"),width="100%", height="400px") ``` ```{r morePressure, echo=FALSE, fig.show="hold"} rpivotTable(mtcars,rows="George.Dontas", cols=c("cyl","carb"),width="100%", height="400px") ``` This should be a different aspect of the report. ```{r evenMorePressure, echo=FALSE, fig.show="hold"} rpivotTable(mtcars,rows="George.Dontas", cols=c("cyl","carb"),width="100%", height="400px") ```
Here is the JS/JQuery...it's a bit ugly and a rather unseemly hodgepodge of the two (JS/JQuery).
```{r listenOrElse,results="as-is",engine="js"} // save current state of the tables to my browser setTimeout(function(){ //add the events first document.querySelector('a#saveBtn').addEventListener('click', savoring); document.querySelector('a#restoBtn').addEventListener('click', giveItBack); function savoring() { // function to save el = document.querySelectorAll('.rpivotTable'); for(i=0; i < el.length; i++){ elId = el[i].getAttribute("id"); stringy = $('#' + elId).data("pivotUIOptions"); // collect rows/columns filters delete stringy['aggregators']; // remove the arbitrary delete stringy['renderers']; stringy2 = JSON.stringify(stringy); // make it one key:value window.localStorage.setItem('table' + i, stringy2); // store it! } }; function giveItBack() { // function to regurgitate el = document.querySelectorAll('.rpivotTable'); console.log("working on the giver"); ods = [...el[0].ownerDocument.scripts]; // make it an array for(j=0; j < el.length; j++){ elId = el[j].getAttribute("id"); where = ods.filter(function(ods){ // filter scripts for table data return ods.dataset['for'] === elId; })[0].innerHTML; where2 = JSON.parse(where).x.data; // WOOO HOO! I figured it out!! where3 = HTMLWidgets.dataframeToD3(where2); // finally sheesh!! gimme = window.localStorage.getItem('table' + j); // get storage $('#' + elId).pivotUI(where3, JSON.parse(gimme), true, "en"); // put it back! } } },100); ```
[![enter image description here][1]][1]
--- ---
### Update
Thanks for pointing out some opportunities for improvement, @George Dontas. This update changes how the configuration is saved. I'm sure there are still ways to improve it, though.
This update adds the file or webpage name as part of the key-value pair used to store the information. Now, both the name of the webpage/script and table number need to match for the tables to update. Additionally, this will alert the user when a configuration cannot be restored. This alert would occur if there is nothing saved and if there is no file name and table matching configuration saved.
#### Updates to Saving the Configuration
There is one new line and one modified line of code in `savoring()`.
New:
path = window.location.pathname.split("/").pop().split(".").slice()[0]; //f name
Modified:
window.localStorage.setItem(path + '_table' + i, stringy2); // store it
The entire function with changes:
function savoring() { // function to save el = document.querySelectorAll('.rpivotTable'); path = window.location.pathname.split("/").pop().split(".").slice()[0]; for(i=0; i < el.length; i++){ elId = el[i].getAttribute("id"); stringy = $('#' + elId).data("pivotUIOptions"); // collect filters delete stringy['aggregators']; // remove the arbitrary delete stringy['renderers']; stringy2 = JSON.stringify(stringy); // make it one key:value window.localStorage.setItem(path + '_table' + i, stringy2); // store it } };

#### Updates to Restoring the Configuration
There are few new lines in this function. The name has to be collected, as in the `savoring()` changes. Additionally, this function now has an alert for the user.
>I started out with the basic system alert, but it wasn't up to snuff for my tastes, so I also developed a custom alert box. I've included both here.

##### Basic Alert and Updated Configuration Retrieval
The only thing that changes from my original answer to making a basic alert are the following lines of code within the `giveItBack()` function:
path = window.location.pathname.split("/").pop().split(".").slice()[0]; //f name
and
if(window.localStorage.getItem(path + '_table' + j) === null) { jj = j + 1; alert("WARNING: There is no saved pivot table configuration for " + path + "'s table " + jj + "."); continue; // don't update, go to next table (if more than 1) }

Here is the complete `giveItBack()` function (note that `notice(msg)` and `msg` are here, but commented out):
function giveItBack() { // function to regurgitate el = document.querySelectorAll('.rpivotTable'); console.log("working on the giver"); ods = [...el[0].ownerDocument.scripts]; // make it an array path = window.location.pathname.split("/").pop().split(".").slice()[0]; //name for(j=0; j < el.length; j++){ elId = el[j].getAttribute("id"); where = ods.filter(function(ods){ // filter scripts data return ods.dataset['for'] === elId; })[0].innerHTML; where2 = JSON.parse(where).x.data; // WOOO HOO! I figured it out!! where3 = HTMLWidgets.dataframeToD3(where2); // finally formatted // is there a saved configuration that matches this file and table? if(window.localStorage.getItem(path + '_table' + j) === null) { jj = j + 1; //this is for the standard alert box alert("WARNING: There is no saved pivot table configuration for " + path + "'s table " + jj + "."); //msg = "<b>WARNING</b><br><br>There is no saved pivot table configuration for<br>" + path + "." //notice(msg); //this is for the custom alert box continue; // go to next loop } gimme = window.localStorage.getItem(path + '_table' + j); // get storage $('#' + elId).pivotUI(where3, JSON.parse(gimme), true, "en"); // put it back! } };
<kbd>
[![enter image description here][2]][2]
</kbd>


##### Custom Alert and Updated Configuration Retrieval
If you choose to use a more custom approach to the alert message, there is a lot more (luckily, it should be copy and paste). You will use the `giveItBack` function from the updates for the basic alert, but comment out or delete `alert(...` and uncomment `msg` and `notice()`.
>For the CSS in my original answer, update the styles for `.btn` to `.btn, #noted` and `.btn:active` to `btn:active, #noted:active`.
This is the remaining CSS for the custom alert. You can add this CSS to the other style tags or keep them separated.
<style> #notice-wrapper { width: 100%; position: fixed; top: 0; left: 0; z-index: 1000000; background: transparent; display: none; transition: opacity 1s ease-in; } #notice-box { -moz-box-shadow: 0px 10px 14px -7px #000000; -webkit-box-shadow: 0px 10px 14px -7px #000000; box-shadow: 0px 10px 14px -7px #000000; border-radius: 4px; border: .5px solid black; width = 300px; background: #003b70; color: white; min-height: 200px; position: absolute; top: 50%; left: 50%; margin: -100px 0 0 -150px; } #notHead { text-align: center; font-size: 1.3em; padding: 4px; margin: 2.5em; font-family: Verdana, sans-serif; } #noted { background: #b21e29; margin: .5em; width: 120px; font-family: Verdana, sans-serif; } </style>
The JS for the custom alert box is next. I placed this function within the `setTimeout(function(){` with `savoring()` and `giveItBack()`.
function notice(msg) { function cr() { if(document.querySelector('#notice-wrapper') === null) { wrapper = document.createElement('div'); wrapper.id = 'notice-wrapper'; html = "<div id='notice-box'><h2 id='notHead'></h2><div id='noticeBtns'>"; html += "<button id='noted'>OK</button></div></div>"; wrapper.innerHTML = html; document.body.appendChild(wrapper); } insta = document.querySelector('#notice-wrapper'); placer(insta); return(insta); } function placer(insta) { wrapper = insta; winHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientheight; wrapper.style.height = winHeight + "px"; } function showy(el) { el.style.display = "block"; el.style.opacity = 1; } function goAway(el) { el.style.opacity = 0; setTimeout(function(){ el.style.display = "none"; }, 1000); } function takeAction(msg) { insta = cr(); insta.querySelector('#notHead').innerHTML = msg; showy(insta); insta.querySelector('#noted').addEventListener('click', function() { goAway(insta); }, false); } takeAction(msg); }
Of course, with this custom option, you have the opportunity to style it as you see fit. Style control isn't an option with the system alert messaging system.
[![enter image description here][3]][3]

[1]: https://i.stack.imgur.com/ntDfD.png [2]: https://i.stack.imgur.com/jBguY.png [3]: https://i.stack.imgur.com/ByJyx.png

        
Present in both answers; Present only in the new answer; Present only in the old answer;