Blocking UI on document ready - javascript

I'm working on a web application which needs to be compatible with Internet Explorer 8 (you know, compatible with the HELL). The thing is that I´m uploading a file which later is processed by a PHP code and refresh the page. When I have a processed file I used that file to insert data into a table, so I need a processbar and block UI while I insert this data (I need to call another PHP process for each row)
The problem is the next one, I want to block that UI, I have the logic and all compatibility problems solved; but after 5 days of work, I can´t block UI. This is a minimum code (which encapsulate all we need) in order to simplify the idea:
$(document).ready({
(...)
$("#title").html('some text');
$("#bar").html('');
$.blockUI({message: $('#window'),css:{width:'303px'}});
go = true;
while (go){
$.ajax({<ASYNC FALSE AJAX CALL});
if (!file.lines) go = false;
<update progress>
}
$.unblockUI();
(...)
});
Obviously, the $.blockUI should block main thread (until I unblocks) and show a personalized window, which have the next code is:
<div id="window" style="display: none; cursor: default">
<div id="title_bar">
<div id="titulos">some text</div>
<div id="cerrar"></div>
</div>
<div id="body">
<img src="an icon"
alt="enviando" border="0" width="33" height="33" id="enviar">
<p class="titulo" id='title'></p>
<p class="texto" id='bar'></p>
<br />
</div>
</div>
I think the problem is that I´m executing that block on a thread which is not main thread, and i cant really blocks UI; but I need that block because I have to force the user to wait until I process all of the information.
Thank guys, I hope you could help me with this.

I think mostly because of synchronous, but if you make it async you need make the changes in your code. Remove while-loop and invoke a function, that will make an async call and on successful completion invoke the same function recursively. Once your terminal condition is met, unblock the UI as below:
$.blockUI({message: $('#window'),css:{width:'303px'}});
// based on the above code I assume you will get file as a response.
process();
function process(file){
if (file && !file.lines){
$.unblockUI();
}
$.ajax({<ASYNC TRUE AJAX CALL})
.done(function(file){
<update progress>
process(file);
});
}

Related

Proper way to handle ajax HTML block

So I was wondering what is the "spec" or "proper" way to handle HTML that is used via ajax.
For example, should I keep all the HTML in the actual page that is using it? Or should I just an ajax call to load it in?
Is there performance increase in keeping it loaded in the page since its one less load? Or does loading that extra data at page load off-set it.
Here is a screenshot illustrating what I mean.. You can see the {name} which is changed depending on what the user provide (limited characters of course).
Any help/opinion is appreciated! Thanks!
Partial source for those asking:
<!-- text field -->
<div class="add-field-wrapper float-left">
<input type="radio" value="text" name="input_type" id="rad-type-text" class="type-radio-btn">
<label for="rad-type-text" class="radio-lbl" data-tooltip="Used for simple inputs such as: <b>Phone Number</b> or <b>Email Address</b>">
<img src="https://placeholdit.imgix.net/~text?txtsize=16&txt=70x70&w=70&h=70" class="field-type-icon" />
<div class="field-type-text">Text Field</div>
</label>
</div>
<!-- select -->
<div class="add-field-wrapper float-left">
<input type="radio" value="select" name="input_type" id="rad-type-select" class="type-radio-btn">
<label for="rad-type-select" class="radio-lbl" data-tooltip="Use this option when you need to provide a list of choices for the user." >
<img src="https://placeholdit.imgix.net/~text?txtsize=16&txt=70x70&w=70&h=70" class="field-type-icon" />
<div class="field-type-text">Select Menu</div>
</label>
</div>
<!-- textarea -->
<div class="add-field-wrapper float-left">
<input type="radio" value="textarea" name="input_type" id="rad-type-textarea" class="type-radio-btn">
<label for="rad-type-textarea" class="radio-lbl" data-tooltip="The textarea field will appear as a <b>WYSIWIG</b> (What you see is what you get) editor. This allows for some customization of the appearance of the input.">
<img src="https://placeholdit.imgix.net/~text?txtsize=16&txt=70x70&w=70&h=70" class="field-type-icon" />
<div class="field-type-text">Text Area</div>
</label>
</div>
Edit:
<!-- Datepicker HTML block - used in JS -->
<div id="datepicker_html" style="display: none;">
<div id="{name}-block" class="datepicker-wrapper form-input-wrapper">
<div class="template-drag-handle"><img src="images/design/up-down-icon.png" class="template-drag-handle-icon" alt="Drag" /></div>
<div class="inputs-wrapper">
<div class="form-row"><input type="text" name="{name}" class="input-datepicker" placeholder="{placeholder}" id="{name}"/></div>
</div>
<?php echo $default_template_chkbox_options_html; ?>
</div>
</div>
That's a "piece" of the html.. it gets loaded into a JS variable:
This is what processes it -- adds the name, changes the placeholder (these can be reused as many times as you want)
function addDatePickerField(){
//Get the HTML
var datepicker_html = $('#datepicker_html').html();
datepicker_html = datepicker_html.replaceAll(/{name}/g, input_name_underscores);
datepicker_html = datepicker_html.replaceAll('{placeholder}', input_name);
$('#template-fields-wrapper').append(datepicker_html);
wrapUpAddInput('datepicker');
}
I just didnt now it if would be better to do an ajax call, store the "external" html and call it in when I need it -- Like, that datepicker HTML block, would be store in separate file, then on a link, load into the DOM.
I will try to address your question, even though it's a very broad one.
Generally, loading your content (e.g. HTML) dynamically via an ajax request does not always give you a performance boost, it really depends what you are doing and trying to achieve.
Should you always pre-load all of your HTML content with the initial request ? Or should you ajax load a portion of it after the page is already loaded on screen ? that is solely depends on your application and needs.
I will explain by an example:
Assuming I am developing a content site, which will be mainly content oriented (e.g articles) and will be served from traditional web browsers (desktop or mobile) then loading my articles for each page via ajax might not be a good idea, with very few rare exceptions.
On the other hand-
If I am developing a web application that needs to send and receive blocks of data in "real time", a project that contains a rich UI which has to have a rich and "enterprise"-like experience where stuff is being executed, updated and displayed on-the-fly smoothly without having to refresh and re-load my application page every time I am saving my work or executing an operation - I will certainly use ajax requests for handling some of that work.
Another aspect is the overall loading time of your page:
Some web-sites are loading some of their HTML via ajax after the page body is loaded - by doing this they are reducing the perceived loading-time of the page, by "perceived" I mean - to the user, it appears to load faster since the partial page is loading almost instantly, and then some blocks inside of the page are loading async via ajax.
Like i've said, this is a very broad question and there are many methods to learn and investigate to finally see what works best for your specific needs.
Good luck

Calling server-side script within a sidebar GAS

I am trying to call another sidebar within a different sidebar to create a sort of tabbed interface in google docs. I cannot figure out how to call the server-side function that displays the new sidebar within the html file of the present sidebar.
Here is my html sidebar button layout...(doesn't work)
<div id='menu'>
<button class="action" id="functions_nav">Functions</button>
<button class="action" id="navbar">NavBar</button>
<button class="action" id="settings" onClick="google.script.run.showSettings()">Settings</button>
</div>
and my gs file...
function showSettings() {
var html = HtmlService.createHtmlOutputFromFile('settings')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setTitle('DebateDocs')
.setWidth(300);
DocumentApp.getUi() // Or DocumentApp or FormApp.
.showSidebar(html);
}
The documentation on google deals with calling the buttons via "input type="button"..." however that will screw with my styling. Additionally they always call the scripts within javascript "script" tags. Is there some way I can route the button to a javascript event within the html file that points to the server?
Thanks for your help! Any is appreciated.
your code is working fine for me.
The IFRAME Sandbox mode is new and has some bugs, try removing it or setting to NATIVE.
Also please share if you can find any error if you see the execution transcript.
Cheers.
PS: Sorry, I know this should be inserted as a comment, but don't yet have reputation to do so :(
You don't need to call the .gs script directly from a button. You can use this configuration.
Button
<div id='menu'>
<button class="action" id="settings" onClick="fncShowSettings()">Settings</button>
</div>
HTML Script Tag
<script>
window.fncShowSettings=function(){
console.log("fncShowSettings ran");
google.script.run
.showSettings(); //Runs server side .gs function
</script>
Code.gs
function showSettings() {
Code here . . .
return someValue;
};
I'm not clear as to what you are asking, so if this doesn't help, just leave a comment.

How to prevent ngInfiniteScroll from being triggered multiple times after the initial trigger?

I am using ngInfiniteScroll to enable infinite scrolling on my website. It works partly as expected, once I scroll to the bottom of the page it calls the method I want it to call to show more posts, except that it keeps calling posts without end after it is triggered once. Does anybody know what could be causing this? This is what my code looks like where I am implementing ngInfiniteScroll, I don't know that this specific code will help much though. I suspect it is getting thrown off by code in another file.
<div style="height: 1px">
<post post-item="item" feed-items="items.feed" feed-name="feedName" ng-repeat="item in items.feed"> </post>
<div ng-if="items.feed.length == 0 && !initialLoad">
<div class="empty-message">Your feed is currently empty, visit the Users page and find some more people to follow!</div>
</div>
<a infinite-scroll="nextPosts()" infinite-scroll-distance="1" href ng-click="nextPosts()" class="show-more">Show more </a>
</div>
Example
You can use the infinite-scroll-disabled directive of ngInfiniteScroll to tell it to NOT load data if a call is already in progress.
E.g.
<div infinite-scroll='loadMore()' infinite-scroll-disabled='busyLoadingData' infinite-scroll-distance='1'>
<p ng-repeat='item in items'>Some data</p>
</div>
JS:
$scope.busyLoadingData = false;
$scope.loadMore = function () {
if ($scope.busyLoadingData) return;
$scope.busyLoadingData = true;
// $http call to get next set of data
// on the .success() callback do $scope.busyLoadingData = false;
}

JQuery maximum .load calls?

I am using the LiquidSlider framework and in each tab there is lots of HTML. So I decided to put the HTML into separate .html files to make the main page index.html cleaner.
Here is my HTML:
..
<head>
.. <-- Import jquery, slider files, etc -->
<!-- Import HTML from other files into divs -->
<script>
$(function(){
$("#about-content").load("about.html");
$("#other-content").load("other.html");
$("#help-content").load("help.html");
$("#contact-content").load("contact.html");
});
</script>
</head>
<body>
<section id="navigation">
..
</section>
<div class="liquid-slider" id="main-slider">
<!-- About -->
<div>
<h2 class="title">about</h2>
<div id="about-content"></div>
</div>
<!-- Other -->
<div>
<h2 class="title">other</h2>
<div id="other-content"></div>
</div>
<!-- Help -->
<div>
<h2 class="title">help</h2>
<div id="help-content"></div>
</div>
<!-- Contact -->
<div>
<h2 class="title">contact</h2>
<div id="contact-content"></div>
</div>
</div>
<section id="footer">
..
</section>
</body>
..
So when the document is loaded, theoretically the HTML would be loaded in via the .load calls right? It seems to work fine, until it gets to the very last tab (contact), where it just fails to load any content..
Odd right? I tried moving the divs around to see if it was a problem with my html files, but the last element always fails to load. Then I tried adding another tab, and the last two fail to load. This leads me to believe there is an upper-limit to the number of .load calls, capped at 3?
Anyone have any ideas or see any obvious problems? Or even suggest any better ways of achieving the same thing?
Thanks.
RTM, there's nothing there about a max number of calls, but there's a lot of information (and examples) of what kinds of callbacks you can use, which might just help you to diagnose the problem itself, for example:
$("#contact-content").load("contact.html", function( response, status, xhr )
{
if ( status == "error" )
{
var msg = "Sorry but there was an error: ";
console.log(xhr);//<-- check this
$( "#error" ).html( msg + xhr.status + " " + xhr.statusText );
}
});
As an alternative, just go for the old-school $.get call, since you don't seem to be passing any data to the server:
$.get( "contact.html", function( data )
{
$("#contact-content").html(data);
});
Another thing to consider might be: given that you're using liquidSlider, I take it not all of the content is visible from the off. Why not register a click handler, that .load's that content when the user actually clicks something? That does away with that series of load calls... Perhaps it's a concurrency issue of sorts. By that I mean: browsers restrict the number of concurrent AJAX requests that can be made.Perhaps you're running into that restriction, and have to wait for the requests to be completed? It's a long shot, but you never know... If you want to, check your browser here
But either way, using JS to fetch parts of the content dynamically is all well and good, but remember that I can switch off JS support in my browser. Or that, if your JS contains a syntax error, the script execution grinds to a halt, leaving me with a (half) empty page to gaze at.
Just using any server-side scripting language seems to me to be a better fit:
//index.php -- using PHP as an example
<div id="contact-content"><?php include 'contact.html'; ?></div>
After this gets processed by PHP, the response from the server will be a fully-fledged html page, that doesn't require any JS-on-the-fly loading. It'll almost certainly perform better, and still allows for cleaner html code on your server...
Server Side Includes would seem to me to be a better way of achieving the same thing. Use the right tool for the right job and all that.
<script>
var array = ['about', 'other', 'contact', 'help'];
for (i in array)
{
$('#'+array[i]).load(array[i]+'.html', function(){ });
}
</script>

template insertion in a editor

Describing a scenario:
I am going through the code mentioned below.B asically I am trying to figure out how to program so that
when a user clicks on "Use Template" button , it gets inserted into an editor.
Page 1:
There are lot of templates present
When a user clicks on the "Use Template" button on , it gets inserted into an editor that is present in
the next page (Page 2).
Please find the code snippet below for the first two templates I am going through:
<div id="templatesWrap">
<div class="template" data-templatelocation="templateone" data-templatename="Template ONE" data-templateid="" >
<div class="templateContainer">
<span>
<a href="https://app.abc.com/pqr/core/compose/message/create?token=c1564e8e3cd11bc4t546b587jan31&sMessageTemplateId=templateone&sHubId=&goalComplete=200" title="Use Template">
<img class="thumbnail" src="templatefiles/thumbnail_010.jpg" alt="templateone">
</a>
</span>
<div class="templateName">Template ONE</div>
<p>
Use Template
</p>
</div>
</div>
<div class="template" data-templatelocation="templatetwo" data-templatename="Template TWO" data-templateid="" >
<div class="templateContainer">
<span>
<a href="https://app.abc.com/pqr/core/compose/message/create?token=c1564e8e3cd11bc4t546b587jan31&sMessageTemplateId=templatetwo&sHubId=&goalComplete=200" title="Use Template">
<img class="thumbnail" src="templatefiles/thumbnail_011.jpg" alt="templatetwo">
</a>
</span>
<div class="templateName">Template TWO</div>
<p>
Use Template
</p>
</div>
</div>
And so on ....
How does the link "https://app.abc.com/pqr/core/compose/message/create?token=c1564e8e3cd11bc4t546b587jan31&sMessageTemplateId=templatetwo&sHubId=&goalComplete=200" is inserting the template into the editor which is located on the next page? I haven't understood the token part and lot's of ID's present in the link
which I think are thereason behind inserting the template.
Has anyone come across such link before? Please advise.
Thanks
MORE CLARIFICATIONS:
Thanks for your answer.It did help me somewhat. I have few more questions:
Basically, I am using TinyMCE 4.0.8 version as my editor. The templates, I am using are from here:
https://github.com/mailchimp/email-blueprints/blob/master/templates/2col-1-2-leftsidebar.html
Some questions based on "Tivie" answer.
1) As you can see in the code for "2col-1-2-leftsidebar.html " it's not defined inside <div> tags unlike you defined it in <div> tags. Do you think that I can still
use it using "2col-1-2-leftsidebar.html " name?
2)I believe,for explanation purpose, you have included
`"<div contenteditable="true" id="myEditor">replaced stuff</div>`
and
<button id="btn">Load TPL</button>
<script>
$("#btn").click(function() {
$("#myEditor").load("template.html");
});
</script>
in the same page. Am I right? ( I understand you were trying to make an educated guess here, hence
just asking :) )
In my case, I have a separate page, where I have written code for buttons just like you wrote in editor.html like the following:
<button id="btn">Load TPL</button>. My button is defined inside <div class="templateContainer">.
Also, my templates are defined in a separate folder. So, I will have to grab the content(HTML Template), from
that folder and then insert into TinyMCE 4.08 editor. (Looks like two step process). Could you elaborate
on how should I proceed here?
More Question As of Dec 27
I have modifier my code for the template as follows:
<div class="templateName">Template ONE</div>
<p>
Use Template
</p>
Please note, I have added an additional id attribute for the following purpose.
If I go by the answer mentioned in the Tivia's post, is the following correct?
<script>
$("#temp1").click(function() {
$("#sTextBody").load("FolderURL/template.html");
});
</script>
My editor is defined like the following on Page 2 (Editor Page).
<div class="field">
<textarea id="sTextBody" name="sTextBody" style="width:948px; max-width:948px; height: 70%"></textarea>
</div>
I am confused, like, the script tag I have defined is in Page 1 where I have defined all the template related code
and the Page 2(Editor) page is a different page. It's simply taking me to Editor page (Page 2) and hence not working.
Please advise where I am wrong.
Thanks
MORE QUESTIONS AS of Jan 2
The problem Iam facing is as follows. Basically, for first template , I have the following code.
Code Snippet #1 where "Use "Template" button is present:
<div class="templateName">Template ONE</div>
<p>
Use Template
</p>
And the function suggested in the answer is as follows:
Code Snippet #2 where Editor is present:
<script>
$("#temp1").click(function() {
$("#sTextBody").load("FolderURL/template.html");
});
</script>
Since, I believe I first need to reach to that page after user clicks on "Use Template" button, where the editor is located, I have defined Code Snippet #1 on Page 1 and have defined the Code Snippet #2 and <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> as the very first two script tags in the Page 2 ( Editor Page). But still when I click on "User Template" button on Page 1, it's just letting me to next page and not loading the template into the editor.
Am I doing something wrong here? Please advise.
P.S. The problem I feel is somehow the click function on Page 2 is not getting activated with the temp1 id button mentioned on Page 1.
Thanks
Well, one can only guess without having access to the page itself (and it's source code). I can, however, make an educated guess on how it works.
The URL params follows a pattern. First you have a token that is equal in all templates. This probably means the token does not have any relevance to the template mechanism itself. Maybe it's an authentication token or something. Not relevant though.
Then you have the template identification (templateOne, templateTwo, etc...) followed by a HubId that is empty. Lastly you have a goalComplete=200 which might correspond to the HTTP success code 200 (OK).
Based on this, my guess would be that they are probably using AJAX on the background, to fetch those templates from the server. Then, via JScript, those templates are inserted into the editor box itself.
Using JQuery, something like this is trivial. here's an example:
template.html
<div>
<h1>TEST</h1>
<span>This is a template</span>
</div>
editor.html
<!DOCTYPE HTML>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<div contenteditable="true" id="myEditor">
replaced stuff
</div>
<button id="btn">Load TPL</button>
<script>
$("#btn").click(function() {
$("#myEditor").load("template.html");
});
</script>
</body>
</html>
Edit:
1) Well, since those templates are quite complex and include CSS, you probably want to keep them separated from you editor page (or the template's CSS will mess up your page's css).
However, since you're using TinyMCE, it comes with a template manager built in, so you probably want to use that. Check this link here http://www.tinymce.com/wiki.php/Configuration:templates for documentation.
2) I think 1 answers your question but, just in case, my method above works for any page in any directory, provided it lives on the same domain. Example:
<script>
$("#btn").click(function() {
$("#myEditor").load("someDirectory/template.html");
});
</script>
I recomend you check this page for the specifics on using TinyMCE http://www.tinymce.com/wiki.php/Configuration:templates
EDIT2:
Let me explain the above code:
$("#btn").click(function() { });
This basically tells the browser to run the code inside the brackets when you click the element with an id="btn"
$("#myEditor").load("someDirectory/template.html");
This is an AJAX request (check the documentation here). It grabs the contents of someDirectory/template.html and places them inside the element whose id="myEditor"

Categories

Resources