How to disallow user to remove HTML element manually from DOM? - javascript

In web development it's quite popular idea to create the element with fixed position and transparent background color which covers the whole page until the user interacts somehow (by accepting consent or paying for the service). Then the element is removed and user can use the web page.
Here's the example:
However user can remove the element manually, using dev tools in the browser.
Is there any way to prevent it? Is it possible to disallow some particular element to be deleted?

You can't.
The browser belongs to the user and is completely under their control.
If you don't want to provide them with something before they accept terms, then don't send the something to the browser until they have.

As far as it seems to be impossible to prevent the user from removing an element it is possible to detect the element removal.
The MutationObserver API allows us to detect changes of a particular DOM element.
Here's example by Jakub Jankiewicz
var in_dom = document.body.contains(element);
var observer = new MutationObserver(function(mutations) {
if (document.body.contains(element)) {
if (!in_dom) {
console.log("element inserted");
}
in_dom = true;
} else if (in_dom) {
in_dom = false;
console.log("element removed");
}
});
observer.observe(document.body, {childList: true});
When the element is removed we can of course add it again or redirect to error page indicating that any manipulations of the page are illegal.
In particular the deletion of the element is easy with this React extension. If we use React then we can just wrap the element we want to prevent from being deleted in the component:
import { WatchForRemoval } from 'react-mutation-observer';
...
<WatchForRemoval onRemoval={console.log.bind(null, 'Child removal triggered.')}>
<div>
Removing this element will trigger callback
</div>
</WatchForRemoval>

This is not possible. You can make it harder for the user to get around it, but you can't prevent them from removing it from the page.
I've seen websites use a lot of different solutions for making it harder to get around, ranging from locking the scrolling of the page to fully removing the content behind the pop up, but ultimately you can't prevent the user from modifying the DOM.

You need to add control server side.
Your user can control the data they receive. Don't send the data if you don't want them to access data.

Related

Move entire document into iframe

I'm adding a chat feature to a couple of our websites. The chat will connect users with people at our help desk to help them use the websites. Our help desk folks want the chat window to appear like a tab on the side of the page and slide out, rather than popping up in a new window. However, I want to allow the user to navigate around the site without losing the chat.
To do this, I've been trying to move the entire page into an iframe once the chat starts (with the chat outside the iframe), so the user can navigate around the site within the iframe without losing the chat.
I used this answer to get started, and that works great visually. However, some of the javascript in the background breaks.
One of the sites is ASP.NET web forms. The other is MVC. I've been working with the web forms one first. Stuff like calling __doPostBack breaks once the page is moved into the iframe since the javascript context is left behind.
Once the user clicks on a link (a real link, not a __doPostBack) and the iframe refreshes, then everything works perfectly.
How I see it, I have a few options:
Copy all javascript variables from window.top into the iframe somehow. Hopefully without having to know all the variable names. I tried this.contentWindow.__doPostBack = window.top.__doPostBack, which works, but other variables are missing so it ultimately fails:
Somehow switch the iframe's context to look at the top window context, if that's even possible? Probably not.
Another thought was to not move the page into an iframe right away, but to wait until the page changes and then load the new page into a new iframe. But I'm not sure how to hook into that event and highjack it.
Something else?
These are sites for use by our employees only, so I only have to support IE11 and Chrome.
Update:
Thanks to LGSon for putting me on the track of using the target attribute (so I can use approach #3). Below is what I ended up doing. When I pop out the chat, I call loadNextPageInIframe(). I'm using jQuery here since we already use it on our site, but everything could be done without. I set the target on all links that don't already have a target pointing to another frame or _blank. I left _parent out, but I don't think we use it anyway.
I have a reference to my chat window div in a global variable called 'chatwindow'.
There still could be some cases where this doesn't work, such as if there is some javascript that sets window.location directly. If we have anything in our sites that does this, I'll have to add a way to handle it.
function loadNextPageInIframe() {
var frame = $("<iframe id=\"mainframe\" name=\"mainframe\" />").css({
position: "fixed",
top: 0,
left: 0,
width: "100%",
height: "100%",
border: "none",
display: "none"
}).appendTo("body");
$("form, a:not([target]), a[target=''], a[target='_top'], a[target='_self']").attr("target", "mainframe");
var firstload = true;
frame.load(function () {
//Runs every time a new page in the iframe loads
if (firstload) {
$(frame).show();
//Remove all elements from the top window except the iframe and chat window
$("body").children().not(frame).not(window.top.chatwindow).remove();
firstload = false;
}
//Make the browser URL and title reflect the iframe every time it loads a new page
if (this.contentWindow && this.contentWindow.location.href && window.top.location.hostname === this.contentWindow.location.hostname && window.top.location.href !== this.contentWindow.location.href) {
var title = this.contentDocument.title;
document.title = title;
if (window.top.history.replaceState) window.top.history.replaceState(null, title, this.contentWindow.location.href);
}
});
}
May I suggest you do the following
get all links
attach an event click handler to intercept when someone click a link
on click event, check if chat is in progress, and if, feed the iframe with the new link
var links = querySelectorAll("a");
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click', function(e) {
if (isChatInProgress()) {
e.preventDefault(); //stop the default action
document.getElementById("your_iframe_id").src = e.target.href;
// anything else here, like toggle tabs etc
}
});
}
Update
To handle forms I see 4 ways at the moment
1) Add an onsubmit handler to your forms
function formIsSubmitted(frm) {
if (isChatInProgress()) {
frm.target = "the iframe";
}
return true;
}
<form id="form1" runat="server" onsubmit="return formIsSubmitted(this)">
2) Add a click handler to your buttons
function btnClick(btn) {
if (isChatInProgress()) {
btn.form.target = "the iframe";
}
return true;
}
<asp:Button runat="server" ID="ButtonID" Text="ButtonText"
OnClick="Button_Click" OnClientClick="return btnClick(this);" />
3) When a chat start, you iterate through each form and alter its target attribute
function startChat() {
var forms = querySelectorAll("form");
for (var i = 0; i < forms.length; i++) {
forms[i].target = "the iframe";
});
}
4) Override the original postback event (Src: intercept-postback-event)
// get reference to original postback method before we override it
var __doPostBackOriginal = __doPostBack;
// override
__doPostBack = function (eventTarget, eventArgument) {
if (isChatInProgress()) {
theForm.target = "the iframe";
}
// call original postback
__doPostBackOriginal.call(this, eventTarget, eventArgument);
}
Update 2
The absolute best way to deal with this is of course to use AJAX to load both page and chat content, but that likely means a quite bigger work load if your sites aren't already use it.
If you don't want to do that, you can still use AJAX for chat and if a user were to navigate to a new page, the chat app recreate the ongoing chat window with all its content again.
I suggest instead of loading content to and from iframes - build the chat as an iframe and use a jQuery modal popup on the page for chat.
You can fix the jquery modal to a fixed location and page scrolling is enabled by default. You need to modify css accordingly to make the popup remains on the same location.
If you go down your current path - you will need to worry a lot about how content is moved to the iframe and it might be difficult to re-use the chat on different pages depending on the content. For example, imagine you playing a video on the page and the user clicks chat - if you load the content to the iframe - the user will lose the status on how far he has viewed, etc.
as per my opinion, adding the whole website as an 'I-Frame' is not a good design practice, and not a good solution for the problem. My suggestion would be:
Ensure that the 'Chat' application is loaded in all the pages, across your website
Whenever the 'Chat' is started, either establish the 'web-socket' connection or somehow, maintain the State on the Server
Have the configuration of the 'Chat' as 'Minimized', 'Open' etc and store them in your cookie or session storage
On every page load, call the 'Chat' application too. Read the Chat related configuration from sessionstorage or cookie and maintain it's state as 'Minimized' or 'Open' etc, including the X and Y position, if you want to make it as 'Floated'
Every time, either fetch the entire conversation from the server via Ajax or try to store and fetch from 'Local Storage' and do Ajax only for any Updates from the other party
Use CSS based 'Float' related properties to make it float and sit at some side.
This will ensure that your chat is available for the user and yet he can navigate all through the site.

Javascript function onclick, back button to "refresh" page

I have looked around, but I'm not seeing anything that specifically addresses this. My goal is to have a link, which can be clicked to either add content or "undo" the act of adding that content. I am trying to us the following:
function ShowDiv() {
if (null == window.set) {
document.getElementById("box2").innerHTML = "Some Content";
window.set = "set";
} else
location.reload();
}
Link
<div id="box2"></div>
This allows me to click the link to show some content inside some div. And then to click the link again to remove that content.
However, I am wondering if there is a way to achieve this result, that also allows the user to click the browser's back button to return the page to the state it was in before triggering the function (e.g., to reload the page).
You are looking for the HTML5 history API. This allows you to push state onto the history as if the browser loaded a different location without actually sending a request and replacing all content and javascript state. This allows the back and forward buttons to work, as long as your JavaScript code shows the correct content according to the current URL.
Resources:
W3C
MDN
Dive Into HTML5

Chat app Scrollable div or Iframe

What is the advised method to make a chat window scrollable, using an iframe or a scrollable div? What are the pros&cons of the two techniques? Which would you opt for and why?
Thanks
You can create a script that will embed a chat into a third-party website creating both <div> or <iframe>
The main interesting differences
iframe
Code: All user events (clicks, key events, hovers etc) are handlable exclusively from your external chat app page. Without a complicated API the user will not be able to easily modify or target desired events to suit their needs (Why should they after all). The sensitive backend code and logic can stay hidden on your side.
Styling: Your chat app will look exactly like you defined it. With an extended API the user will only be able to select some predefined styles. (I personally hate that.) So more coding for you.
Uses Mostly used by free chat apps where they force the app to be just the way they want it to be, preventing custom styles and possibly the removal of the App logo, link to the from site, or some random ads. Also used if you want to provide the data storage on your side, or provide silent application updates.
Scroll and heights are unaware of the surrounding items which ends mostly having an API where the user chooses some predefined chat heights.
DIV
Code: All user events (clicks, key events, hovers etc) are easily accessible and modifiable to the programmer. You can still have a nice plugin / API that will simplify customizations to the user.
Styling: The DIVs being rendered inside the user page will inherit that page styles.
The good part it that the chat app will have a design that suits perfectly the page design.
The hard part is that in your CSS you'll have to probably prevent some chat sensitive styles to be overwritten by the host page styles. Be careful.
Uses: people are gonna love it. If you want users to keep your link or logo you can ask them to keep the copyright or the link. You cannot count that this will happen. If you sell your app, or you just don't care, than I find this use the proper one.
Scroll and heights of chat elements are aware of the surrounding document. My suggestion here is to create a fluid chat app using %. That way your app will fit inside every container, and if it's a fluid page... more love for you.
So even if I would personally choose the <div> one, it's totally up to your needs.
Regarding scrollability I've created a nice UI technique:
Create a variable-flag that will register if the scrollable area is hovered
after you ping the server for the new message, run a function that will scroll the area to bottom
if the scrollable area is hovered means that the user is reading old chats
on mouseleave = scroll automatically the chat to the bottom (last conversation)
See it in action here
HTML:
<div class="chat">
<div class="messages">
<div>Old message</div>
</div>
<textarea></textarea>
<button>Post</button>
</div>
BASIC CSS (more CSS in the demo link):
.chat{
position:relative;
margin:0 auto;
width:300px;
overflow:hidden;
}
.chat .messages{
width:100%;
height:300px;
overflow:hidden;
}
.chat .messages:hover{
overflow-y:scroll;
}
.chat .messages > div{
padding:15px;
border-bottom:1px dashed #999;
}
jQuery:
var $chat = $('.chat'),
$printer = $('.messages', $chat),
$textArea = $('textarea', $chat),
$postBtn = $('button', $chat),
printerH = $printer.innerHeight(),
preventNewScroll = false;
//// SCROLL BOTTOM
function scrollBottom(){
if(!preventNewScroll){ // if mouse is not over printer
$printer.stop().animate( {scrollTop: $printer[0].scrollHeight - printerH }, 600); // SET SCROLLER TO BOTTOM
}
}
scrollBottom(); // DO IMMEDIATELY
function postMessage(e){
// on Post click or 'enter' but allow new lines using shift+enter
if(e.type=='click' || (e.which==13 && !e.shiftKey)){
e.preventDefault();
var msg = $textArea.val(); // not empty / space
if($.trim(msg)){
$printer.append('<div>'+ msg.replace(/\n/g,'<br>') +'</div>');
$textArea[0].value=''; // CLEAR TEXTAREA
scrollBottom(); // DO ON POST
// HERE Use AJAX to post msg to PHP
}
}
}
//// PREVENT SCROLL TO BOTTOM WHILE READING OLD MESSAGES
$printer.hover(function( e ) {
preventNewScroll = e.type=='mouseenter' ? true : false ;
if(!preventNewScroll){ scrollBottom(); } // On mouseleave go to bottom
});
$postBtn.click(postMessage);
$textArea.keyup(postMessage);
//// TEST ONLY - SIMULATE NEW MESSAGES
var i = 0;
intv = setInterval(function(){
$printer.append("<div>Message ... "+ (++i) +"</div>");
scrollBottom(); // DO ON NEW MESSAGE (AJAX)
},2000);
I will myself always go for a div for a chat application, Why?
Here is basic benefit. You can handle the events on a div, that you cannot handle using an iframe. You can try it for yourself, try to handle click, mouseover events inside an iframe, you won't get anything.
$('div').click(function () {
alert('Div was clicked!');
}
While iframe won't let you access events on the child elements of it.
While div will provide each and every event to the parent or even the js to handle and do the coding as necessary. For iframe you need to handle the events inside the iframe, lets say the page from where the iframe was loaded, its events are inside the code that was used to create it.
$('iframe').click(function () {
// code..this will execute when click is on iframe, not for a child
}
But you cannot do something as
$('iframe html body div').click(function () {
/* techniques for iframes are different and harder as
* compared to ones used for div, to get a child event
*/
})
But the elements inside the div can be embedded for your webpage. And you can always change its child or parent elements. So chat app will be better, if you can handle all the element events.
<div>
Some text
</div>
jQuery
$('div').on('event', function () { // on an event..
// so on, adding more and more event handlers and blah blah
})
In a div, you can just update the content using ajax request, and then add it to the div and you can also use jQuery API to scroll it. No matter how much page size, you can use % or exact place where to scroll to. So divs are simpler.
$('div').load('chat_page.php'); // load a page in the div
Or just update it using,
$.ajax({ // create ajax request
url: 'chat_message', // url
success: function (resp) { // if OK
$('div').html(resp); // update the page
}
});
Iframes are generally used to let others use your functionality, such as embedding chat application in a third party site, where you don't need them to edit or reuse your code. So you give them an iframe and a link.
Scolling thing was not understood by me! :( Sorry about that, I think I am going to write vague answer for that, so I will let that part go but this is how you can scroll the element
$('div').scrollTo(10); // scroll 10px down..
(You asked for browser support in comments) However, jQuery is supported cross-browser and cross platform. And the remaining part is HTML which is supported everywhere!
http://jquery.com/browser-support/ Here is a link to know the browser support
I prefer to use div as you can easily manage everything about it and it is easier to refresh, using less data for download for the server. Just a personal opinion.
PROS or DIV include less data, insert anywhere any time, and ability to easily use data for other tasks if needed on the page.
Pros of IFRAME easier to setup and code and easier ability to make it stand alone.
Cons of Iframe and it is harder to access data within and requires more code to do so if needed and cons of div are getting all the css and code right and inplace for the div and its parents and its children for it to flow correctly and nicely.

Jquery - tell when the hash changes?

I'm trying to make my site respond correctly to the back button. I've saved that hash of what I want it to do, but I don't know the hook for jQuery to be able to tell when the hash changes. It's not .ready(), because the page doesn't reload. What do I use?
Edit for a bit of clarity:
I'm using an iframe, so I can't tell when someone clicks a link. It's on the same subdomain, so i'm able to see it's filepath, and am saving it so you can bookmark. Unfortunately by saving it as a hash, my back button now fails to reload, which fails to reload the iframe, so my back button is essentially broken. If there was a way to tell when the URI changes, I could check it against the iframe address and change it if they don't match.
All I need is a way to check if the URI has changed. Is there a .change() for the URI? Something along those lines?
You can try History Event plugin.
After the document is ready, you examine the hash and alter the page appropriately.
I don't know the hook for jQuery to be able to tell when the hash changes
You can intercept your hash anchors' click events and respond appropriately as opposed to waiting for a "the hash has changed" event (which doesn't exist).
Some approaches create a "the hash has changed" event by inspecting window.location.hash on a timer.
Ben 'the cowboy' Alman wrote a cross platform plugin for hash changes
http://benalman.com/news/2010/07/jquery-hashchange-event-v13/
I dont know if your using it inside of the iframe or what, but if you were to use it outside the iframe it would be like
$(function(){
$(window).hashchange(function(){
//Insert event to be triggered on has change.
changeIframeContent(window.location.hash);
})
})
You should have a look at the solution of Ben Nadel which is in binding events to non-DOM objects.
There is'nt a buitin way to watch for hash changes, in firefox you could use watch method, but as far as I know it isnt default, so you can hack it writing something like (see below)
function setWatchHashChanges(functionObject)
{
if(window.location.watch)
{
window.location.watch('hash', function(e){functionObject(e);return e;});
} else {
if(!setWatchHasnChanges.hash)
{
setWatchHasnChanges.hash = window.locaton.hash;
} else {
setInterval(function(){
if(setWatchHasnChanges.hash!== window.locaton.hash)
{
setWatchHasnChanges.hash = window.locaton.hash;
functionObject(setWatchHasnChanges.hash);
}
}, 100);
}
}

iFrame Validation

I currently have an iframe within my main page that has a number of checkboxes that need to be actioned prior to leaving the iframe. i.e, if the user commences checking the checkboxes and half way through they then click back on the main page, i.e leaving the iframe, I would like to be able to trap/validate that they have left the iframe and prompt them with a message indicating this, say with a "Note: You will lose all data entered here - Leave: Yes/No?" type message.
Prompting a User to Save When Leaving a Page. This 4guys article sounds like what you need. It talks about the onbeforeunload event. There's some awesome posts here on stackoverflow about onbeforeunload too.
It appears that onbeforeunload indeed does not fire for an iframe. Bugger!
Here's some sample code that should work though. This will only work if you're in the same domain, otherwise same origin policy will prevent the iframe from talking back to the parent.
I also haven't tested these in many browsers so YMMV.
You've got two options here, depending on where you want to put the prompt for changes logic.
Option one involves the iframe telling the parent window when there's changes.
Parent window javascript:
window.onbeforeunload=closeIt;
var changes = false;
function closeIt()
{
if (changes)
{
return "Yo, changes, save 'em?";
}
}
function somethingChanged() {
changes=true;
};
Iframe javascript:
$(function() {
$('input').change(parent.somethingChanged);
});
Option two involves the iframe taking control over the parent window's onbeforeunload
Parent window javascript:
There is none :-)
Iframe javascript:
$(function() {
parent.window.onbeforeunload = myCloseIt;
$('input').change(somethingChanged);
});
var changes = false;
function myCloseIt()
{
if (changes)
{
return "Yo, changes, save 'em?";
}
}
function somethingChanged() {
changes=true;
};
In either option the naive changes variable could be beefed up a bit, probably using techniques from the 4guys article, to see if there's really been any changes.
If they're on different domains, but you're still in charge of "both sides" of the HTML, there's still some options, they're just harder.
xssinterface is a library that uses postMessage and location hashes and secret voodoo black magic to communicate cross site.

Categories

Resources