GDPR Compliance Sufficiency for Google Family Products - cookies

Since the "non-specific" question I asked earlier didn't have the repercussion nor the closure I was expecting and needed, I decided to move on with the implementation I left there and perpetuate the user decision regarding the use of cookies through a cookie, even though this is as stupid as it sounds.
I'll favour the general laziness around replicating the fully functional, yet not exactly useful, HTML of the other topic in here:
<!DOCTYPE html>
<html>
<head>
<title>GDPR Compliance Implementation</title>
<style stype="text/css">
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font:inherit;font-size:100%;vertical-align:baseline}html,body{color:#242729;font-family:Arial,"Helvetica Neue",Helvetica,sans-serif;font-size:13px;line-height:1.26666667}body{background:#FFF;box-sizing:border-box;color:#242729;display:flex;flex-direction:column;font-family:Arial,"Helvetica Neue",Helvetica,sans-serif;font-size:13px;line-height:1.30769231;min-height:100%;min-width:1075px}a,.s-link{color:#07C;cursor:pointer;text-decoration:none}a.s-link__inherit,.s-link.s-link__inherit{color:inherit}.td-underline{text-decoration:underline!important}div{display:block}p{clear:both;margin-bottom:1em;margin-top:0}input[type="submit"],input[type="button"],button,.button,.btn,[class*="btn-"],.hero-box.double-panel .panel.white .btn{background-color:transparent;border:1px solid transparent;border-radius:2px;box-sizing:border-box;cursor:pointer;display:inline-block;font-family:inherit;font-weight:400;line-height:1;min-height:2.46153846em;outline:none;padding:.61538462em 1em;position:relative;text-align:center;text-decoration:none;touch-action:manipulation;transition:color .1s ease-in,background-color .1s ease-in,border-color .1s ease-in,box-shadow .1s ease-in;vertical-align:middle}svg:not(:root),symbol,image,marker,pattern,foreignObject{overflow:hidden}svg{width:14px;height:14px}.svg-icon{vertical-align:bottom;-moz-transform:rotate(360deg)}.s-btn .svg-icon{transition:opacity 200ms cubic-bezier(.165,.84,.44,1);margin:-.30769231em .15384615em -.15384615em -.53846154em}select,input,button,.button,a.button:link,.btn,[class*="btn-"],.hero-box.double-panel .panel.white .btn{background-color:#0095ff;border-color:#07c;box-shadow:inset 0 1px 0 #66bfff;color:#FFF}.svg-icon:not(.native) *{fill:currentColor}.s-btn{background-color:transparent;border:1px solid transparent;border-color:rgba(0,89,153,0);border-radius:2px;box-shadow:0 0 0 0 rgba(0,149,255,0);color:#07C;cursor:pointer;font-family:inherit;font-size:inherit;font-weight:400;line-height:1.15384615;outline:none;padding:.8rem;position:relative}.s-btn,.s-btn:focus{background-color:rgba(0,119,204,0)}.s-btn,.s-btn:hover,.s-btn:focus,.s-btn.is-selected,.s-btn[disabled]{background-image:none}.s-btn__inverted{box-shadow:0 0 0 0 rgba(0,149,255,0);color:rgba(204,234,255,0.9)}.s-btn__inverted,.s-btn__inverted:focus{background-color:rgba(255,255,255,0)}.bg-black-700{background-color:#3b4045!important}.fc-white{color:#FFF!important}.baw0{border-width:0}.lh-lg{line-height:1.61538462!important}.ps-fixed{position:fixed}.r0{right:0}.b0{bottom:0!important}.l0{left:0}.grid{display:flex}.grid-center{align-items:center!important;justify-content:center!important}.p16{padding:16px!important}.gs8{margin:-4px}.mx-auto{margin-left:auto;margin-right:auto}.m0{margin:0}.mb-0{margin-bottom:0!important}.mt-10p{margin-top:10%}.ml-auto{margin-left:auto}.gsx,.gsx>.grid,.gsx>[class*="grid--cell"]{margin-bottom:0;margin-top:0}.gs8>.grid,.gs8>.grid--cell{margin:4px}.wmx10{max-width:81.025641rem!important}.z-banner{z-index:5000!important}.hidden{display:none!important}
</style>
</head>
<body>
<div class="mx-auto mt-10p">
<p>GDPR Compliance Implementation</p>
<p>
Have you agree with GDPR Compliance?
<span id="hasCompliedWith">NO</span>
</p>
<p id="disagreeWithGDPR">
Click here to disagree with GDPR
</p>
</div>
<div id="js-gdpr-consent-banner" class="p16 bg-black-700 fc-white ps-fixed b0 l0 r0 z-banner" role="banner" aria-hidden="false">
<div class="wmx10 mx-auto grid grid__center jc-spacebetween gs8 gsx" role="alertdialog" aria-describedby="notice-message">
<div class="grid--cell" aria-label="notice-message">
<p class="mb0 lh-lg">
This site uses cookies to deliver our services and to show you relevant ads and job listings.
By using our site, you acknowledge that you have read and understand our <a class="s-link s-link__inherit td-underline fc-white" target="_blank" href="https://stackoverflow.com/legal/cookie-policy">Cookie Policy</a>, <a class="s-link s-link__inherit td-underline fc-white" target="_blank" href="https://stackoverflow.com/legal/privacy-policy">Privacy Policy</a>, and our <a class="s-link s-link__inherit td-underline fc-white" target="_blank" href="https://stackoverflow.com/legal/terms-of-service/public">Terms of Service</a>.
Your use of Stack Overflow’s Products and Services, including the Stack Overflow Network, is subject to these policies and terms.
</p>
</div>
<div class="grid--cell ml-auto" aria-label="notice-dismiss">
<button class="s-btn s-btn__inverted fc-white bg-black-700 baw0 p16 js-notice-close" role="status" aria-hidden="true">
<svg aria-hidden="true" id="gdpr" class="svg-icon m0 iconClearSm" width="14" height="14" viewBox="0 0 14 14">
<path d="M12 3.41L10.59 2 7 5.59 3.41 2 2 3.41 5.59 7 2 10.59 3.41 12 7 8.41 10.59 12 12 10.59 8.41 7z"></path>
</svg>
</button>
</div>
</div>
</div>
<script type="text/javascript">
/*!
* JavaScript Cookie v2.2.0
* https://github.com/js-cookie/js-cookie
*
* Copyright 2006, 2015 Klaus Hartl & Fagner Brack
* Released under the MIT license
*/
!function(e){var n;if("function"==typeof define&&define.amd&&(define(e),n=!0),"object"==typeof exports&&(module.exports=e(),n=!0),!n){var t=window.Cookies,o=window.Cookies=e();o.noConflict=function(){return window.Cookies=t,o}}}(function(){function g(){for(var e=0,n={};e<arguments.length;e++){var t=arguments[e];for(var o in t)n[o]=t[o]}return n}return function e(l){function C(e,n,t){if("undefined"!=typeof document){if(1<arguments.length){"number"==typeof(t=g({path:"/"},C.defaults,t)).expires&&(t.expires=new Date(1*new Date+864e5*t.expires)),t.expires=t.expires?t.expires.toUTCString():"";try{var o=JSON.stringify(n);/^[\{\[]/.test(o)&&(n=o)}catch(e){}n=l.write?l.write(n,e):encodeURIComponent(String(n)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),e=encodeURIComponent(String(e)).replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent).replace(/[\(\)]/g,escape);var r="";for(var i in t)t[i]&&(r+="; "+i,!0!==t[i]&&(r+="="+t[i].split(";")[0]));return document.cookie=e+"="+n+r}for(var c={},f=function(e){return e.replace(/(%[0-9A-Z]{2})+/g,decodeURIComponent)},a=document.cookie?document.cookie.split("; "):[],u=0;u<a.length;u++){var s=a[u].split("="),p=s.slice(1).join("=");this.json||'"'!==p.charAt(0)||(p=p.slice(1,-1));try{var d=f(s[0]);if(p=(l.read||l)(p,d)||f(p),this.json)try{p=JSON.parse(p)}catch(e){}if(c[d]=p,e===d)break}catch(e){}}return e?c[e]:c}}return(C.set=C).get=function(e){return C.call(C,e)},C.getJSON=function(e){return C.call({json:!0},e)},C.remove=function(e,n){C(e,"",g(n,{expires:-1}))},C.defaults={},C.withConverter=e,C}(function(){})});
window.onload = function(e) {
checkStatus();
document.getElementById( 'gdpr' ).onclick = function(e) {
Cookies.set( 'gdpr', '1' );
checkStatus();
}
document.querySelector( '#disagreeWithGDPR a' ).onclick = function(e) {
Cookies.remove( 'gdpr' );
checkStatus();
}
function checkStatus() {
if( typeof Cookies.get( 'gdpr' ) !== 'undefined' ) {
document.getElementById( 'hasCompliedWith' ).innerHTML = 'YES';
document.getElementById( 'js-gdpr-consent-banner' ).classList.add("hidden");
document.querySelector( '#disagreeWithGDPR' ).style.display = 'block';
} else {
document.getElementById( 'hasCompliedWith' ).innerHTML = 'NO';
document.getElementById( 'js-gdpr-consent-banner' ).classList.remove("hidden");
document.querySelector( '#disagreeWithGDPR' ).style.display = 'none';
}
}
}
</script>
</body>
</html>
I made some changes on my final version, notably to have two buttons, one to manifest the acceptance and another the declinal, instead of just one link to close the banner.
With this, I now register one single Cookie with a boolean-integer value, 1 (one) if the user has accepted the Terms — which was written and left available in a very visible place in the footer — or 0 (zero) if the User declined.
I opted for this format not only to demonstrate the User has a more fine control over the decisions but also to simplify the JS conditions.
But — and here comes the point of this discussion — how to apply this decision to mainly, but not limited to, Google Family Services?
It's so much information scattered across several pages that I honestly got lost, but still I managed to come up with this:
Google AdSense
<script>
(adsbygoogle=window.adsbygoogle||[]);
if( typeof cookie !== 'undefined' ) {
/**
* #internal
*
* Modifying the initialized Google AdSense Object in case the
* User didn't consent with GDPR
*/
if( cookie == '0' ) {
adsbygoogle.requestNonPersonalizedAds = 1;
}
} else {
/**
* #internal
*
* But if the consent Cookie doesn't even exist or if the User is still
* browsing ignoring the GDPR message in the bottom we'll pause the
* Ads Request in order to wait for the User to Consent for the first time
*/
adsbygoogle.pauseAdRequests = 1;
}
</script>
The cookie variable is already initialized in the <head> with the Cookie value
After initializing the AdSense variable, I test for the presence of my cookie and if it's not there — which means the GDPR banner will be visible — I make use of
Google Analytics' pauseAdRequests, which, as far as I understood, would not show any ads while the User doesn't consent to the Terms.
If my Cookie does exist, I then test its value and only if 0 (zero), I configure my AdSense with requestNonPersonalizedAds. I only know what that means in theory, as I haven't seen it in action yet.
Google Analytics
Google Analytics was, apparently, easier:
if( typeof cookie === 'undefined' || cookie == '0' ) {
window['ga-disable-UA-XXXXX-Y'] = true;
}
All I had to do was test the presence of my Cookie or if its value means the non-acceptance and in that case disable the tracking.
Other than that, I also configure it with the IP Anonymization. Because I'm not sure the impact that not having Users' IP Addresses would cause on my reports, it's there by default, opting-out or not.
Well, that sure was a long topic with all details I could come up with and all code I have so far — except the little difference I mentioned — so I believe now I can have a proper answer for this matter that's bothering me for so much time.

Related

How do I inject a template into another template in Flask [duplicate]

I Want to develop a flask navigation bar like Google Contacts.
I Want to Render a particular HTML page inside the red box (as in the picture) when I click each of the navigation buttons (the green box as in picture) without refreshing the page.
I have already tried using
{% extends "layout.html" %}
As #Klaus D. mentioned in the comments section, what you want to achieve can be done using Javascript only. Maybe your question were
How can I send a request to my server-side (to get or fetch some information) and receive back a response on the client-side without having to refresh the page unlike the POST method usually does?
I will try to address the aforementioned question because that's probably your case.
A potential solution
Use Ajax for this. Build a function that sends a payload with certain information to the server and once you receive back the response you use that data to dynamically modify the part of the web-page you desire to modify.
Let's first build the right context for the problem. Let's assume you want to filter some projects by their category and you let the user decide. That's the idea of AJAX, the user can send and retrieve data from a server asynchronously.
HTML (div to be modified)
<div class="row" id="construction-projects"></div>
Javascript (Client-side)
$.post('/search_pill', {
category: category, // <---- This is the info payload you send to the server.
}).done(function(data){ // <!--- This is a callback that is being called after the server finished with the request.
// Here you dynamically change parts of your content, in this case we modify the construction-projects container.
$('#construction-projects').html(data.result.map(item => `
<div class="col-md-4">
<div class="card card-plain card-blog">
<div class="card-body">
<h6 class="card-category text-info">${category}</h6>
<h4 class="card-title">
${item.title_intro.substring(0, 40)}...
</h4>
<p class="card-description">
${item.description_intro.substring(0, 80)}... <br>
Read More
</p>
</div>
</div>
</div>
`))
}).fail(function(){
console.log('error') // <!---- This is the callback being called if there are Internal Server problems.
});
}
Build a function that will fetch the current page via ajax, but not the whole page, just the div in question from the server. The data will then (again via jQuery) be put inside the same div in question and replace old content with new one.
Flask (Server-side)
''' Ajax path for filtering between project Categories. '''
#bp.route('/search_pill', methods=['POST'])
def search_pill():
category = request.form['category']
current_page = int(request.form['current_page'])
## Search in your database and send back the serialized object.
return jsonify(result = [p.serialize() for p in project_list])
Thank you #CaffeinatedCod3r,#Klaus D and #newbie99 for your answers.
I Figured it out. instead of using Flask we can use Angular JS Routing for navigation.
Here is the example that i referred:
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-route.js"></script>
<head>
<base href="/">
</head>
<body ng-app="myApp">
<p>Main</p>
Banana
Tomato
<p>Click on the links to change the content.</p>
<p>Use the "otherwise" method to define what to display when none of the links are clicked.</p>
<div ng-view></div>
<script>
var app = angular.module("myApp", ["ngRoute"]);
app.config(function($routeProvider, $locationProvider) {
$routeProvider
.when("/banana", {
template : "<h1>Banana</h1><p>Bananas contain around 75% water.</p>"
})
.when("/tomato", {
template : "<h1>Tomato</h1><p>Tomatoes contain around 95% water.</p>"
})
.otherwise({
template : "<h1>Nothing</h1><p>Nothing has been selected</p>"
});
$locationProvider.html5Mode(true);
});
</script>
</body>
</html>
By Using $locationProvider.html5Mode(true) i was able to remove the # from the URL.

accept.js in sandbox - E_WC_21: User authentication failed

Trying to work out accept.js to replace a depreciated method for authorize.net payments. Not doing anything gcomplicated, but can't get past the authentication failed message when using the sandbox
Logging into the sandbox account to generate keys … they're named slightly differently than the code samples. So I MAY BE AN IDIOT.
OK, apiLoginID - obvious …
Code below calls for data-clientKey. Not 100% sure which of the two below that actually is. I've tried both. Same error with both.
API Login ID : 4CLLpD------
Transaction Key : 9628s6xCSh------
Key : ------A4D932A4AFED546DE55E4D04C16CA66549915AFDC4FBA3A1665E271A2FB48A7A34394843A47BC170FFB4A5B99EDD17B75D99942E4E7F7133C2E1------
<script type="text/javascript"
src="https://jstest.authorize.net/v3/AcceptUI.js"
charset="utf-8">
</script>
<form id="paymentForm"
method="POST"
action="mysite.com/beta-account/order-receipt.php" >
<input type="hidden" name="dataValue" id="dataValue" />
<input type="hidden" name="dataDescriptor" id="dataDescriptor" />
<button type="button"
class="AcceptUI btn-success btn-lg"
data-billingAddressOptions='{"show":true, "required":false}'
data-apiLoginID="4CLLpDX----"
data-clientKey="9628s6xCShc-----"
data-acceptUIFormBtnTxt="Submit"
data-acceptUIFormHeaderTxt="Card Information"
data-responseHandler="responseHandler">Pay
</button>
</form>
<script type="text/javascript">
function responseHandler(response) {
if (response.messages.resultCode === "Error") {
var i = 0;
while (i < response.messages.message.length) {
console.log(
response.messages.message[i].code + ": " +
response.messages.message[i].text
);
i = i + 1;
}
} else {
paymentFormUpdate(response.opaqueData);
}
}
function paymentFormUpdate(opaqueData) {
document.getElementById("dataDescriptor").value = opaqueData.dataDescriptor;
document.getElementById("dataValue").value = opaqueData.dataValue;
document.getElementById("paymentForm").submit();
}
</script>
Right now, there's not really anything on the order-receipt.php page. I'm just trying to get the post to make it that far and show me a dump of everything that post to the page, so even once I get this working, I've still got a ways to go.
When I go to the payment page, hit the "Pay" button, fill out the credit card form, hit "submit" … it doesn't go anywhere at all. It stays on the page and the console reports: "E_WC_21: User authentication failed due to invalid authentication values."
This has turned into one more frustrating thing after pulling over half my hair out over authorize.net's documentation of what I need to do about the MD5 end-of-life … of which I never could get anything to work to replace the SIM relay-response method that was being used. response.js seems fairly simple as a replacement, and I'm stuck here too.
What do I try next?
OK, I think I found the problem …
There's a difference between the API Login ID, the Transaction Key, and the Client Key.
That's not immediately obvious in some of the docs ….
For getting the data-clientKey, you should go to this place. Please see the attach screenshot.
Screenshot

Rendering parameters incorrect when multiple of same rendering

I'm having an issue with a rendering I'm building in Sitecore 8 Update 3, using MVC with Glass Mapper v4.
I have a Feature Promo rendering that has a Rendering Parameter Template Feature Promo Parameters which defines a droplist field named Align with the possible values Left and Right.
When in Experience Editor and Preview mode the rendering renders correctly and when debugging RenderingContext.Current["Parameters"] contains Align=Left or Align=Right accordingly, and Glass maps this correctly to my POCO.
However, when in web mode, the first rendering has Align=Left as its parameter, all subsequent renderings of the same type have Align with no value.
Checking the layout XML in the web database via Sitecore Rocks, I can see the parameters are there correctly:
<r p:p="1" xmlns:p="p" xmlns:s="s">
<d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}">
<r p:before="r[#uid='{CAE5DB0F-1971-4931-939B-9F7DB14AF0F8}']"
s:ds="{F63266A5-CC62-4915-9D89-CB01C7A0D05A}"
s:id="{6BA52384-D976-499D-8A0D-7F729EB4376B}"
s:par="Align=Left" s:ph="main"
uid="{4CBD0824-D232-46F9-8763-295D3B493A4F}"/>
<r p:before="r[#uid='{12A7C72A-1821-4F8D-9A87-745604BE5106}']"
s:ds="{C50C7579-3680-46C3-93B2-9429EB9E0100}"
s:id="{6BA52384-D976-499D-8A0D-7F729EB4376B}"
s:par="Align=Right" s:ph="main"
uid="{CAE5DB0F-1971-4931-939B-9F7DB14AF0F8}"/>
<r p:before="*[1=2]" uid="{12A7C72A-1821-4F8D-9A87-745604BE5106}"/>
</d>
</r>
No matter what I do, the second (and any subsequent renderings of the same type) doesn't get the specified parameter value.
The code of the rendering is as follows:
#model Promo
#{
var settings = Html.Glass().GetRenderingParameters<FeaturePromoParameters>();
var alignment = "feature-promo-style-a";
if (settings != null && settings.Align.EqualsText("Right")) {
alignment = "feature-promo-style-b";
}
}
<div class="feature-promo #alignment">
<div class="layout layout-a">
<div class="region region-a">
<div class="region-inner">
<div class="feature-promo-image-container">
#Html.Glass().Editable(m => m.Image)
</div>
<div class="block block-size-b feature-promo-text">
#if (Html.Glass().IsInEditingMode || !Model.PreTitle.IsEmptyOrNull()) {
<div class="pre-title">#Html.Glass().Editable(m => m.PreTitle)</div>
}
#if (Html.Glass().IsInEditingMode || !Model.Title.IsEmptyOrNull()) {
<h2 class="h3 color-a">#Html.Glass().Editable(m => m.Title)</h2>
}
#Html.Glass().Editable(m => m.Body)
</div>
</div>
</div>
</div>
</div>
Can anyone advise what I'm doing wrong, or if I've found a random bug?
Update for Marek Musielak:
OK, its now only hitting the breakpoint once -- and has the uid of the first rendering on the page: {4CBD0824-D232-46F9-8763-295D3B493A4F}. Could this turn out to be something dynamic placeholders related?
RenderingContext.CurrentOrNull.Rendering["Parameters"] = "Align=Left"
This appears to be due to caching... oh the shame.
The renderings had Cacheable unchecked, and no other caching settings selected.
I've just updated them to have Cacheable checked and Vary by Parameters checked, re-published and its now working correctly.
I would have thought that having Cacheable off would mean the rendering would not be cached, but apparently not.
Thanks.

CSS3 class match letter range [a-z]+?

Is there any possibility to create CSS definition for any element with the class "icon-" and then a set of letters but not numbers.
According to this article something like:
[class^='/icon\-([a-zA-Z]+)/'] {}
should works. But for some reason it doesn't.
In particular I need to create style definition for all elements like "icon-user", "icon-ok" etc but not "icon-16" or "icon-32"
Is it possible at all?
CSS attribute selectors do not support regular expressions.
If you actually read that article closely:
Regex Matching Attribute Selectors
They don’t exist, but wouldn’t that be so cool? I’ve no idea how hard it would be to implement, or how to expensive to parse, but wouldn’t it just be the bomb?
Notice the first three words. They don't exist. That article is nothing more than a blog post lamenting the absence of regex support in CSS attribute selectors.
But if you're using jQuery, James Padolsey's :regex selector for jQuery may interest you. Your given CSS selector might look like this for example:
$(":regex(class, ^icon\-[a-zA-Z]+)")
I answered this one on facebook but thought I'd best share here too :)
I haven't tested this so don't shoot me if it doesn't work :) but my guess would be to excplicitly target elements that contain the word icon in the classname, but to instruct the browser not to inlcude those classes containing numbers.
Example code:
div[class|=icon]:not(.icon-16, .icon-32, icon-64, icon-96) {.....}
Reference:
attribute selectors... (http://www.w3.org/TR/CSS2/selector.html#attribute-selectors):
[att|=val]
Represents an element with the att attribute, its value either being exactly "val" or beginning with "val" immediately followed by "-" (U+002D).
:not selector...
(http://kilianvalkhof.com/2008/css-xhtml/the-css3-not-selector/)
Hope this helps,
Waseem
I tested my previous solution and can confirm that it DOES NOT work (see comment from BoltClock). This however does:
OP: "In particular I need to create style definition for all elements like "icon-user", "icon-ok" etc but not "icon-16" or "icon-32""
The required CSS code would look something like this:
/* target every element were the class name begins with ( ^= ) "icon" but NOT those that begin with ( ^= ) "icon-16", or "icon-32" */
*[class^="icon"]:not([class^="icon-16"]):not([class^="icon-32"]) {.....}
or
/* target every element were the class name begins with ( ^= ) "icon" but NOT those that contain ( *= ) the number "16" or the number "18" */
*[class^="icon"]:not([class*="16"]):not([class*="32"]) { ...... }
Test code:
<!DOCTYPE html>
<html>
<head>
<style>
div{border:1px solid #999;margin-bottom:1em;height:100px;}
*[class|=icon]:not([class|=icon-16]):not([class|=icon-32]) {background:red;color:white;}
</style>
</head>
<body>
<div class="icon-something">
<h4>icon-something</h4>
<p><strong>IS</strong> targeted therfore background colour will be red</p>
</div>
<div class="icon-anotherthing">
<h4>icon-anotherthing</h4>
<p><strong>IS</strong> targeted therfore background colour will be red</p>
</div>
<div class="icon-16-install">
<h4>icon-16-install</h4>
<p>Is <strong>NOT</strong> targeted therfore no background colour</p>
</div>
<div class="icon-16-redirect">
<h4>icon-16-redirect</h4>
<p>Is <strong>NOT</strong> targeted therfore no background colour</p>
</div>
<div class="icon-16-login">
<h4>icon-16-login</h4>
<p>Is <strong>NOT</strong> targeted therfore no background colour</p>
</div>
<div class="icon-32-install">
<h4>icon-32-install</h4>
<p>Is <strong>NOT</strong> targeted therfore no background colour</p>
</div>
<div class="icon-32-redirect">
<h4>icon-32-redirect</h4>
<p>Is <strong>NOT</strong> targeted therfore no background colour</p>
</div>
<div class="icon-32-login">
<h4>icon-32-login</h4>
<p>Is <strong>NOT</strong> targeted therfore no background colour</p>
</div>
</body>
</html>

XSL master/ detail

I have a xsl code that I would like to show a nested row below each row that the user chooses.
Let's say I have a row that shows 4 columns with the main order details, I want the user to be able to click a plus or 3 dots "..." to see more details about this order.
I have all the information loaded already to the xml on the page so there is no need to go to the db again for the details.
Is this possible?
Example will be appreciated.
Thanks.
A crude example to show how its done in javascript! :) In IE click on "allow blocked contents"
<html>
<head>
<script language="javascript" type="text/javascript">
var f=0;
function tnd()
{
if(f==1)
{
var str2="The images, quotes and everything else are intended to be maintained strictly confidential. Rightclick of the mouse has been disabled, as well as alt+printscreen and copy options do not work well in major browsers. design:aravind"
document.getElementById("t_n_d").innerHTML=str2;
f=0;
return 1;
}
if(f==0)
{
var str1="to read features, terms and conditions about this design."
document.getElementById("t_n_d").innerHTML=str1;
f=1;
return 1;
}
}
</script>
</head>
<body>
<span id='footertext'
style="font-size: 12px;"><span onmousedown='tnd();' style='color: red; text-decoration: underline; cursor: pointer;'>click here</span> : <span id='t_n_d'>to read features, terms and
conditions about this design.</span></span></td>
</tr>
</body>
</html>
Copy the html code in "str2" to load tables .. pictures or etc ..
(ps: replace double-quotes with single-quotes in str2)
also please note that javascript is a client-side script .. it is harms performance on over usage .. this is just to give you an idea.