Monitor DOM changes and style content with jQuery Mobile and SammyJs - javascript

I am using jQuery Mobile as a mobile framework. I use jQuery to dynamically populate my pages with custom content. jQuery Mobile does not apply styling to element created after page load. For that reason, I am using
$('[data-role=content]').trigger('create');
so jQuery Mobile re-evaluates the page styling after my new content has been created.
I also use SammyJs to load the routes and handle the dynamic content creation. I found that if I put the trigger(create) inline with my JSON request, the code does not work. However, if I execute the code from a console (adding time between the JSON request and the trigger), jQuery would correctly apply styling...
My workaround is to use setTimeout :
setTimeout(function() {
$('[data-role=content]').trigger('create');
}, 100);
However, I don't feel it is the best solution because the content appears unstyled for miliseconds (user can see it) and then gets refreshed with correct styling...
Is there a way to monitor DOM changes with jQuery mobile or Sammy?

Related

How to sandbox a div element?

I am trying to build a content editor. This contenteditor will load a HTML document (with JavaScript) into for example a #result element. The problem with this, is that if inside this HTML element there is for example $("input").hide();, then all of my inputs are gone throughout the whole page, so not just inside the loaded HTML (my goal).
What I want to do with the editor is when a client clicks on an element that represents something in the database, the info of this element will popup and the user will be able to edit this. (So, if a user hovers over a form with the class "contact-form" (which is in the database, connected to the loaded page) a new window will popup with information about this specific form element.
Also, I cannot completely disable Javascript, since the loaded HTML might contain Javascript for styling etc.
My goal: Remove Javascript, that can be annoying when a user loads in an HTML file. Like an alert(); Also, remove the ability for the Javascript to edit somehthing outside it's own DOM.
P.S. I am open to better workarounds like using an iframe for this, BUT I want to be able to hover over elements in interact with them.
Edit: It seems that this question might be a bit too broad, looking at the comments. Summary of my question: How can I disable alert() for a specific div and how can I create a sandbox so that code inside a div, can only change elements from inside that div.
What you're looking for is HTML sanitization. This is the process by which you remove any dangerous content from a snippet of HTML on the server, before it's loaded in the browser. There are plenty of sanitization libraries out there that can strip script tags, object tags, etc. Just remember, you can't sanitize using javascript because by the time you've injected your script, another malicious script may have already loaded and run.
The only way to effectively sandbox a javascript environment is with iframes. You'll notice that websites like CodePen, JSBin and JSFiddle use them extensively. There's something called the ShadowDOM, which is the basis of Web Components, but it isn't very well supported yet.
To make it possible to run your own frontend scripts that allow for hovering, you can inject your script after your sanitization process. This way, if it's loaded inside an iframe your script will also be loaded.
Finally, alert() doesn't belong to any elements on the DOM. You can trigger an alert as soon as the page loads, for example. However, if you're trying to prevent alerts from popping up on user interactions, you could try removing all event listeners from a particular element. This won't be necessary if you sanitize the HTML of script tags, however, since the script wouldn't have had a chance to load so there won't be any event listeners.
You can use ShadowDOM to load an html document into a host node. See also WHY SHADOW DOM?

Why should I need to add jQueryMobile Script only after all other scripts?

If I add any other scripts after JQM script then my page doesn't work properly.
Also according to Jqm docs I must include jQM script at the end of other scripts.
What's the reason behind it ?
Thanks
First, this is not always the case, but there are some situations when this is necessary. Any plugin than can cause a change to the page content loaded into the DOM must be initialized before jQuery Mobile. Best example is jQuery UI.
To understand this you need to understand how jQuery Mobile works. When jQM initialize it load's everything into the DOM. Even then process is not over because when content is loaded then jQM starts a markup enhancement process (custom widget styling). This process should not be tempered with because it could cause problems with widgets initialization.
One more thing, if jQuery Mobile detects something else is messing with a DOM content during the page initialization it will stop the process and ajax page loader will be shown.

How to test whether a page has been "pagecreated" in Jquery Mobile?

I have a two page application. Both pages have all content created dynamically on the client.
Problem is, if I go page A > page B > page A > page B, on the second+ visit, page B does not get enhanced by Jquery Mobile anymore, although pagecreate triggers correctly. I'm stuck with a page of un-enhanced markup.
I can't call create on the separate widgets of the page, because widgets will be of random type and because I cannot call create prior to initialization. After receiving this error I called pagecreate manually on the un-enhanced page, which fixed all widgets.
Problem is, how can I detect if the page has been enhanced by JQM? Because I don't want to call this on an already enhanced page.
So, seemingly easy question:
How can I test if a page has been enhanced by Jquery Mobile?
Thanks for inputs!
It is pretty simple.
In case you were using trigger('pagecreate') to enhance page markup then use this to check if page container has been enhanced:
$(document).on('pagebeforeshow', '#index', function(){
alert($.mobile.activePage.hasClass('ui-page'));
});
Live example: http://jsfiddle.net/Gajotres/HthYd/
In case you are using trigger('create') to enhance only page content div use this to check if content container has been enhanced:
$(document).on('pagebeforeshow', '#index', function(){
alert($.mobile.activePage.find('[data-role="content"]').hasClass('ui-content'));
});
Live example: http://jsfiddle.net/Gajotres/8jcGb/
Of course, this cases will work only in case you are enhancing whole page or whole content.
EDIT :
And here's a real live example with a dynamically added page: http://jsfiddle.net/Gajotres/8jcGb/

Preventing CSS of Jquery Dialog content from being applied to main window

In my web application, I have written a cross-domain ajax call which is fetching an HTML page from a different domain. This newly fetched page is being rendered in a jQuery dialog using the following code $('#previewDialog').html(response).dialog('open');
This renders the response properly in the dialog. However, the response (HTML page) also has some CSS styles in it. These styles (generally BODY, INPUT etc) are getting applied to my main window (parent page) and distorting the complete view of the page.
When the dialog with the HTML page opens, the view of the parent page is completely distorted because of the CSS used in the HTML page (response of AJAX call) which gets applied to all the components. And when I close the Dialog, the parent page gets back into shape.
Is there anyway, by which I can prevent the CSS of the HTML page which is being displayed in dialog, not get applied to my parent page?
Trivial answer: have everything from the page that you pull in be wrapped in a div with a class not used elsewhere. modify the .css for that page so that it only applies to elements within a div of that class.
Edit: If you cannot control the css of the origin page, things become somewhat more complicated. your problem, though, is that you're injecting the HTML (including the css link) directly into your page. Instead, try the following:
Grab the HTML for the other page. Place it into a div off to the side that you're not using for anything else using the html() command.
Go into that div using the jquery DOM commands. Grab the portion of the page inside of the troublesome links, and pull it over to the $('#previewDialog') location. Destroy the contents of the working space div. If there is javascript or css that you need to preserve, have it entered (modified, if necessary - like with div wrappers) elsewhere in the page.
Now, this only works if the pages that you're being fed don't have their css or javascript changing with any frequency.
An alternate version of the same thing - while you have it as a response (a string format) use string manipulation tools to excise the css reference, rather than using DOM commands to pull what you need out of it.
More complicated/difficult version of the same thing (though somewhat more robust): Use string commands to slice out the css references (as with the alternate version) and then make another call using that css reference to acquire the .css file. Use string commands on the .css file to add in the div-wrapper limits as initially described, then insert it elsewhere on the page as an internal style sheet.

Twitter social box delay page loading - how to async it?

Twitter generates me box code to insert on page: http://pastebin.com/5TgkL5vP but on slow connection it prevent page from loading. Is there any way to add "Loading..." and make it async? (I know about iframe but its awful way)
There is a solution in here;
http://od-eon.com/blogs/stefan/asynchronous-loading-twitter-widgets/
$(window).load(function(){
$.getScript('http://widgets.twimg.com/j/2/widget.js', function(){
$.getScript('/media/js/twitter.js', function(){
$('#twtr-widget-1').appendTo('#twitter_p')
})
})
})
To delay the loading of the twitter widget you could load it after your whole page is loaded. You could use the window's onload event handler to start loading the twitter widget once your page has been downloaded.
Or you could use a javascript library (like jquery) to run that code once you HTML is loaded but images and CSS and other assets are still loading: jquery's .ready() method does just that.
In case you don't want to use bare javascript (although recommended for learning) jquery (like others) does provide a .load() event that behaves just like the onload example on W3c.
In any case, with any of those two methods you could place a "loading..." text in a placeholder and then replace it with the widget once it's loaded.
You should try experimenting with both and see which one produces the best perceived results. Sometimes you want the page's content to load blazingly fast, in that case you should hold all external content from being loaded until the content is loaded (using onload or .load()), while sometimes you want everything to be loaded more or less at the same time (using .ready()).
I hope it didn't come out backwards :D.
The solution explain by od-eon.com is OK but for IE the CSS is not correctly added because it tries to add CSS in a window onload event. This event is fired asynchronously so no CSS is added.
The line $('#twtr-widget-1').appendTo('#twitter_p') is not useful.
You must not add a CSS position attribute to the div which will contain the box because nothing is displayed in this case. If you want to add this box in an absolute div you must add an empty div in it and pass the div's id in parameter.

Categories