Custom landing page for SaaS application - css

I am building a SaaS based web application, to which users can connect using their own domain and apply their company branding to it.
How can I customize the landing page of my application based on domain from which it is being accessed. There is no login information to identify the customer.
Thanks.

On your landing page, you can fetch request url and then customize the response accordingly.
You didn't mention the programming language, however in Java we can use ((HttpServletRequest)request).getRequestURL().toString() to get it.
Recently for one of my projects I used a third party service - www.grooveui.com, it does something similar but without you having to write server side code.

You can try to put in your iframe such code:
<script>
var wantedUrl = (window.location != window.parent.location)
? document.referrer
: document.location.href;
var wantedUrlEsc = escape(wantedUrl);
var newEl = document.createElement('script');
newEl.src = "https://your.server.com?wantedUrlEsc=" + wantedUrlEsc;
document.getElementsByTagName('head')[0].appendChild(newEl);
// or document.head.appendChild(newEl) in modern browsers
</script>
and on server side you can try read and decode the wantedUrlEsc parameter.
Good luck!

Related

Alternative to iframe for microservices ui composition

I'm currently integrating multiple microservices ui into a web portal. I have a navigation sidebar with link to microservices which will be loaded into an iframe in the central area.
I have lot of issue with iframe (security with frame option header, window sizing, etc...)
Do you know about a better alternative to an iframe?
If your micro services have a REST API available, you can use an embeded javascript code instead of iframe. Your embed code would look something like:
<div id="embed_id"></div>
<script type="text/javascript">
(function(){
var embededJavascriptElement = document.createElement("script");
embededJavascriptElement.type = "text/javascript";
embededJavascriptElement.charset= "utf-8";
embededJavascriptElement.id = "embed_script";
embededJavascriptElement.src = "<path to your script>";
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body") [0]).appendChild(embededJavascriptElement);
})();
</script>
The script above will insert another script tag into your DOM. That script will be interpreted, will search for the element with id ="embed_id" and will render the embeded code into that div (you need to implement this behavior).
You already tagged your question accordingly with spring-cloud and Zuul. I'd suggest this is exactly the way to go cause this way you can avoid the browsers sandbox as well as to manage CORS headers on your services. Just use start.spring.io and include Zuul as a requirement and define your rules. I suggest you start with static routes and if you then are familiar and confident with Zuul, embed a service registry and discovery like Eureka, consul or etcd.

Need to include a helper html page in my meteor project

I have a helper.html page that I need to include in my Meteor app to assist with using an api. Looks like this.
<head>
<script type="text/javascript" src="https://www.example.com/api-helper.js"> </script>
</head>
<body>
</body>
Right now I just have it in the root directory of my app. As it is now, here are the problems: the other api script which I have included in main.html, can't find the helper.html. Second, I get this error in the console: Error: Oh no! No route found for path: "/helper.html?. So my question is how do I properly include this helper html page into my Meteor project? Help greatly appreciated.
Thanks
Just put your html file into a folder called public in the root folder.
Error: Oh no! No route found for path: "/helper.html"
This is an error from iron:router, it's complaining that it can't find any route for path "helper.html".
I suppose you get this error message when typing directly http://localhost:3000/helper.html in your browser address bar, which is WRONG because this is not how iron:router is supposed to work.
iron:router manages pure client-side routing using HTML5 push state API contrary to classic server-side routing involved when requesting "/helper.html" to Apache or nginx means the server is going to send you an actual HTML response page displayed by the browser.
In Meteor "single-page apps", the server does not send any HTML responses to the client, it only sends data. It means that the routing takes place entirely in the client, the URL in the address bar gets parsed and iron:router provides utilities to respond accordingly, which usually involves rendering a different template based on which path (route) you hit.
I hope you really understand the difference in nature between these two approaches because this is very important to be aware of when developing with Meteor.
As far as your problem is concerned, I'll take DISQUS integration as an example which seems to be a similar issue.
DISQUS integration on standard PHP solutions is straightforward, you just need to copy-paste this so-called universal embed code :
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = '<example>'; // Required - Replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the comments powered by Disqus.</noscript>
blog comments powered by <span class="logo-disqus">Disqus</span>
This is fine because once a page gets sent to the client in a traditional website, javascript code gets executed once and we are done : if the user click on another page on the website, the all process of generating the HTML response, sending it to the client and executing JS code will be started from scratch.
However we can't just copy-paste this code inside a Meteor template, because Meteor webapps are "single-page apps", no page reloading process should ever happen in these type of websites.
When we navigate to another page in a Meteor app, the javascript context stays the same and we don't want the DISQUS script to reexecute. What we need to do instead is loading the script only once in the rendered callback of our template.
So we come up with the following Meteor template logic to integrate DISQUS comments loading :
<template name="disqus">
<div id="disqus_thread"></div>
<a href="http://disqus.com" class="dsq-brlink">
blog comments powered by <span class="logo-disqus">Disqus</span>
</a>
</template>
Template.disqus.rendered=function(){
// assumes we get identifier and title as data context
var identifier=this.data.identifier;
var title=this.data.title;
// we need a way to tell if the script has already been loaded or if it's
// the first time, we can check for the existence of the DISQUS variable on
// the global window object to make the difference
if(window.DISQUS){
// DISQUS API has our back, see this resource
// https://help.disqus.com/customer/portal/articles/472107-using-disqus-on-ajax-sites
window.DISQUS.reset({
reload:true,
config:function(){
this.page.identifier=identifier;
this.page.title=title;
}
});
}
else{
// first initialization
window.disqus_shortname = "disqus-shortname";
window.disqus_identifier = identifier;
window.disqus_title = title;
window.disqus_developer = 1;
// load the script via JS instead of embedding it in the HTML
var script = $("<script>",{
type:"text/javascript",
async:true,
src:"//" + disqus_shortname + ".disqus.com/embed.js"
});
$("head").append(script);
}
};
This example demonstrates the way to go when you need to embed API code (google-analytics, DISQUS, etc...) in a Meteor website.

Cross domain iFrame - cookie is not transferred

we have a website with our application running in an iFrame on multiple domains and subdomains. The main website (www.example.com) has only static content with links to the sites with framed application sites. So sub.example.com, sub2.example.com, search.another.com have all iFrame with the application running.
We'd like to track all these sites with Google Analytics (GA). Subdomain tracking is working fine but I couldn't find a way to make the cross domain work accurately. The main issue is I cannot share the visitor cookie information among the top level domains. So, the same visitor who goes to sub.example.com and search.another.com get 2 different cookies, which result in various issues. (e.g. inflated visitor counter, cannot correctly track referral info, etc)
Can you please help me fix this?
(I've done a pretty thorough search on the web, tried several scenarios but no luck so far)
Here is the core of our GA implementation:
on sub.example.com (and all subdomains of the main website)
_gaq.push(['b._setAccount', 'UA-XXX']);
_gaq.push(['b._setDomainName', 'example.com']);
_gaq.push(['b._setAllowLinker', true]);
_gaq.push(['b._addIgnoredRef', 'example.com']);
_gaq.push(['b._addIgnoredRef', 'search.another.com']);
_gaq.push(['b._trackPageview']);
on search.another.com (all external subdomains have variants)
_gaq.push(['b._setAccount', 'UA-XXX']);
_gaq.push(['b._setDomainName', 'search.another.com']);
_gaq.push(['b._setAllowLinker', true]);
_gaq.push(['b._addIgnoredRef', 'example.com']);
_gaq.push(['b._addIgnoredRef', 'search.another.com']);
_gaq.push(['b._trackPageview']);
just after iframe on all pages
<script type="text/javascript">
_gaq.push(function ()
{
var iFrameTracker = _gat._getTrackerByName('b');
var iframe = document.getElementById('myframe');
iframe.src = iFrameTracker._getLinkerUrl(iframe.src);
});
</script>
on the link on www.example.com
<a href="http://search.another.com" onClick="_gaq.push(function ()
{
var tracker = _gat._getTrackerByName('b');
var linkerUrl = tracker._getLinkerUrl('http://search.another.com');
});">
linkerUrl has the correct Url with the cookie of www.example.com. But for some weird reason, GA assigns a new cookie on the search.another.com. I tried setting the domain name to none (['b._setDomainName', 'none']), which didn't help. I'm not sure if I'm missing a simple fundamental point here. I guess the issue might be related to having cross domain iFrames and the links can be either in the iFrame or in the frameset. So I want to track both.
I do the debugging with the Chrome GA Debugger addon.
(Btw, theoretically we can have infinite number of top-level / sub domains. So manually creating filters for each domain on GA is not an option. )
You're simply assigning the linkerUrl to a variable. You need to redirect the user to that url instead.
You should return false on the onClick handler to keep the browser from doing the usual redirect.
<a href="http://search.another.com" onClick="_gaq.push(function ()
{
var tracker = _gat._getTrackerByName('b');
var linkerUrl = tracker._getLinkerUrl('http://search.another.com');
window.location.href = linkerUrl;
});return false;">
Alternatively you should be using _link. Which does pretty much the same thing.
<a href="http://search.another.com"
onClick="_gaq.push(['b._link', this.href]);return false;">

How can I apply GA download tracking with Sitecore?

I'm posting this question to Stackflow b/c after doing much research into an answer to this very question online, I did not come across a straight forward answer and had to do my own sleuthwork to resolve this.
Basically, Sitecore uses a handler file .ASHX for all files uploaded to the Media Library. Since the 3rd party GA tracking tool I was using (entourage.js or gatags.js) does not recognize .ashx as a whitelisted download file, it was not adding the appropriate GA tracking syntax to the GA pixel tracker (__utm.gif).
So the solution turns out to be simple but sadly, not retroactive, meaning all files previously uploaded to the Media Library in the Sitecore content tree will continue to use the ashx extension unless you reupload the image. In your web.config file, search for the "Media.RequestExtension" setting. If you change the value associated with this setting from "ashx" to a blank string, this will force Sitecore to use the originalextension of the file and image in the Sitecore Media Library.
Aside from interfering with GA analytics, this method of turning every downloadable file extension into an ashx file is poor SEO practice. AND, Sitecore will not point you in the right direction of getting around this other than a round-about way (google Sitecore dynamic linking and configuration) because they want you to use their Sitecore OMS download tracking capability. And that's it! Two days of research led me to this conclusion.
So the solution turns out to be simple but sadly, not retroactive,
meaning all files previously uploaded to the Media Library in the
Sitecore content tree will continue to use the ashx extension unless
you reupload the image.
Not sure where you got this information, but it's incorrect. You can blank out the Media.RequestExtension setting and all existing files will use their original extension. In IIS7 Integrated Mode, you should be able to make this change without having to make other server configuration changes.
Edit: More Info
If you analyze Sitecore.Configuration.Settings.Media.RequestExtension (the API equivalent to this settings) in a decompiler, you can see that it's only used by the MediaProvider when constructing the Media URL. Sitecore should remember the original extension of the media and can serve it with its original URL, regardless of what this setting was when it was uploaded. That's my experience, anyway, and it seems to be validated by looking into Sitecore.Kernel.
You could use this script to track download events via Google Analytics.
if (typeof jQuery != 'undefined') {
jQuery(document).ready(function($) {
var filetypes = /\.(zip|pdf|doc*|xls*|ppt*|jpg|ashx)$/i;
var baseHref = '';
if (jQuery('base').attr('href') != undefined) baseHref = jQuery('base').attr('href');
jQuery('a').each(function() {
var href = jQuery(this).attr('href');
if (href) {
if (href.indexOf('?') != '-1') {
href = href.substring(0, href.indexOf('?'));
}
if (href.match(filetypes)) {
jQuery(this).click(function() {
var extension = String((/[.]/.exec(href)) ? /[^.]+$/.exec(href) : undefined);
var filePath = String(href);
_gaq.push(['_trackEvent', 'Download', extension, filePath]);
if (jQuery(this).attr('target') != undefined && jQuery(this).attr('target').toLowerCase() != '_blank') {
setTimeout(function() {
location.href = baseHref + href;
}, 200);
return false;
}
});
}
}
});
});
}
Just add in the required file types here at this line -
var filetypes = /.(zip|pdf|doc*|xls*|ppt*|jpg|ashx)$/i;
Having done a quick google for gatags.js, I can see that you can add an extension to the whitelist on line 24:
var isDoc = path.match(/\.(?:doc|eps|jpg|png|svg|xls|ppt|pdf|xls|zip|txt|vsd|vxd|js|css|rar|exe|wma|mov|avi|wmv|mp3)($|\&|\?)/);
Change it to:
var isDoc = path.match(/\.(?:ashx|doc|eps|jpg|png|svg|xls|ppt|pdf|xls|zip|txt|vsd|vxd|js|css|rar|exe|wma|mov|avi|wmv|mp3)($|\&|\?)/);
Alternatively, you could attach the Google Analytics _trackEvent yourself with a dom selector and a click event.
Either way, I think OMS can track media library files regardless of extension - removing the default ashx extension doesn't stop the file being handled by Sitecore.

How to include HTML contents from another site? I have access to both sites

I have a site which is using DNN (DotNetNuke) as a content management system. I am using another site for my event registrations. I have sent them my template; which displays the basics including a hover menu with many different items in it.
Issue is - as I update the menu on my site using DNN, I need it to be reflected on the site using my template - without me having to send them a new file. Anyone have suggetsions on how to approach this?
I don't want to send the events provider all of the DNN DLLs as well as my database login information in order to render the menu.
I created a page on my site that is something like 'menu.aspx' - this produces the menu in HTML format, however it has tags like in it that I'd like to remove before serving it to them.
What is the best approach for this? Do I need to write a custom server control using XMLHttp? Can I accomplish this in Javascript?
Any advice much appreciated.
Thank you!
If both sites are hosted on the same domain (eg site1.domain.com and site2.domain.com) you can use JavaScript and XmlHttpRequest to insert code from one site to another. Otherwise, the Same Origin Policy prevents you from using AJAX.
If they're not on the same domain but you have access to the page on their website, you can simply include there a JS script from your site :
<script type="text/javascript" src="http://yoursite.com/code.js"></script>
In the JS, simply document.write() what you want on the page. This way, you can easily change the content of the page on their site without having to send them a new file.
Finally, you can also use an iframe on their site, pointing to a page on yours.
EDIT: As Vincent E. pointed out, this will only work if they're on the same domain - my bad.
If you are unwilling or unable to use frames, then I would set up an ashx on your DNN server which renders the menu (if you've got it in a user control all the better, as you can just instatiate it and Render it directly to the output stream) and then just make an Ajax call to that from your events page and insert it directly into the DOM.
Here's a quick and hacky jquery-based example of the events page end of things:
<script type="text/javascript">
function RenderMenu(data)
{
$('#Menu').html(data);
}
$(document).ready(function() {
$.ajax({
type : 'GET',
url : 'http://localhost/AjaxHandlers/Menu.ashx',
data : '',
success : RenderMenu,
});
});
</script>
You'll want an empty div with the ID 'Menu' on the page where you want your menu to sit, but apart from that you're good to go.
If for whatever reason you can't get the menu HTML in an isolated way, then you'll need to do some text processing in RenderMenu, but it's still do-able.
I am not a web expert, so don't shoot me.
Can't you just put their registration form into an iFrame in DNN ?

Resources