Here is the situation:
I have a webservice that returns a form.
This form is then used by many other sites in an iFrame element.
I need the form to "wear" the hosting site's background, color, or in other words CSS (but i will settle for background and logo if this is easier).
My webservice and the other sites are not on the same domain.
I have full control over my webservice and i can define general requirements for all sites.
What is the best way to handle this?
There are several ways to accomplish this:
1 - Pass in a stylesheet as a parameter into the iframe:
Pass in a CSS stylesheet as a query parameter in the src attribute of the iframe. This is perhaps the easiest method, and it gives the owner of that stylesheet more control over how the form looks on that person's site.
<body>
<!-- This is the client's website -->
<!-- This is your form -->
<iframe src="http://example.com/form/abc/?css=http://example.com/file/formStyle.css" />
2 - Pass in the color and logo into the iframe:
This is the same basic idea as in the first example, except you're not referencing an external stylesheet:
<iframe
src="http://example.com/form/abc/?color=#AAAAAA&logo=http://example.com/logo.png" />
3 - Use PostMessage:
Another option is to use the postMessage API. With postMessage, you can pass a message from one context to another, across domains. Thus, the client page could pass the background color to the iframe page, and this could be reused to pass other types of information and data as well.
Iframe code:
// register to listen for postMessage events
window.addEventListener("message", changeBackground, false);
// this is the callback handler to process the event
function changeBackground(event)
{
// make sure the code you put on the client's site is secure. You are responsible
// for making sure only YOU have cross domain access to his/her site.
// NOTE: example.org:8080 is the client's site
if (event.origin !== "http://example.org:8080")
return;
// event.data could contain "#AAAAAA" for instance
document.body.style.backgroundColor = event.data;
// do other stuff
}
}
Top Level Client Page:
// pass the string "#AAAAAA" to the iframe page, where the changeBackground
// function will change the color
// targetOrigin is the URL of the client's site
document.getElementById("theIframe").contentWindow.postMessage("#AAAAAA", targetOrigin);
This solution only works in modern browsers, including IE8, FF3.6+, Chrome 13+, Safari 5+, etc. See the Mozilla Developer Center for more information on HTML5 postMessage.
How to pull the CSS parameter from the query string?
Use the gup function in the iframe page to get the value of the CSS parameter:
function gup(name) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(window.location.href);
if (results == null)
return "";
else
return results[1];
}
Afterwards, you can then use it to create a link CSS tag:
// get url parameter from iframe src:
var cssPath = gup("cssPath");
// create link and append to head
var linkElem = document.createElement("link");
linkElem.setAttribute("href", cssPath);
linkElem.setAttribute("rel","stylesheet");
document.getElementsByTagName("head")[0].appendChild(link);
OR
var color = gup("color");
document.body.setAttribute("style","background-color:" + color);
Related
I am using django with django-channels and htmx.
In certain cases, my django views will send an SSE event to a user subscribed to the relevant channel, like a notification for example. Some of those events (depending on event name) needs to trigger a modal pop-up (like a rating modal after an e-commerce order or service completes).
I have implemented the requirements of the server-side event and data generation. I want to use the htmx sse extension on the frontend (django template).
My problem is, I want to get an event, let's say order_complete, and use that to trigger an hx-get call to a particular url which will be sent by the sse event. That hx-get's response will then be placed in the placeholder where modal view logic exists. I can get the event and trigger the get request as described in the htmx sse extension docs, but I don't know how to get the url to put in the hx-get.
I have very little knowledge of JavaScript and not all that much more on htmx. I've looked at out of band swaps but I'm not sure if that's what I need.
I'd appreciate any opinion or suggestions for proceeding including a non-htmx solution if it's better performing or easier.
Thank you.
You can append parameters to a (fixed) url.
In a client side javascript handle the sseMessage event.
document.body.addEventListener('htmx:sseMessage', function (evt) {
//* check if this event is the one you want to use
if (evt.detail.type !== "order_complete") {
return;
}
//* If a JSON string was sent, leave it as it is
//evt.detail.elt.setAttribute("hx-vals", evt.detail.data);
//* if not
var msg = {};
msg.orderId = evt.detail.data;
evt.detail.elt.setAttribute("hx-vals", JSON.stringify(msg));
});
see https://htmx.org/attributes/hx-vals/
resulting url if evt.detail.data was 123:
/orders/showmodal?orderId=123
the html:
<div hx-ext="sse" sse-connect="/sse-something">
<div hx-get="/orders/showmodal"
hx-trigger="sse:order_complete"
hx-swap="innerHTML"
hx-target="#idModalPlaceholder">
</div>
</div>
Update
You can also use an event listener just for order_complete.
document.body.addEventListener('sse:order_complete', function (evt) {
//* If a JSON string was sent, leave it as it is
//evt.detail.elt.setAttribute("hx-vals", evt.detail.data);
//* if not
var msg = {};
msg.orderId = evt.detail.data;
evt.detail.elt.setAttribute("hx-vals", JSON.stringify(msg));
});
I found a similar question here: Wrap URL within a string with a href tags using Coldfusion
But what I want to do is replace tags with a slightly modified version AFTER the user has submitted it to the server. So here is some typical HTML text that the user will submit to the server:
<p>Terminator Genisys is an upcoming 2015 American science fiction action film directed by Alan Taylor. You can find out more by clicking here</p>
What I want to do is replace the <a href=""> part with a new version which would be like this:
...
clicking here
So I'm just adding the text rel="nofollow noreferrer" to the tag.
I must match anchor tags that contain a href attribute with a URL, not just the URL string itself, because sometimes a user could just do this:
<p>Terminator Genisys is an upcoming 2015 American science fiction action film directed by Alan Taylor. You can find out more by http://www.imdb.com</p>
In which case I still only want to replace the tag. I don't want to touch the actual anchor text used even though it is a URL.
So how could I rewrite this Regex
#REReplaceNoCase(myStr, "(\bhttp://[a-z0-9\.\-_:~###%&/?+=]+)", "\1", "all")#
the other way round, where its selecting tags and replacing them with my modified text?
If you're willing, this is a really easy task for jQuery (client-side)
JSFiddle: http://jsfiddle.net/mz1rwo0u/
$(document).ready(function () {
$("a").each(function(e) {
if ($(this).attr('href').match(/^https?:\/\/(www\.)?imdb\.com/i)) {
$(this).attr('rel','nofollow noreferrer');
}});
});
(If you right click any of the imdb links and Inspect Element, you'll see the rel attribute is added to the imdb links. Note that View Source won't reflect the changes, but Inspect Element is the important part.)
If you want to effect every a link, you can do this.
$(document).ready(function () {
$("a").each(function(e) {
$(this).attr('rel','nofollow noreferrer');
});
});
Finally, you can also use a selector to narrow it down, you might have the content loading into a dom element with the id contentSection. You can do...
$(document).ready(function () {
$("#contentSection a").each(function(e) {
if ($(this).attr('href').match(/^https?:\/\/(www\.)?imdb\.com/i)) {
$(this).attr('rel','nofollow noreferrer');
}});
});
It's a bit tougher to reliably parse this in cold fusion without the possibility of accidentally adding it twice (without invoking a tool like jSoup) but the jQuery version is client-side and works by obtaining data from the DOM rather than trying to hot-wire into it (a jSoup implementation works similarly, creating a DOM-like structure you can work with).
When talking about client-side vs server-side, you have to consider the mythical user who doesn't have javascript enabled (or who turns it off with malicious intent). If this functionality is not mission-critical. I'd use JQuery to do it. I've used similar functionality to pop an alert box when the user clicks an outside link on one of my sites.
Here's a jSoup implementation, quick and dirty. jSoup is great for how it selects similarly to jQuery.
<cfscript>
jsoup = CreateObject("java", "org.jsoup.Jsoup");
HTMLDocument = jsoup.parse("<A href='http://imdb.com'>test</a> - <A href='http://google.com'>google</a>");
As = htmldocument.select("a");
for (link in As) {
if (reFindnoCase("^https?:\/\/(www\.)?imdb\.com",link.attr("href"))) {
link.attr("rel","nofollow noreferrer");
}
}
writeOutput(htmldocument);
</cfscript>
What I am trying to achieve is to find a way of displaying a wiki page content in a floating iFrame ( and of course keep the styling ) for a tool that I am developing for our employees. Right now the tool I made is using jQuery dialog box to display a specific document / pdf, For compatibility and usability purposes I would really like to upgrade that so it uses a wiki page instead of documents / PDFs.The problem that I am facing is that there is no really direct link to the content of a Sharepoint wiki page instead the only available direct link is the one to the page all together with all the navigation menus, option panel, user panel etc. I want to avoid using javascrip to strip away these elements. Instead I am simply trying to find out if sharepoint 2013 has some more elegant way of providing the content such as: Web service or javascript SP API.
My ideas so far:
REST Url to give the content back? I know for sure it works for lists and libraries but I couldn't find anything in the REST API About wiki page content
SP.js ? Couldn't find anything about that either
Anyways, it could be possible that I have overlooked things, or probably haven't searched hard enough. However, any help is very very welcome. If you don't know about a concrete solution I would be very happy with nice suggestions too :)
If there is nothing out of the box I will have to get to my backup plan of a jQuery solution to get the page and strip off all unnecessary content and keep the styling.
I believe you are on the right track with REST API, in Enterprise Wiki Page the content is stored in PublishingPageContent property.
The following example demonstrates how to retrieve Enterprise Wiki Page content:
var getWikiPageContent = function (webUrl,itemId,result) {
var listTitle = "Pages";
var url = webUrl + "/_api/web/lists/GetByTitle('" + listTitle + "')/items(" + itemId + ")/PublishingPageContent";
$.getJSON(url,function( data ) {
result(data.value);
});
}
Usage
getWikiPageContent('https://contoso.sharepoint.com/',1,function(pageContent){
console.log(pageContent);
});
And something for those of you who like to have more than one different examples:
var inner_content;
var page_title = "home";
$.ajax({
url: "https://mysharepoint.sharepoint.com/MyEnterpriseWikiSite/_api/web/Lists/getbytitle('Pages')/items?$filter=Title eq '" + page_title +"'",
type: "GET",
headers: {
"ACCEPT": "application/json;odata=verbose"
},
success: function (data) {
if (data.d.results[0]) {
inner_content = data.d.results[0].PublishingPageContent;
}
},
error: function(){ //Show Error here }
});
That's what did the job for me.
This example fetches the inner content of an Enterprise wiki page by Title( make sure you are not using the Name of the page, although Title and Name can be given the same string value, they are different fields in sharepoint 2013 )
I'm filling my WebApp (Django) template variables in html body data attributes. So that I can access them later through Javascript:
<body data-node_ip={{NODE_IP}}>
<body data-node_port={{NODE_PORT}}>
Later in the Javascript code, I'm accessing the variables through jQuery's data method:
var connection = $("body").data("node_ip") + $("body").data("node_port")
This works well with all modern browsers (IE10, Chrome, FF).
Problem:
However it doesn't work with IE9 or older. IE9 only stores one single value associated to the tag.
My question:
How do I store these template variables in my HTML document (without using Javascript / jQuery) so that they are also accessible down to IE9?
Thanks!
This doesn't seem to be valid. You can only have one body element. But you can and should put all the attributes on that single element:
<body data-node_ip={{NODE_IP}} data-node_port={{NODE_PORT}}>
Why don't you assign them different ids and access them like this:
var connection = $("#body1").data("node_ip") + $("#body2").data("node_port")
I am trying to use flowplayer's overlay to load an external page that has a django form built in.
However the overlay loads the page but the submit button simply refreshes the page.
How do i actually submit the values entered in the form?
<script src="http://cdn.jquerytools.org/1.2.5/full/jquery.tools.min.js"></script>
<script>
$(function() {
// if the function argument is given to overlay,
// it is assumed to be the onBeforeLoad event listener
$("a[rel]").overlay({
mask: {
color: '#ebecff',
loadSpeed: 200,
opacity: 0.9
},
effect: 'apple',
closeOnClick: false,
onBeforeLoad: function() {
// grab wrapper element inside content
var wrap = this.getOverlay().find(".contentWrap");
// load the page specified in the trigger
wrap.load(this.getTrigger().attr("href"));
}
});
});
</script>
<div class="bananas">launch</div>
my view boom has a model form.
Without seeing the actual view code, it's hard to give a helpful answer. In the future, please be sure to do so...
If you don't have the overlay programmed to redirect to the page, then submitting it to that same url might process/save the data without you noticing. Is the data being saved, or does absolutely nothing happen when you click 'submit'?
Generally, this is how it works: you need to be posting to a url, defined in urls.py, that points to a view function in your views.py. (These names are merely convention, and can be called whatever you like) You mentioned that you have a view named 'boom': is it defined in your urls.py like this?
url(r'^path/to/boom/$', 'model.views.boom',),
Check that this is defined and that your form is posting to it.
The view must then contain logic to process the request and return a response. Posting to that url will transfer a cleaned_data dictionary of form variables that can be accessed over the field names defined in the form. It looks like this: x = form.cleaned_data[x]. Check the form for its validity with form.is_valid(), and then do your processing. This can involve saving objects, running arbitrary code, whatever you wish.
To find out more, be sure to read the excellent documentation.