This might be a simple question for geeks, but not for me, at least. I was developing a simple XUL program from scratch. I used wizard tag to simplify the GUI that appears to the user. On a wizard page I have inserted a progressmeter to show the progress of a function called myFunction() which belongs to the JavaScript which is available in the XUL file. How can I properly update the progressmeter based on the real progress of the function?
Yes, the reverse thread work round does work, but as per the doc (here: https://developer.mozilla.org/en/nsIThread) processNextEvent may wait for a very long time if there are no pending events! Err.. since xulrunner is single thread there appear to be few, resulting in a huge slow down. Waggling the mouse helps though.
On further investigation use processNextEvent(false) works without delay.
Have you tried setting the progression of the progressmeter using its "value" property?
myProgressmeter.value = 50;
You just need to increment this value depending on the progression of your function.
Note that the value should be set between 0 and myProgressmeter.max
Related
I have inherited a third party Javascript - it's about 7000 lines when de-minified - that I need to use to open and close a panel of content when a link is clicked. It works fine when I import the HTML and js file to a content module in my CMS (DNN) but has the unfortunate side effect of breaking the bootstrap hamburger menu when the page is viewed on a mobile device.
I have neither the time nor JS skill to work out exactly how 7000 lines of script work, which bits I actually need and then adjust them so they only do what I need them to and not impact on the menu.
What I am hoping is that there is some way I can wrap the entire script so that it only applies to a specific area of the HTML and not to the menu area. I can easily assign an ID to the div that contains the code where I want it to operate.
So is there was way to do this - a way of testing at the start of the script that the current element matches the ID I assign, if it does then enable all functions in the entire script and if not then do nothing?
Update after reading initial replies...
The offending code can be seen at https://dnnplaypen.epicservices.com.au/application
The JS file (unminified version) can be found at https://dnnplaypen.epicservices.com.au/portals/0/scripts/main.unmin.js - I believe it may in fact be a complete BootStrap JS implementation which possibly explains the conflict.
and this is the relevant section of the HTML...
View them.</p>
<div id="MemberTypes" class="collapse">
<p style="margin-left:20px;"><img src="/portals/0/Images/OrangeDot.png"> <span style="font-weight:bold">Civil Intrastructure (CIM) Entrant</span></p>
<p style="margin-left:40px;">(Works in the civil industry and either supervises 1 or more people or has a civil university qualification e.g. leading hands, site supervisors, engineers, project managers, CEOs)</p>
<p style="margin-left:40px;">You’ll answer some questions about your qualification & employment details to confirm your eligibility.</p>
<p style="margin-left:20px;"><img src="/portals/0/Images/OrangeDot.png"> <span style="font-weight:bold">Student</span></p>
<p style="margin-left:40px;">(Studying civil-related course at university at least 50% of the time)</p><p style="margin-left:40px;">Please have current enrolment document(s) as evidence.</p>
<p style="margin-left:20px;"><img src="/portals/0/Images/OrangeDot.png"> <span style="font-weight:bold">Affiliate</span></p><p style="margin-left:40px;">i.e. Part of the supply chain servicing the industry</p>
</div>
Any assistance in identifying which part of the JS is invoked when the link is clicked would be much appreciated.
Possibly.
First, opening and closing an element on a click shouldn't take even 7 lines of code, let alone 7000. Refusing to look into that code is dereliction. Just throwing it into an app without knowing what it does is irresponsible.
Second, your best bet may be to use DevTools to trace the click event. In Chrome you open the Sources panel, and in Firefox you open the Debugger panel. On the right side, near the top, there is a pause icon. Click that, then click the part of the webpage that toggles the content. If you're lucky, the debugger will halt execution on the first statement in the toggle codepath, which you can and should step through.
Third, the strategy we'll use is to wrap the entire block of code inside a function that exposes a fake version of the DOM API. This 7k block of mystery code is ultimately using some of the basic DOM methods to identify and manipulate the relevant elements. Your goal will be to create a fake version of that API that only returns the specific element you care about. You'll add an ID or other identifying attribute to the element in question, and then return that element whenever the mystery code invokes your API (which it will think is the real API).
Here is a simple example:
// first, get our hands on the one element you want the mystery code to see
const elementThatShouldToggle = document.getElementById('target-element')
// second, construct an object that provides methods with the same names as what the real document provides
const fakeDOM = {
// normally, document.getElementById takes an argument
// your fake version will ignore that arg and just return the content el
getElementById: () => elementThatShouldToggle,
// you may need to mock several DOM accessor methods
querySelector: () => elementThatShouldToggle,
querySelectorAll: () => [elementThatShouldToggle]
}
// third: wrap the mystery code in a function that uses variable shadowing to obscure the real DOM, substituting your fake DOM instead
(function sandbox(document) {
/* paste the 7000 lines of mystery code here */
})(fakeDOM)
There are drawbacks to this approach:
You'll need to create fake versions of every DOM method that the mystery code uses; this will require you to run the app several times and look for exceptions. For every exception, you'll need to study the stack trace to identify any DOM methods that are implicated, and then create mocks that return safe values.
If the mystery code uses the same DOM methods as the code you like, your fake API implementations will have to be a little smarter. You may need to set up branching behavior in your fake methods that return the real elements in some cases, and safe values for all other cases. Again, this will be a guess-and-test affair.
Once the mystery code has its hands on a real DOM node, it can use the API on that node to access the entire rest of the document. It's probably not an evolving threat, so it's probably enough to then also mock the DOMNode API on the element that you provide to the mystery code.
There may be calls inside the mystery code that does scary or bad things but without using the APIs that you're studying. If you do nothing to detect or prevent that, then the bad stuff will happen, and injecting this code into your app will inject the bad stuff, too.
How will you know when you've done enough guessing and testing? Well, because you refuse to study the 7000 lines of code, there's really no way to be sure. For all we know, there's a setTimeout buried in there that does something really interesting after 45 minutes. The only way to figure that out would be to wait for 45 minutes.
With this mocking strategy, it is guaranteed that you will write far more new code than if you just wrote your own toggle script. This is hard mode. It will be complicated, tedious, brittle, and even after all of that it will not provide the guarantee that you want.
A better approach would be to use the debugger to study the codepath that gets invoked on click, and then extract that code or write a replacement. Toggling some content is generally a near-trivial task. If you need help doing that, there are countless tutorials online, no doubt including some Q&As here on SO.
I'm currently implementing a system for running build process remotely from browser. One of the tasks is to display build console output which downloads partially by ajax. And here I've faced the problem: I'm trying to output this log to textarea control and the log is quite heavy (may reach 12Mb and more depending on how many targets are building). My concern is about a compatibility of textarea with my requirements. I'm beginning to suspect this is not the best way of displaying so huge amount of info since I've been trying different approaches for appending data to textarea:
<textarea id='log'></textarea>
//using jQuery
$("#log").append(data["log"]); <- data["log"] is ajax result
//or classic JS
document.getElementById("log").value += data["log"]
the result is always the same: as larger textarea content as longer UI lags (it may entirely freeze for a second or two). Any ideas would be appreciated.
http://jsfiddle.net/93bexk59/
Hey,
basically - don't use textarea and minimize amount of dom manipulations.
What you can do?
1 Use documentFragment API to build parts of DOM out of it
2 Cache data which passes from ajax and drop it on page every N-th items
3 Render the things using async calls, not immediately.
setTimeout(function(){
//some render here
}, 0)
I've attached an example (jsfiddle).
Hope I understand you correctly, and with this approach (list instead of textarea you have more customization options).
I am working on a simple Cordova app with about 4 page types and I am trying to think through which is the better way to handle the inner HTML templates.
Hidden HTML hard coded into the HTML files that is hidden and populated/revealed by my JS.
Using a JS template system and appending and removing from the DOM.
I feel that appending all that to the DOM for a page is inefficient when I could just update the sections that change. But perhaps an append is lightweight enough where I shouldn't worry about it.
There are a number of ways you can do it. In terms of load on the browser. That is hard to say. From your question it is hard to know what is in these pages, what are you displaying, is it live data, static html etc.
When you first plot out an app, if you are from the old class of building multiple page websites, it can be a little concerning as to how well your app/page will run with all those pages crammed in to one, and all that data plus code.
The answer is, amazingly well. If done properly in modern browsers, and for example Ipads the app will run to near native performance.
The options you have are
Map all the pages into one HTML document. Hide each page content using css display:none, flip them into view using css animation, fading or just display:block.
Use a javascript routing library to map urls to blocks of code that deal with each page, this makes mapping out your app much easier, and means that buttons can just link to your pages, like a real website. see http://projects.jga.me/routie/
Building all the page templates into one page can make it hard to code, as the page becomes enormous, consider breaking the inner content of each page into separate files, you can then give each page holder a url and use a small xhr request to load the page on-the fly, once loaded you can cache it into memory or even local-storage, depending on whether you remove it when it is closed or keep it hidden.
In my experience you can put an enormous number or nodes into one page and have very little speed drop, bear in mind if you use something like jquery and do a lot of $(".page > .page1 > .items li") your going to have a slow app.
Tips
Use element ID's everywhere document.getElementById(..) is 100's of times faster in a loop that $(...)
cache elements when you find them, if you need them later store them in a memory cache.
keep for loop inner code to a minimum.
use a decent click touch libary like http://hammerjs.github.io/ and delegate all the events of the body tag or at least on each page.
If you need to touch the server, load data, think dom first, device second server later. A good app is a responsive app, that responds to the user instantly.
I know this has been posted a while ago, but for the sake of the users I am going to add my answer.
I completely agree with MartinWebb but my answer will shed some light on the results of his options. I am currently working on a similar project. Please note that this answer pertains to cordova (previously called phonegap) specifically. My app has about 5 pages with +-20 different components (input's, div's, h1's, p's, etc.). This is what i tried and the result of each:
jQuery was my first option, mainly because it is easy to use and reduces the amount of code required to accomplish a said goal. Result: First time I tried this approach I though I would spice it up with animations and transformations. The result of this was a very unresponsive app. I removed the animation and transformation, however due to the nature of my application I required multiple dynamically added components and jQuery just wasn't up for the task.
Css display:none and visible:hidden was my next option. I used javascript's dom to display certain div's. Result: This works if your not planning on switching many div shortly after one another eg. a simple menu. It quickly became apparent that this wasn't going to work. Also this does not eliminate my need for the dom. Remember document.getElementById('menu').style.display = "none"; is still part of the dom. This as a solution, for me, is poor. There is a reason that var menu= document.createElement('div'); is part of the language. Which brings me to my last option.
Building a page 90% on javascript's dom was my last option. Logically I could not see how 600 lines of code cold trump one .innerHTML or .style.display = "block"; but it did. Result: It was by far the most responsive of all the solutions.
I'm not saying that all webpages should be coded with dom appending, but as I stated previously, for a cordova app of a few pages (<6), with a few components a javascript dom appending approach would be best. It takes longer to code, but you will be rewarded with control and efficiency. I would suggest coding the backbone of your app in html and populating and controlling with javascript's dom.
Best of luck.
The first option, <div>s with display:none; would be more efficient by a small margin, but you can get the best of both worlds by compiling your JavaScript and templates together into a single file using something like browserify or require.js.
I am building an ajax based website, where almost every page has it's own Javascript file which is being loaded along with html.
I have couple questions if I'm doing things in a right way, so let's get started :)
First of all, the way I execute the loaded script. All of my code is encapsulated in a function, so say I have loaded the register page, what i would do is:
page_class = "register"; //this will change when new page is loaded
new window[page_class];
So this works the way I want it to work, but I'm concerned about one thing, when the user comes back from the other page to register one more time and new object are going to be created one more time will it create memory leaks or some other bad things? If so what can I do to rerun my whole script?
My next question is fairly simple, I attach my jquery events using on and when I switch the page I loop through all elements that will be removed and detach every element, is that enough to prevent memory leaks? If not what could i improve?
So considering what we've figured out from the comments, here's my 2 cents:
I would suggest making your site sectionally ajaxed. By that I mean all music areas as one subsection, videos in another, etc. So within each section you ajax around and when transitioning to another section you gracefully fade and naturally page load the next.
.detach() in my opinion is not enough to ensure proper memory handling since detach keeps the removed section referenced. Good for when you want to recall it but useless if the user just clicked an area and backed out never to return. Now you have this reference to an entire section stored in memory.
How to handle memory in each section? You can maintain section objects. An example:
var music = {
loaded: 0,
current_track: null,
init: function(){
if(this.loaded == 0)
{
$.ajax... get your music section html and write it to the #music element
this.loaded = 1;
}
},
selectTrack: function(id)
{
// just an example
}
};
while maintaining a constant site object:
var site = {
init: function(){
// call selected page, etc
},
move: function(page){
if(page == 'music')
{
music.init();
$('#content').animate(...);
}
}
};
$(document).ready(function(){
site.init();
});
Where the site obj is initted on page load and when the move function is called it calls the init method for the respective object, which does nothing if the page has already been loaded. This example obviously depends on there being a #music element as well as a container element called #content. This part could be totally irrelevant depending on how you handle transitions. All your call, but the general idea is the same. You can always set display to none to avoid rendering bottlenecks for complex markup.
You mentioned, at least briefly, that the project was expected to pretty big. Not to be too pessimistic, but "big" is defined after the fact and not in the plan. Unless you have millions of dollars to throw at this. I'm not trying to dissuade you. By all means, make your site as you expect it to be. But consider that scaling up when demand calls is a much more sane approach than going full throttle fancy before anyone knows about it.
I only say this because I've worked for clients who have thrown millions into the gig claiming it will be the next youtube and 6 months later they were gone. Where they focused on stability and security, they failed in design and marketing. That - and pretty much that alone - is why I suggest making only sections ajaxed. It keeps it compartmentalized, the focus is easy to keep track of and you only have that one piece to worry about. When you get 10,000 users, consider going full ajax. When you get there you may also know why it might be a better move to consider ipads and tablets over a fancy ajax site. Your cool transitions and fades will be a wounded dog on mobile devices. Considering the direction things are going, is that what you want?
Again, this is only my opinion. I don't know your site or skill set or even whether or not you have already considered all I mentioned. If you have any specific questions I can try to answer or update this post.
Good luck.
Regarding the js options mentioned:
Standard jquery will likely suffice, unless you have time to fully understand something like bootstrap
Node.js is awesome but you need to make sure your server can deploy it. Dreamhost, for example, does not support it. At least they didn't last I checked. They're a good example of a decent, common host. Same for Media Temple, I think. Please correct me if I'm wrong.
Suppose you have a webpage that keeps refreshing, like so - how can you display a text-counter that counts to 10 ?
Keep the value in a cookie, or use HTML5 local DB stuff.
Simple javascript would work.
use the function setinterval() to run some code (you can chose the time interval in miliseconds).
An example of this is here:
http://www.w3schools.com/jsref/met_win_setinterval.asp
Combine this with the getElementById function
document.getElementById('my_div').innerHTML = a_variable;
and a div like so
<div id="my_div"></div>
(or instead of the div update a text input box like on the w3 example)
I've refrained from writing the code for you, but writing it should be good practice and more valuable for you.
P.S. Iam & Dave answered the question which was posed in your title - the title is slightly inaccurate. Better would be "In JavaScript how would you change the inner html of the body of a webpage at regular intervals"
You should use cookies because they are pressistant and you will be able to use the as much as you need , here is the link on how to use them.
I would suggest you if you are using any server side language you would be able to use Session or Cache object to preserve the values, in the end you will be able to use HTML5 Local DB.