I am replacing a server side solution that allowed a master application page to fire headless window that talk to the originating page.
Now I am doing it in SPO with SPFx and so far I just used one page and web part with a big dialog that can't get out of the sending page.
My users want to be able to put the dialog on the second monitor so I think I have to do it in a different window / web part. I am planning a version 2.0 and collection ideas how to do it.
So far I think I will use "broadcast-channel" for communicating between the parent page/web part and the child page/web part.
I still need to figure out the following:
How to create a sharepoint page containing just a SPFx web part without all the side and top bla bla. (safe to hide by CSS?)
How to pass the spfxContext from parent to child
how to debug 2 separate SPFx projects at the same time while building the solution.
Any suggestion is welcomed. Samples even more 😘
Thank you in advance.
Try to use an extension:
export default class CssInjectApplicationCustomizer
extends BaseApplicationCustomizer<ICssInjectApplicationCustomizerProperties> {
#override
public onInit(): Promise<void> {
const cssUrl: string = '/SiteAssets/inject.css';
const head: any = document.getElementsByTagName("head")[0] || document.documentElement;
let customStyle: HTMLLinkElement = document.createElement("link");
customStyle.href = cssUrl;
customStyle.rel = "stylesheet";
customStyle.type = "text/css";
head.insertAdjacentElement("beforeEnd", customStyle);
return Promise.resolve();
}
}
inject.css:
/* Hide header */
#SuiteNavPlaceHolder, .od-SuiteNav{
display:none !Important;
}
/** Hide options header **/
div[class^="sideActionsWrapper-"],
.sideActionsWrapper-53 .ms-searchux-searchbox {
display: none;
}
/** Hide header lists**/
.CanvasSection .ms-DetailsList-headerWrapper,
.CanvasSection div[class^="itemsViewDetailsListCommandBar_"]{
display: none;
}
/** Hide Header page **/
div[class^="detailsListContainer_"],
.ControlZoneEmphasisBackground,
.root-63,
.root-76{
background-color:transparent;
}
I have a view with a grid from where I launch a different view in a new window. The parent view needs to pass data to the child view and it cannot be passed as a query string since it is pretty large. I cannot use a native modal. I am just using window.open and have not created a custom modal context.Things that I have tried
1. Tried populating hidden field elements in the new window using something like the code below
var popup = window.open('/#/viewname');
popup.onload=function(){document.findbyid('hiddenfield')= newvalue };
I am using a splash page to display loading in durandal , onload of the new window the router is still navigating and I get the splash page document
2. Tried requiring the parent view in the child view and then grabbing the parent view data using something like the code below
define(['viewmodels/parent'],function ('parent'){
function activate(){
localvariablevalue= parent.observable;
}
return{
activate:activate
}
});
I get parent.observable as undefined. More than likely it is out of context as this is a new window.
3.Tried a singleton global.js file and requiring it in both parent and child but I think that is also losing context as I get undefined even with that approach
Any ideas on how to achieve this.. if it can be achieved using v 1.2 ? If it can be achieved by creating a custom Modal context then can someone give some pointers on how to define the addContext function for a new window .
By using window.open an independent instance of a #/viewname SPA gets created that has no relation to the first SPA. If you really have to open a new window than you'd need to look into other ways to exchange information between windows like e.g. localstorage.
But you're probably better off rethinking the requirements and see if you can't achieve the goal with modals instead.
Edit based on comment: That has nothing to do with Durandal loosing context, it's about window.open not opening in the same session. see e.g. window.open doesn't open in same session
Edit2 As an alternative you might use the param #/viewname in the second windows vm.activate to retrieve the data either from the server directly (if applicable) or via webstorage e.g. localstorage or sessionstorage from the first browser.
Edit3 I did a quick test do see if that can be accomplished using window.open alone. Tested in Firefox/Firebug. I would still recommend to checkout the links to webstorage to ensure that this is working cross browser.
Go to http://dfiddle.github.io/dFiddle-1.2/#/, open up a console and create a global var:
window.myVar = {complex: true};
create a new window
var myWindow = window.open('http://dfiddle.github.io/dFiddle-1.2/#/view-composition');
go back first console and create a property myvar on myWindow
myWindow.myVar = myVar;
change to the console of the second window and check
myVar // output {complex: true}
The alternative that I was suggesting uses the unique hash value that you pass in to the second window and then either retrieves the complex data (that can be added as query string) as part of the activate callback. The data could be stored on the server or via webstorage.
Rainer thanks for trying to help out. The following code will generate maximised modals. At this stage I am resigning to this solution and passing my data as activation in showModal. It is an exact copy of the default modal context with minor css variations.But posting it if it helps someone out.
1. CSS
.modalHostMax {
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
position: fixed;
opacity: 0;
-webkit-backface-visibility: hidden;
-webkit-transition: opacity 0.1s linear;
-moz-transition: opacity 0.1s linear;
-o-transition: opacity 0.1s linear;
transition: opacity 0.1s linear;
}
.modalMax {
width: 100%;
height: 100%;
}
2.New modal context
var addContext = function (contextName) {
modalDialog.addContext(contextName, {
blockoutOpacity: .2,
removeDelay: 200,
addHost: function (modal) {
var body = $('body');
var blockout = $('<div class="modalBlockout"></div>')
.css({ 'z-index': modalDialog.getNextZIndex(), 'opacity': this.blockoutOpacity })
.appendTo(body);
var host = $('<div class="modalHostMax"></div>')
.css({ 'z-index': modalDialog.getNextZIndex() })
.appendTo(body);
modal.host = host.get(0);
modal.blockout = blockout.get(0);
if (!modalDialog.isModalOpen()) {
modal.oldBodyMarginRight = $("body").css("margin-right");
var html = $("html");
var oldBodyOuterWidth = body.outerWidth(true);
var oldScrollTop = html.scrollTop();
$("html").css("overflow-y", "hidden");
var newBodyOuterWidth = $("body").outerWidth(true);
body.css("margin-right", (newBodyOuterWidth - oldBodyOuterWidth + parseInt(modal.oldBodyMarginRight)) + "px");
html.scrollTop(oldScrollTop); // necessary for Firefox
$("#simplemodal-overlay").css("width", newBodyOuterWidth + "px");
}
},
removeHost: function (modal) {
$(modal.host).css('opacity', 0);
$(modal.blockout).css('opacity', 0);
setTimeout(function () {
$(modal.host).remove();
$(modal.blockout).remove();
}, this.removeDelay);
if (!modalDialog.isModalOpen()) {
var html = $("html");
var oldScrollTop = html.scrollTop(); // necessary for Firefox.
html.css("overflow-y", "").scrollTop(oldScrollTop);
$("body").css("margin-right", modal.oldBodyMarginRight);
}
},
afterCompose: function (parent, newChild, settings) {
var $child = $(newChild);
var width = $child.width();
var height = $child.height();
$child.attr('class', 'modalMax');
$(settings.model.modal.host).css('opacity', 1);
if ($(newChild).hasClass('autoclose')) {
$(settings.model.modal.blockout).click(function () {
settings.model.modal.close();
});
}
$('.autofocus', newChild).each(function () {
$(this).focus();
});
}
});
};
3. In your target view make sure that the container min-height is set to $(document).height()
4. To use just set custom context by calling addContext('yourcontextname').Then create your modal - app.showModal('viewname',{data},'yourcontextname')
How can I add a phone number to a website that is clickable but hides the link when I'm browsing on a website that doesn't support touch.
I could use Modernizr to set it up although. I don't know how.
<p><img src="assets/images/bt_calltoaction.gif" alt="View Projects" width="306" height="60"></p>
Could you just have the code in twice? i.e...
<div class="desktoptel">0800 000 000</div>
<div class="mobiletel"><a href="tel:0800-000-000">0800-000-000</div>
Then just 'display:none;' on the relevant class depending on your browser sizes?
I was just dealing with this issue, looking up solutions, and I found this thread (and a few others). I have to confess that I couldn't get any of them to work properly. I'm sure I was doing something wrong, BUT I did figure out a cheat.
As others have pointed out, changing the CSS to hide the visible link indication (color, text-decoration, cursor) is the first and easiest step. The cheat is to define a title for the tel link.
<p>Just call us at <a class="cssclassname" href="tel:18005555555"
title="CLICK TO DIAL - Mobile Only">(800) 555-5555</a>.</p>
By doing this, not only is the visible indicator of a link disguised (via CSS - see examples from others), but if someone does hover over the link, the title will pop up and say "CLICK TO DIAL - Mobile Only". That way, not only is there a better user experience, but your client doesn't accuse you of having a broken link!
For me the easiest, yet simplest method without any new classes / setup is via css:
a{
color: #3399ff;
}
a[href^="tel"]:link,
a[href^="tel"]:visited,
a[href^="tel"]:hover {
text-decoration: none;
color: #000;
pointer-events: none;
cursor: default;
}
/* Adjust px here (1024px for tablets maybe) */
#media only screen and (max-device-width: 480px) {
a[href^="tel"]:link,
a[href^="tel"]:visited,
a[href^="tel"]:hover {
text-decoration: underline;
color: #3399ff;
pointer-events: auto;
cursor: pointer;
}
}
Html just goes like this:
(+12)3 456 7
This works for modern browsers & IE 11+. If you need to include 8 < IE < 11 add the following to your javascript, since pointer-events dont work in IE:
var msie = window.navigator.userAgent.indexOf("MSIE ");
if (msie > 0){
var Elems = [], Tags = document.querySelectorAll("a[href^='tel']");
//Nodelist to array, so we're able to manipulate the elements
for (var i = 0; i < Tags.length; i++ ) {
Elems[ i ] = Tags[ i ];
}
for(var i = 0; i < Elems.length; i++){
Elems[ i ].removeAttribute('href');
}
}
EDIT: i found another answer on another thread, that may be useful for you - SO - Answer
I recently had this same problem. This problem is all over stackoverflow and everywhere else. How do you hide 'tel:' prefix and keep it from blowing up in regular browsers. There's no good single answer.
I ended up doing it this way:
first I use metalanguage to filter browser vs mobile (like php/coldfusion/perl) based on useragent string:
regular exp match for "/Android|webOS|iPhone|iPad|BlackBerry/i",CGI.HTTP_USER_AGENT
that gives me an if/else condition for desktop browser vs phone.
Next, my href tag looks like this: <a class="tel" id='tel:8005551212' href=''>800-555-1212</a>
Use CSS to style the .tel class in desktop stylesheet so it doesn't look like a link to desktop browsers. the phone number can still be clicked but its not obvious, and it wont do anything:
/* this is in default stylesheet, styles.css: */
.tel{
text-decoration:none;
color: #000;
cursor:default;
}
/* it should be re-styled in mobile css: */
.tel{
text-decoration: underline;
color: #0000CC;
cursor:auto;
}
Finally, I do a little jquery on the mobile links. The jQuery gets the id from the a.tel class, and inserts it into the href property, which makes it clickable for phone users.
The whole thing looks like this:
<!-- get regular CSS -->
<link rel="stylesheet" href="styles/styles.css" type="text/css" media="Screen" />
<!-- get user agent in meta language. and do if/else on result.
i'm not going to write that part here, other than pseudocode: -->
if( device is mobile ) {
<!-- load mobile CSS -->
<link rel="stylesheet" href="styles/mobile.css" type="text/css" media="handheld" />
<!-- run jQuery manipulation -->
<script>
$(function(){$('a.tel').prop('href',$('a.tel').prop('id'));});
</script>
}
<p> Call us today at <a class="tel" id='tel:8005551212' href=''>800-555-1212</a>!</p>
One caveat to this approach: id's should be unique. If you have duplicate phone numbers on a page that you want to link, change the id to name, then you use jQuery to loop through them.
You could use css media queries to control when its viewed as link and when not.
#media(min-width:768px){
a[href^="tel:"] {
pointer-events: none;
}
}
anything below 768px will work as link, above that, just as text.
if you just wanted to disable the click on the mobile screens:
if(typeof window.orientation !== 'undefined'){
$('a[href^="tel:"]').on('click', function(e){
e.preventDefaults();
});
}
Hope this helps :)
I've had success with this using Modernizr, specifically the touch test. It's not a perfect solution in that it doesn't do anything to help tablets or touch-enabled laptops, but it works in most desktop browsing situations.
HTML:
Call us at: 1-800-BOLOGNA
CSS:
.no-touch a.call-us {
color: black; /* use default text color */
pointer-events: none; /* prevents click event */
cursor: text; /* use text highlight cursor*/
}
The above CSS targets links with class="call-us" on non-touch devices which covers the majority of desktops.
Note that pointer-events is supported in all modern browsers but IE only supports it in versions 11+. See the compatibility chart.
Another solution, still imperfect, would be to use Modernizr.mq along with Modernizr.touch to detect screen width and touch capability and then inject the phone link with jQuery. This solution keeps the phone link out of the source code and then only appears on touch devices smaller than a certain width (say 720px which will probably cover most phones but exclude most tablets).
Ultimately, it's up to the browser vendors to come up with a bulletproof solution here.
I found the best way. I get that this is old, but I found a very easy way of doing this.
Using this code below
888-555-5555
//This is the logic you will add to the media query
.not-active {
pointer-events: none;
cursor: default;
}
In your CSS make use of media queries.
So make a media query for all desktops
#media only screen and (min-width: 64em) {
/* add the code */
.not-active {
pointer-events: none;
cursor: default;
}
}
Now all desktop sized pages wont be able to click on it.
it seems this could be done with a simple media query for most browsers. Something like this is working like a charm for me:
<style type="text/css">
#mobil-tel {
display:none;
}
#media (max-width: 700px) {
#mobil-tel {
display:block;
}
#desktop-tel{
display:none;
}
}
</style>
and on the desktop link, leave out the 'href', on the mobile link, put in the 'href'.
Just thought I would add my two-cents worth to (what is turning out to be a rather lengthy) discussion.
I basically use the onClick event (on the link) to execute Javascript to return a boolean true or false. If the return value is true, i.e. some variable or function that tests if the device is a phone returns a value true, then the href URL is followed by the browser. If the the return value is false, then the href URL becomes, in effect, inactive. (Standard HTML behavior, way before HTML5.)
Here is what I mean:-
<html>
<head>
<title>tel markup example</title>
<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script> <!-- Does not really matter what version of jQuery you use -->
<script>
var probablyPhone = ((/iphone|android|ie|blackberry|fennec/).test(navigator.userAgent.toLowerCase()) && 'ontouchstart' in document.documentElement);
function initialize() {
if ( !probablyPhone ) {
alert ("Your device is probably not a phone");
( function( $ ) {
$( '.call' ).css ( "text-decoration", "none" );
$( '.call' ).css ( "color", "black" );
$( '.call' ).css ( "cursor", "default" );
} )( jQuery );
}
}
</script>
</head>
<body onLoad="initialize();">
Please ring (some fictitious number in Australia): +61 3 9111 2222
</body>
</html>
Note that I also added some re-formatting of the link to make it appear to the user as if it's just ordinary text.
Here is a gist I created.
Just to finish this post/ answer, credit for writing succinct JavaScipt code for detecting a phone (based on the user agent and the ontouchstart event) goes to a fellow Melbournian rgb in this stackoverflow post
Here is a simple jquery-based solution which I developed to solve this problem. See code comments for explanation.
https://jsfiddle.net/az96o8Ly/
// Use event delegation, to catch clicks on links that may be added by javascript at any time.
jQuery(document.documentElement).on('click', '[href^="tel:"]', function(e){
try{
// These user-agents probably support making calls natively.
if( /Android|webOS|iPhone|iPad|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
// Do nothing; This device probably supports making phone calls natively...
} else {
// Extract the phone number.
var phoneNumber = jQuery(this).attr('href').replace('tel:', '').trim();
// Tell the user to call it.
alert("Please call "+phoneNumber);
// Prevent the browser popup about unknown protocol tel:
e.preventDefault();
e.stopPropagation();
}
} catch(e){
console.log("Exception when catching telephone call click!", e);
}
});
My approach is similar to another approach above; there are a few considerations I take into account:
As we know, there is no good programmatic way to detect support. This is a rare case where we are forced to parse the UserAgent string.
This should be client side; there is no need for server side detection.
There are now desktop browsers that can handle tel: links; Chrome's behavior on the desktop is, at worst, to do nothing when clicked. At best, you can make a call with Google Voice.
Because doing nothing when clicked is Chrome's fallback behavior, we should use that behavior as a fallback on all browsers.
If your page takes responsibility for creating tel: links, it should take responsibility for all tel: links and disable autodetection in the browser.
With all of this in mind, I suggest first adding a meta tag to your <head>:
<meta name="format-detection" content="telephone=no"/>
Then, define a JavaScript function that parses the UserAgent and returns true if and only if we think the browser will not bring us to an error page when the link is clicked:
function hasTelSupport()
{
return /Chrome\/|Mobile( Safari)?\/|Opera M(in|ob)i\/|w(eb)?OSBrowser\/|Mobile\;|Tablet\;/.test(navigator.userAgent);
}
Then, call that function from the onclick attribute in your link:
Call Me
This will allow tel: links to be clicked on Chrome, Edge, iOS Safari, Android Browser, Blackberry, Dorothy, Firefox Mobile, IE Mobile, Opera Mini, Opera Mobile, and webOS. The links will do nothing when clicked on other devices or browsers.
Please use international format for your tel: links. In other words, the first characters should be a + and a country code.
Thanks to TattyFromMelbourne's post I am now using a pretty simple bit:
My button id="call" will make the phone call based on his "probablyphone" test function but also will scroll down to the contact info section either way giving the button a working use no matter what.
I aslo replaced the alert with an empty function, to remove the pop-up.
<a id="call" href="#contact">PHONE US</a>
$("#call").on('click', function() {
var probablyPhone = ((/iphone|android|ie|blackberry|fennec/).test(navigator.userAgent.toLowerCase()) && 'ontouchstart' in document.documentElement);
var link = "callto:15555555555";
if ( !probablyPhone ) {
window.alert = function() {};}
else{window.location.href = link;}
});
</script>
You can use css3 media queries to detect a mobile window and hide the link accordingly.
#media(max-width:640px){
.your-calling-link{
display:none;
}
}
Alternately, if you want to show the link and just disable click functionality, use jquery function:
screen.width
or
screen.innerWidth
and disable the click functionality on the link using
$('.your-link').off(click);
One way of handling this is to create two separate divs and use display:hidden.
Example:
<div class="mobile-desktop"><p>123-456-7890</p></div>
<div class="mobile-mobile">123-456-7890</div>
In your css set your mobile break points. This part is really up to you. Let's say
#media only screen (min-width: 768px){
.mobile-mobile {
display:none;
}
}
#media only screen (max-width: 767px){
.mobile-desktop{
display:none;
}
}
This should let you hide one div based on screen size. Granted 789 is just a number I picked, so pick a size you believe is mobile. You can find them online at like this site I found on Google or others like it. Lastly, this is just a quick css markup, you might have to tinker but the idea is there.
This way works without adding any more CSS.
Try replacing the a tag with something else like a span tag, but only for mobile browsers of course. Benefits are that you are not cloaking this a with CSS preventing default action while keeping it still as a link. It won't be a anymore, so you won't have to worry.
I've created an example to here. Bold phone there works this way, see code below.
I took piece of code from one of the respondent to define if browser is mobile. And you have to mark these links with class="tel" or find a way to determine if the href has "tel:" in it. JQuery is also required.
// define if browser is mobile, usually I use Anthony's Hand mobile detection library, but here is simple detection for clarity
var probablyPhone = ((/iphone|android|ie|blackberry|fennec/).test(navigator.userAgent.toLowerCase()) && 'ontouchstart' in document.documentElement);
if ( !probablyPhone ) {
// find all the A with "tel:" in it, by class name
$('a.tel').each(function(){
var span = document.createElement('span');
// SPAN inherits properties of A, you can also add STYLE or TITLE or whatever
span.innerHTML = this.innerHTML;
span.className = this.className;
// replace A with SPAN
this.parentNode.insertBefore(span, this);
this.parentNode.removeChild(this);
});
}
Input this into custom css and call it a day:
a.tel { color: #FFFFFF; cursor: default; /* no hand pointer */ }
Change your color as needed.
Cheers!
I am adding the following css through javascript when mobile device is detected.
pointer-events:none
The js code is:
var a = document.getElementById("phone-number");
if (Platform.isMobile()) // my own mobile detection function
a.href = "tel:+1.212.555.1212";
else
$(a).css( "pointer-events", "none" );
In my target site, all phone link markups are in this pattern:
111-222-3333. My solution is such simple:
function setPhoneLink() {
if (screen.width > 640) {
$("a[href^='tel:']").each(function(){
$(this).replaceWith($(this).text());
});
}
}
Device-width: mobile<640; tablet >=768 and <1024; desk >=1024.
Source: http://javascriptkit.com/dhtmltutors/cssmediaqueries2.shtml
Don't use the screen size as a requirement for that.
You can use CSS media query like this:
#media (pointer: fine) { /* this is for devices using a mouse, maybe a pen */
a[href^="tel:"] { /* select only "tel:" links */
pointer-events: none; /* avoid clicks on this element */
}
}
#media (pointer: coarse) { /* this works for mobile phones */
}
More info: https://developer.mozilla.org/en-US/docs/Web/CSS/#media/pointer
#media screen {.telephone {pointer-events: none;}}