[Shiny]: Add link to another tabPanel in another tabPanel - html

I'm trying to put a link on my "home" tabPanel to all others tabPanels of my app.
The idea is as follows:
ui = navbarPage("",
tabPanel("home",
fluidPage(
fluidRow(box("this 1st box should lead me to tab1a")),
fluidRow(box("this 2nd box should lead me to tab1b")),
fluidRow(box("this 2nd box should lead me to tab2")))
),
navbarMenu("tab1",
tabPanel("tab1a"),
tabPanel("tab1b")),
tabPanel("tab2")
)
shinyApp(ui, server=function(input, output) {})
I've seen the answer in Add link panel tabs in Shiny with various top level navigation bars, but I couldn't implement it on my code, since it deals with html (which i've never worked before, so I'm not familiar with the functions etc) and the code considers tabPanels within the same tab (not sure if that's why it didn't work here, if maybe it didn't work because the tabs I'm trying to link are on a navbarPage or something).
Can anyone help me or tell me where i could learn how to implement this on my example?

This answer is purely JavaScripted, but very minimal, I guess. Since Shiny creates tabs with random number Ids, and does not give access to the Ids it used, this has do be done client-sided. But there is no knowledge of JavaScript needed to implement this to other scenarios. The JavaScript part is just for Copy/Paste and the trigger command is easy to understand.
What did I do? I installed a function, that finds the Navbar link corresponding to the desired tab, and just clicks it. This utility can be added to any element with the "onclick" attribute. There are no special tags (e.g. no "a" tag) required.
The code below should make it easy to customize this solution to fit your needs.
Note: I used the original Code with the box, although it does not have any visual effect.
Code:
library(shiny)
library(shinydashboard)
ui = shinyUI(
navbarPage("Header",
tabPanel("home",
tags$head(tags$script(HTML('
var fakeClick = function(tabName) {
var dropdownList = document.getElementsByTagName("a");
for (var i = 0; i < dropdownList.length; i++) {
var link = dropdownList[i];
if(link.getAttribute("data-value") == tabName) {
link.click();
};
}
};
'))),
fluidPage(
fluidRow(box("this 1st box should lead me to tab1a", onclick = "fakeClick('tab1a')")),
fluidRow(box("this 2nd box should lead me to tab1b", onclick = "fakeClick('tab1b')")),
fluidRow(box("this 2nd box should lead me to tab2", onclick = "fakeClick('tab2')"))
)
),
navbarMenu("tab1",
tabPanel("tab1a", "Some Text inside Tab 1a."),
tabPanel("tab1b", "Some Text inside Tab 1b.")
),
tabPanel("tab2", "Some Text inside Tab 2.")
)
)
server = function(input, output, session){}
runApp(shinyApp(ui, server), launch.browser = TRUE)
Have fun!

Related

Add external hyperlink to tabPanel or navbarMenu in r Shiny

I am trying to add external hyperlinks to the tabPabel and navbarMenu tabs/dropdowns in a navbarPage setup in Shiny (using bootstrapPage). I found multiple questions that refer to linking to another tab within a Shiny app, but I want to specifically link to another webpage without opening a new browser window.
I found the following questions that kind of get there:
How to direct to another web page after clicking tabPanel in Shiny App
Open URL by tabPanel in Shiny
The second question is what I want to do; however, when I use the following method to accomplish this, it adds a "phantom" tab:
tabPanel(a("Open Sales Gsheet", href="http://google.com", target="_blank"))
Here is some example code for the Shiny app setup that I am working with:
library(shiny); library(shinythemes)
ui <- bootstrapPage("",
navbarPage(
id = "navbar",
theme = shinytheme("yeti"),
title = a("Home", href = "https://google.com", style = "color:white;"), ## page title with hyperlink and browser tab title (works as intended)
tabPanel(title = HTML("Panel_1</a></li><li><a href='http://google.com' target='_blank'>test")), ## tabPanel hyperlink test (adds "phantom" tab)
navbarMenu(title = "Test Menu",
tabPanel(title = a("Open Sales Gsheet", href="http://google.com", target="_blank")) ## navbarMenu hyperlink test (adds "phantom" option)
)
)
)
server <- function(input, output, session) {
## empty server
}
shinyApp(ui, server)
Here is a screenshot of the "phantom" tab issue:
https://i.imgur.com/tIYbhzT.png
As you can see, both the tabPanel and navbarMenu tabs/dropdowns have additional "phantom" tabs that have been added as a result. The first question I posted above shows an answer that involves editing the html code (or the list that is produced in R)... but I cannot figure out how to do this with a tabPanel or navbarMenu object.
I just want this to look like a normal navbarPage dropdown where the tabPanel and navbarMenu selections link to an external site (in the same browser window - browseURL as an observeEvent in the server script does not work since it opens in another window). Any help would be appreciated!
It's tricky to add custom elements in a shiny navbar page but it can be done with some javascript. The following code should add your link to the dropdown menu in the navbar. Save it as a .js file in your app's base directory then include the script in your ui function.
navAppend.js in your app's base directory:
$(document).ready(function() {
$(".navbar .container-fluid .navbar-nav .dropdown .dropdown-menu").append('<li>Open Sales Gsheet</li>');
});
in your ui:
ui <- tagList(
tags$head(includeScript("navAppend.js")),
navbarPage(
id = "navbar",
theme = shinytheme("yeti"),
title = a("Home", href = "https://google.com", style = "color:white;"), ## page title with hyperlink and browser tab title (works as intended)
# nav menu the link will be added to
navbarMenu(title = "Test Menu")
)
)

Is there a way to search for searchable text in <map...><area ... title="searchable text" /></map> and <img alt="searchable text" />?

Using Ctrl-F in most browsers will allow you to search for text, but only in only the text areas. I would like to search for text in what should be accessible areas that are not necessarily text rendered areas such as <map ...><area title="searchable text" /></map> and <img alt="searchable text" />. Is there a browser or addon that will do what I'm asking for? This stuff is here for accessibility, but it doesn't seem to be really all that accessible (except by mouse hover, which again isn't all that accessible).
NOTE
An answer that is required, does not use something that is decoupled from the view. I.e. searching through the source code isn't an option as this is largely difficult to read (esp on complex pages) and doesn't show where the information is located on the rendered page.
Is there a browser or addon that will do what I'm asking for?
Oh yes. Lynx browser does it.
But I guess it's not a solution ;-)
If your question is so, there is no way to override what CTRL+F is doing in your browser.
You can design a custom plugin inside your website, or an addon for your browser. This would be quite easy... but will require other shortcut.
If your main problem is to locate tags based on their alt or title attributes content, this is quite easy in javascript:
var search='enter image';
var nodes=document.querySelectorAll("[alt*='"+search+"'],[title*='"+search+"']");
You can then highlight the matching nodes using jquery or what you want.
for (i in nodes) {
nodes[i].className+=' resultHighlighted';
}
and scroll to the first result:
nodes[0].scrollIntoView();
If you intend to create a browser plugin, you can create your custom a bookmarklet or a custom plugin, and associate a shortcut to this bookmark (see https://github.com/iSunilSV/Chrome-Bookmark-Shortcut)
A simple bookmarklet to find the first match by title or alt attribute and scroll to it will be something like that:
javascript:text=prompt("search inside alt or title attribute");
document.querySelector("[alt*='"+text+"'],[title*='"+text+"']").scrollIntoView();
In your browser, use the "View Source" or "Source Code" function, and then within that window that pops up, use the Ctrl-F for Find.
You can also use the "Inspect Element" directly on an element to split the screen into two windows- one for code and one that's rendered.
For more information, here's a sample article for Chrome:
https://support.google.com/adsense/answer/181951?hl=en
Would something like the Web Developer browser plugin work? It's available for Chrome, FF and Opera. There are a few features that toggle the display of various attributes such as title, alt and even ARIA roles. This injects the attribute text inline with the element.
In my opinion, it's not a bug; they were just not designed for this use.
As I'm sure you are aware, the alt attribute replaces the image when it's not available. So how could you scroll to something that is not always displayed? Whereas you seem to be after a permanent description; a figcaption would be more appropriate for this.
As for the title attribute, it was intended to merely clarify the purpose of a link. There should not be any new information to the user in the title; therefore I think it would be redundant to have two lots of the same information highlighted in one place.
The purpose of searching is to find text on screen, seeing as neither title or alt are always displayed I think the user would be more confused by the fact that nothing is highlighted, and that they are just taken to an image or random link/area. If the image has a figcaption that becomes highlighted, then it would make sense to them. Besides, how are they going to search for the title if they don't know what to search for? Title and alt do not come up in text displayed by search engines; the user will never know about it unless they've been to your site before, in which case they'll know where to look.
Also you state the following:
This stuff is here for accessibility, but it doesn't seem to be really all that accessible
Which, understandably, seems true to you as you probably do not need it. However alt and title are read out to those who use screen readers so isn't entirely useless.
Idea 1
I assume you have Windows and Firefox installed
I have my Firefox installed with 2 add-ons.
Install a add-on called Tile Tabs, it make it possible for example left side is web view and the same page on right side with source code.
Install add-on called Web page to source code & viceversa that make it possible to toggle between view and source code by pressing on CTRL+SHIFT+S
Since what you required is not a default thing in all nowadays browses as far as I know.
Screen shot of the solution:
Idea 2
Install FireBug, you can view/edit/debug source codes and view HTML live and what you highlight on the code will be also highlighted on the view.
Screen shot:
Note: Btw idea 1 is not only good for view / source code but it is also good to compare two views or read article to the right and answer question to the left.
You can use the search funktion in Chrome's developer tools "Elements" Tab (Press F12 -> Tab "Elements" -> Press CTRL + F) and use XPath on your searches. Example:
//*[#title="Google"]
Matches will be shown with a yellow background in the code and when you hover it, its position will be hightlited in the view.
Dev Tools "Element" Search with XPath
It is coupled with the view, allows you to see the element's position and it's also an out-of-the-box solution in Chrome (tested in Chromium 45 for Ubuntu).
Hope it helps!
Regards
EDIT
Forgot - If you want to use wildcards on your searches, you can also do it like this:
//*[contains(#title, 'Google')]
EDIT 2
For the posterity! Further research shows that your goal might be possible to achieve using the Firefox-Addon Greasemonkey, which allows you to customize the way a web page displays or behaves, by using small bits of JavaScript.
I performed several tests with this addon and could achieve a nice effect with simple images (display the ALT attribute as a DIV overlapping the image), but with area sections the thing gets a lot more complicated, as area regions can be squares, circles, and polygons with infinite coordinates plus retrieving the exact positioning of the area itself can be a bit tricky but maybe gives you or someone else a start point.
Based on the ALT Tooltips Script (http://greasemonkey-user-scripts.arantius.com/alt-tooltips-for-firefox), I created the following script and defined it in Greasemonkey:
// ==UserScript==
// #name Alt Tooltips 2
// #namespace http://www.biterion.com
// #description Alt Tooltips 2
// #include *
// #grant all
// ==/UserScript==
function getPosition(element) {
var xPosition = 0;
var yPosition = 0;
while(element) {
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition };
}
function getAreaPosition(element) {
var position = element.coords.split(',');
xPosition = position[0];
yPosition = position[1];
return { x: xPosition, y: yPosition}
}
var res = document.evaluate("//img",document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
var i, el;
for (i=0; el=res.snapshotItem(i); i++) {
if(el.alt) {
alternate = el.alt
} else {
alternate = "No alt text";
}
position = getPosition(el);
var newDIV = document.createElement ('div');
newDIV.innerHTML = "<div style='position:absolute;background:yellow;color:black;top:" + position["y"] + ";left:" + position["x"] + "' id=" + i + ">" + alternate + "</div>";
document.body.appendChild(newDIV);
}
var res2 = document.evaluate("//area",document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
var i2, el2;
for (i2=0; el2=res2.snapshotItem(i2); i2++) {
if(el2.alt) {
alternate2 = el2.alt
} else {
alternate2 = "No alt text";
}
position2 = getAreaPosition(el2);
var newDIV2 = document.createElement('div');
newDIV2.innerHTML = "<div style='position:absolute;background:yellow;color:black;top:" + position2["y"] + ";left:" + position2["x"] + "' id=" + i2 + ">" + alternate2 + "</div>";
document.body.appendChild(newDIV2);
}
As you can see, the script firstly detects all "img" and "area" elements, extracts its positioning and creates a new DIV element containing the "alt" attribute, which is then positioned on the upper left corner of the image.
As stated, the problem with areas is, that the positioning should be relative to the parent image and not absolute like in the script, plus the coordinates should be extracted accordingly to the type of area shape (currently only extracting the two first coordinates of each area, which will work for squares but will surely fail for other shapes).
Hope this will help someone :-D
Regards

How do I link to mid-page content that's already inside a mid-page link?

I'm making a page that has 4 in-page tabs on it. To link to those tabs, the URL is
URL/#tab-1-tab; URL/#tab-2-tab etc
Now, in one of the tabs I want to have buttons that link to specific points on a page inside another tab, but not sure if it's actually possible to link to.
I've made the anchors on that page with
<a name="1"></a>
But I can't figure out how to link to them. I tried
URL/#tab-4-tab/#1 and URL/#tab-4-tab#1
Not sure what else to try. The links do work if I go to the tab with the anchors, then erase the tab url bit and just put in the anchor link, so instead of
URL/#tab-4-tab, I type in URL/#1
Then it jumps to the right point.
But that doesn't work if I'm on any other tab or page.
Is it possible to do this somehow?
If your using tabs to switch div CSS properties like display:none / display:block then you will need some jQuery / JavaScript to switch them based of URL no differently then your jQuery that listens for the tabs "onclick" event then shows that relative div.
First step would be to obtain a JavaScript URL reader that listens for variables or hashtag-bookmarks. Here is an example of a variable reader I have used before.
http://jsfiddle.net/googabeast/hhkuj/
function getUrlVars() {
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
vars[key] = value;
});
return vars;
}
//usage
var myVar = getUrlVars()["tab"];
That would make the URL format slightly different then your above posting, something more like "index.php?tab=2" / "index.php?tab=3" etc...
Next phase would be generate a switch based off the incoming URL variables to properly show the requested div.

How do I select a tab and set content of the tabpanel in JavaScript

I'm stuck at this: I've created tabs and corresponding tabpanels. By default, I've hidden the tabs. To make a tab visible, I use this JavaScript line:
document.getElementById("tab-id").setAttribute("selected", true);
However, the content of the corresponding tabpanel does not update as I expected. I've tried using this:
document.getElementById("tabbox-id").selectedPanel = "tabpanel-id";
But nothing is happening; the content of the tabpanel is not updated.
Any assistance will be highly appreciated.
The selected attribute is set internally, it is merely an indicator that selection changed - changing it won't actually change selection. What you most likely want to do is this:
var tabpanel = document.getElementById("tabpanel-id");
document.getElementById("tabbox-id").selectedPanel = tabpanel;
Note that selectedPanel is the panel and not its ID. Alternatively you could also use selectedIndex:
document.getElementById("tabbox-id").selectedIndex = 1;
Documentation

How to export all relevant HTML/CSS for one element

I'm sure this question is out there but I cannot find it:
Is there a tool that can get one element of my HTML document and export that element, all its parents and all its associated CSS but nothing else?
EDIT:
Sorry I was not clear enough. I don't mean that I want Firebug/DevTools, I mean a tool [that maybe a feature of some kind of in-browser] that outputs all the relevant HTML/CSS for the selected element into a self contained file / to the clipboard.
EDIT2:
When I say outputs all relevent HTML/CSS I mean that I want that element and all it's css rules, and then each parent element with their css rules all the way up to . What I would get as an output would be enough HTML/CSS to open as a standalone page and have the target element rendered and effected by all relevant CSS rules.
Yes, there is a tool/s and ways to do that.
First, with Chrome extension, you can install SnappySnippet from Chrome Web Store. It allows easy HTML+CSS extraction from the specified (last inspected) DOM node. Additionally, you can send your code straight to CodePen or JSFiddle.
Second, CSS Used, other Chrome extension, for extracting CSS with children CSSs.
And third, without extension, if you want CSS embedded in HTML or above extensions is not working for you, you can use any Webkit based browser (like Chrome or Firefox) to run script in console which will add all css to html element and you can easily just copy OuterHTML and it will work anywhere.
var el = document.querySelector(“#yourId”); // change yourId to id of your element, or you can write “body” and it will convert all document
var els = el.getElementsByTagName("*");
for(var i = -1, l = els.length; ++i < l;){
els[i].setAttribute("style", window.getComputedStyle(els[i]).cssText);
}
So, just copy this code to Console (Right click on page->Inspect->Console), change yourid to yourid or set it to "body", run it and then right click on your element and "copy outerHTML"
Do you mean something like Firebug ( Firefox addon )? Or the Debug bar in Chrome ( Press F12 in the browser )?
In Chrome:
Press F12
Click on the loop in the bottom left.
Click on the element
Now you can see all the style.
In the big window you can see other element, and the element under
it.
In chrome, you can right click the page, and then select "inspect element" to view the html code of the page (but in the browser). Then, right click on the element that you want to export, and select "copy as html". Paste it into whatever editor you like. Hope this helps.
Press F12 or right click and go "inspect element" then select element to get the HTML code for the current webpage. Once at that point click the magnifying glass to the left and click on an element of the page using that, that will show you the code used for that specific element, after that you can right click and select "Copy Html" or you can go "Edit as Html" and then copy the code.
You can try to use a tool like Site Sucker for this. I've used it to grab entire websites, but there are settings available that might limit to what you're looking for.
Great question - it was alive and kicking for me today :-)!
Building on the accepted answer (thank you for that!) and this answer, I've got:
var el = document.querySelector("#question > div.post-layout > div.postcell.post-layout--right > div.s-prose.js-post-body"); // change yourId to id of your element, or you can write “body” and it will convert all document
var els = el.getElementsByTagName("*");
for(var i = -1, l = els.length; ++i < l;){
el = els[i]
s = getComputedStyle(el)
for (let styleKey in el.style) {
for (let computedStyleKey in s) {
let computedStyleKeyCamelCase = computedStyleKey.replace(/\-([a-z])/g, v => v[1].toUpperCase());
if ((typeof el.style[styleKey] != "function") && (styleKey != 'cssText')){
if(styleKey == computedStyleKeyCamelCase) {
el.style[styleKey] = s[computedStyleKey];
}
}
}
}
}
P.S.:
The above code should run in the Developer Tools (F12) console (tried it in Chrome) and it will add the inline style to each element
After running you could right click and do Copy / OuterHTML