I am trying to use iscroll4 in my IOS app development with cordova 2.1.0.
<script type="application/javascript" src="iscroll.js"></script>
<script type="text/javascript">
var myScroll;
function loaded() {
setTimeout(function () {
myScroll = new iScroll('wrapper');
}, 100);
}
window.addEventListener('load', loaded, false);
</script>
If i want to edit the parameters like vScroll , vScrollBar,fixedScrollbar etc. dynamically ie. after the initialisation of iscroll(myScroll = new iScroll('wrapper');), how can i do it in javascript.
Thanks in advance.
I wouldn't try to look for an 'works in every situation'-solution.
I would:
Sum up the particular options you would want to modify.
See which of these options matter during initialitation
programmatically (manually) change these options
options that only matter at runtime (i.e. are read when an event occurs), I'd simply try to modify the myScroller.options object.
For example, you can set these options:
myScroller = new iScroll( el, { x:20, y:30, onRefresh: function(){ alert(11); } } );
Would you want to modify these 3 (or more..), considering my steps you'd do:
x, y, scrollbarClass
in the initialization we see that x & y are used (line 120):
// Set starting position
that.x = that.options.x;
that.y = that.options.y;
That means that these options influences more than just runtime stuff, during initialization it modifies that.x en that.y (even tho pretty simple so far).
3.
myScroller.x = newX;
myScroller.options.x = newX;
myScroller.y = newY;
myScroller.options.y = newY;
// Also depeneds on x & y, but only do this if you actually useTransform and care about this!
/*
* obtain required variables..
*/
var appVersion = navigator.appVersion,
vendor = (/webkit/i).test(appVersion) ? 'webkit' :
(/firefox/i).test(navigator.userAgent) ? 'Moz' :
'opera' in window ? 'O' : '',
has3d = 'WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix(),
trnOpen = 'translate' + (has3d ? '3d(' : '('),
trnClose = has3d ? ',0)' : ')';
// Code that actually matters, and where we use above variables
if (that.options.useTransform) that.scroller.style[vendor + 'Transform'] = trnOpen + that.newX + 'px,' + that.newY + 'px' + trnClose;
else that.scroller.style.cssText += ';position:absolute;top:' + that.newY + 'px;left:' + that.newX + 'px';
4.
myScroller.options.onRefresh = function() { alert(33); }
Maybe you can even do all these things in the options.onDestroy property ;)
Update: I also noticed the destroy function, and might come in convenient if you do want to 'totally clear' the scroller. But I didn't see code that would remove the physically created scrollbar, but I'm not sure.
Related
When creating an animation I try to use javascript for additional effects, namely snow being piled up and falling off the edges of the foreground. I figured that the javascript could do the "calculations" on a <canvas> that had the image, then send the "snow" to a php script that would create the png images. This is all placed on my local "server" because that is the only one that can write files.
<html>
<head>
<title>Making Snow</title>
</head>
<body bgcolor="black">
<canvas id="canvas" width="1920px" height="1080px"></canvas>
</body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script>
var canvas;
var ctx;
var frame=-530;
var simg = new Image()
var dimg = new Image()
onload = function()
{
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
simg.src = "prodB/C/DGB.0530.png"
}
simg.onload = function()
{
var ipo=3;
// Initialize all pixels on the screen/page
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(simg,0,0);
document.title = "Making Snow " + (frame+530) + " / 7000";
snowdraw();
}
dimg.onerror = function()
{
dimg.src = "../imagewriting/snow" + zeroFill(frame+530,4) + ".png";
}
dimg.onload = function()
{
frame++;
if(frame<530)
simg.src = "prodB/C/DGB.0530.png"
else if(frame>4400)
simg.src = "prodB/C/DGB.4400.png"
else
simg.src = "prodB/C/DGB." + zeroFill(frame,4) + ".png"
}
var snowdraw = function()
{
var temp;
var canvasData = "";
// console.log(screen);
// Animation
// Choose a random pixel at the top of the screen
if(frame<7000)
{
for(ny=canvas.height-2; ny>=0; ny--)
{ // Iterate through all the pixels starting from the bottom right corner.
for(nx=canvas.width-2; nx>=0; nx--)
{
canvasData=canvasData+"1";
}
}
$.ajax({
method: "POST",
url: "makesnow.php",
data:{ imgData: canvasData, frame: (frame+530) }
})
.done(function( msg ) {
dimg.src = "../imagewriting/snow" + zeroFill(frame+530,4) + ".png";
});
}
else
{
document.title = "COMPLETE";
}
}
// http://stackoverflow.com/questions/1267283/how-can-i-create-a-zerofilled-value-using-javascript
// by Peter Bailey http://stackoverflow.com/users/8815
function zeroFill( number, width )
{
width -= number.toString().length;
if ( width > 0 )
{
return new Array( width + (/\./.test( number ) ? 2 : 1) ).join( '0' ) + number;
}
return number + ""; // always return a string
}
</script>
</html>
However, on the 1640th frame (or more precisely frame=1110) ajax is suddenly undefined. The image snow1640.png is created, but the browser tells me ajax is not defined and won't advance passed Making Snow 1640 / 7000. Because of the small random nature for each "snow flake" I can't just pick it up from where I left off, as the snow would jump from one frame to the next. Though I did try that at one point and ajax still stopped after that frame.
I first ran it on the local machine running Firefox (http://127.0.0.1/...) then moved onto another machine on the network which is more powerful running Chrome and both died on that same frame. Thought it might be a memory or file limit so I moved the complete frames out of there. Still nothing.
EDIT: Code now snippit of just the problem.
Also, console.log for data and ajax.responseText seem to be generally empty, both during successful "renders" and when it starts iterating ajax is not defined (every other line empty, every other error).
EDIT: New development! Turns out that the error ReferenceError: ajax is not defined anyways gets called between frames (and the 404 when asking dimg if image was created).
EDIT: By typing in console.log($.ajax) after onload and commenting out simg.src I got function ajax().
Error persists, this time I expanded it to reveal the following:
success http://127.0.0.1/ag/makesnowBC.html 197:7
j http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js 2:27131
fireWith http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js 2:27949
x http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js 4:22242
b http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js 4:26298
EDIT: Changed the code to now use Synchronous ajax. This time there are no error messages what so ever, but it still stops at 1640.
In our Angular app we're using highcarts-ng for our HighCharts implementation.
Here is the Chart Maximize and Minimize function, which works:
function expandChartPanel() {
vm.chartMaxed = !vm.chartMaxed;
viewHeader = ScopeFactory.getScope('viewHeader');
highChart = ScopeFactory.getScope('highChart');
var chart = highChart.chartObject;
var highChartContainer = document.getElementById("highchart-container");
var highChartContainerWidth = document.getElementById('highchart-container').clientWidth;
var highChartContainerHeight = document.getElementById('highchart-container').clientHeight;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
if (vm.chartMaxed) {
vs.savedWidth = highChartContainerWidth;
vs.savedHeight = highChartContainerHeight;
console.log('savedWidth = ', vs.savedWidth);
console.log('savedHeight = ', vs.savedHeight);
root.chartExpanded = true;
viewHeader.vh.chartExpanded = true;
highChart.highChartMax = true;
highChartContainerHeight = document.getElementById('highchart-container').clientHeight;
windowWidth = window.innerWidth;
windowHeight = window.innerHeight;
highChart.chartConfig.size.width = windowWidth;
highChart.chartConfig.size.height = windowHeight - 220;
chart.setSize(windowWidth, windowHeight - 220);
}
else {
root.chartExpanded = false;
viewHeader.vh.chartExpanded = false;
highChart.highChartMax = false;
highChart.chartConfig.size.width = vs.savedWidth;
highChart.chartConfig.size.height = vs.savedHeight;
chart.setSize(vs.savedWidth, vs.savedHeight);
}
highChart.restoreChartSize();
}
Here is the reflow function:
function restoreChartSize() {
console.log('restoreChartSize');
if (!vs.chartObject.reflowNow) {
vs.chartObject.reflowNow = vs.chartObject.reflowNow = function() {
this.containerHeight = this.options.chart.height || window.window.HighchartsAdapter.adapterRun(this.renderTo, 'height');
this.containerWidth = this.options.chart.width || window.window.HighchartsAdapter.adapterRun(this.renderTo, 'width');
this.setSize(this.containerWidth, this.containerHeight, true);
this.hasUserSize = null;
}
}
vs.chartObject.reflowNow();
}
This reflow function above, works perfectly in this jsFiddle, but not in our app.
The full Gist file of our HighChartsDirective file.
After clicking Maximize, the chart will expand to the full size of the browser window, but then after dragging to resize the browser window, I call the restoreChartSize function, which activates the reflow.
However the size of the chart does not go to auto-size 100% 100%, it goes back to the previous size of the chart :(
Before Maximize:
After the Maximize function:
Now after resizing the browser window:
window.onresize = function(event) {
console.log('window resizing...');
highChart = ScopeFactory.getScope('highChart');
highChart.restoreChartSize();
console.log('highChart.chartConfig = ', highChart.chartConfig);
};
^ back to the smaller static sizes, not auto-size 100%
You can do this by adding a new method to chart that will manually trigger the reflow like so:
chart.reflowNow = function(){
this.containerHeight = this.options.chart.height || window.window.HighchartsAdapter.adapterRun(this.renderTo, 'height');
this.containerWidth = this.options.chart.width || window.window.HighchartsAdapter.adapterRun(this.renderTo, 'width');
this.setSize(this.containerWidth, this.containerHeight, false);
this.hasUserSize = null;
}
Then whenever you want to get away from manual resizing using setSize() just call chart.reflow()
Here's an working example: jsFiddle
Reference taken from: github-issue
UPDATE for ng-highcharts users
For doing this when using ng-highcharts library, you can simply pull out the chart object in the controller that has highcharts-ng dependency and add the reflowNow function, like so:
var chart = this.chartConfig.getHighcharts();
chart.reflowreflowNow = function (){ ... }
This is also the recommended way to pull out chart to do custom jobs by author of ng-highcharts as noted here and this fiddle.
I ended up finding an alternative solution to be the only thing I could get working, and it actually was pretty simple and straight forward to do. In case anyone else is looking for a fix for this, here's links to the resources that were useful and solved the issue for me.
You can simply add this to your chart config object, at the same level as the config.series or config.options. The comment references info but the actual solution that worked for me uses $timeout with 0 seconds, here
*For using highcharts-ng obviously
http://plnkr.co/edit/14x7gfQAlHw12XZVhWm0?p=preview
$scope.chartConfigObject = {
// function to trigger reflow in bootstrap containers
// see: http://jsfiddle.net/pgbc988d/ and https://github.com/pablojim/highcharts-ng/issues/211
func: function(chart) {
$timeout(function() {
chart.reflow();
//The below is an event that will trigger all instances of charts to reflow
//$scope.$broadcast('highchartsng.reflow');
}, 0);
}
};
Changes in jQuery or jQuery-UI are incompatible to plugin jquery.illuminate.0.7
The plugin jquery.illuminate.0.7 works in chrome 30, firefox 22 and IE 10. It uses
jquery_1.6.1.min.js
jquery-ui_1.8.13.min.js
jquery.illuminate.0.7.js
But changing the version of jQuery and jQuery-UI the causes the demo of the illuminate plugin to only work in chrome 30. The demo uses
jquery_1.9.1.js and
jquery-ui_1.10.3.js
jquery.illuminate.0.7.js
In firefox 22 it causes the following error:
TypeError: $.css(...) is undefined pointing to jquery.illuminate.0.7.js:223
HTML and js code
<script>
window.onload = function(){
$("#illuminate").illuminate({
'intensity': '0.3',
'color': '#98cb00',
'blink': 'true',
'blinkSpeed': '1200',
'outerGlow': 'true',
'outerGlowSize': '30px',
'outerGlowColor': '#98cb00'
});
};
</script>
The relevant html is only the button
<button type="submit" class="btn" id="illuminate" >submit</button>
What have i tried
I looked through the source code of the illuminate plugin to see where the error occurs. The method $.cssHooks.boxShadowBlur contains this js:
$.cssHooks.boxShadowBlur = {
get: function ( elem, computed, extra ) {
return $.css(elem, support.boxShadow).split(rWhitespace)[5];
},
set: function( elem, value ) {
elem.style[ support.boxShadow ] =
insert_into($.css(elem, support.boxShadow), value, 5);
}
};
The github page of jquery still contains a matching function (see line 111):
jQuery.fn.extend({
css: function( name, value ) { ....
My Question
Did any breaking change occur in jQuery.js or jQuery-ui that could be responsible for $.css(...) failing
what can i do to make the plugin compatible to the latest (or at least 1.9.1) version of jquery and jquery-ui (1.10.3)
Updates and Pointers so far
User Dave asked how i load the javascript libraries. I load them synchronously in the following order:
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script src="jquery.illuminate.0.7.js"></script>
User Sumurai pointed out that it could have to do with the deprecated curCSS. I found the following code in jQuery 1.9.1:
jQuery.extend({
// Add in style property hooks for overriding the default
// behavior of getting and setting a style property
cssHooks: {
opacity: {
get: function( elem, computed ) {
if ( computed ) {
// We should always get a number back from opacity
var ret = curCSS( elem, "opacity" );
return ret === "" ? "1" : ret;
}//if
}//get
}//opacity
},//cssHooks
// more properties for jQuery.extend ....
So jQuery 1.9.1 still uses curCSS for the cssHooks.opacity. The plugin illuminate adds another property to cssHooks: $.cssHooks.boxShadowBlur. But as far as i can tell this method has nothing to do with cssHooks.opacity. Therefore the curCSS should have no effect.
Whew, well that took some debugging.
The problem is that illuminate assumes that jQuery doesn't support the box-shadow property, but the newer jQuery version does. That means that when vendor prefixes aren't available (which they aren't in the latest FireFox), you get either an infinite loop or an undefined property. Fortunately illuminate went with an undefined property BoxShadow instead of the infinite loop which would have come from using boxShadow (as I found out, leading to several browser hangs).
So that's the problem, what's the fix? Strip the offending code from illuminate. All cases of support.boxShadow should be changed to simply 'boxShadow', and the cssHooks.boxShadow block removed. You can also delete the bit which sets support.boxShadow in the first place.
My test case is here: http://jsfiddle.net/JbTcs/2/ and works in FireFox and Chrome, and I'm told IE10.
The fixed source code for illuminate is:
/*
* jQuery Illuminate v0.7 - http://www.tonylea.com/
*
* Illuminate elements in jQuery, Function takes the background color of an element
* and illuminates the element.
*
* TERMS OF USE - jQuery Illuminate
*
* Open source under the BSD License.
*
* Currently incompatible with FireFox v.4
*
* Copyright © 2011 Tony Lea
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the author nor the names of contributors may be used to endorse
* or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* modified version
*
*/
(function($){
$.fn.illuminate = function(options) {
var defaults = {
intensity: '0.05',
color: '',
blink: 'true',
blinkSpeed: '600',
outerGlow: 'true',
outerGlowSize: '30px',
outerGlowColor: ''
};
var options = $.extend(defaults, options);
var original_color = '';
var new_color = '';
var dead = false;
$.fn.illuminateDie = function() {
dead = true;
options.intensity = '0.05';
options.color = '';
options.blink = 'true';
options.blinkSpeed = '600';
options.outerGlow = 'true';
options.outerGlowSize = '30px';
options.outerGlowColor = '';
$(this).css({'boxShadow': '0px 0px 0px', 'background-color': "#" + original_color});
}
function toggleIllumination(obj, original_color, new_color, outerGlow) {
if(rgb2hex(obj.css('background-color')).toUpperCase() == original_color.toUpperCase()) {
obj.animate({"background-color": "#" + new_color, 'boxShadowBlur': outerGlow }, parseInt(options.blinkSpeed),
function(){
if(!dead)
toggleIllumination($(this), original_color, new_color, outerGlow);
});
}
if(rgb2hex(obj.css('background-color')).toUpperCase() == new_color.toUpperCase()) {
obj.animate({"background-color": "#" + original_color, 'boxShadowBlur': '0px' }, parseInt(options.blinkSpeed),
function(){
if(!dead)
toggleIllumination($(this), original_color, new_color, outerGlow);
});
}
}
function colorAdd(hex, percent) {
percentHex = parseInt(Math.round(parseFloat(percent)*16));
return hexAdd(hex[0], percentHex) + hexAdd(hex[1], percentHex) + hexAdd(hex[2], percentHex) + hexAdd(hex[3], percentHex) + hexAdd(hex[4], percentHex) + hexAdd(hex[5], percentHex);
}
function hexAdd(val, val2) {
result = parseInt(val, 16) + val2;
if(result > 15) return 'F';
return result.toString(16).toUpperCase();
}
function rgb2hex(rgb) {
rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
function hex(x) {
return ("0" + parseInt(x).toString(16)).slice(-2);
}
return hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
}
return this.each(function() {
obj = $(this);
if(obj.is("input")){
if(obj.css('border') == ''){ obj.css('border', 'none') };
}
dead = false;
original_color = rgb2hex(obj.css('background-color'));
if(options.color == ''){
new_color = colorAdd(original_color, options.intensity);
} else {
new_color = options.color.replace('#', '');
}
var BlurColor = '';
if(options.outerGlowColor == ''){
BlurColor = new_color;
} else {
BlurColor = options.outerGlowColor.replace('#', '');
}
obj.css('boxShadow','0px 0px 0px #'+BlurColor);
var firstColor = '';
var firstBlur = '';
if(options.blink == 'true'){
firstColor = original_color;
firstBlur = '0px';
} else {
firstColor = new_color;
firstBlur = options.outerGlowSize;
}
var outerGlow = '';
if(options.outerGlow == 'true'){
outerGlow = options.outerGlowSize;
} else {
outerGlow = '0px';
}
obj.animate({"background-color": "#" + firstColor, 'boxShadowBlur': firstBlur }, parseInt(options.blinkSpeed),
function(){
if(options.blink == 'true')
toggleIllumination($(this), original_color, new_color, outerGlow);
});
});
};
var div = document.createElement('div'),
divStyle = div.style,
support = $.support,
rWhitespace = /\s/,
rParenWhitespace = /\)\s/;
div = null;
function insert_into(string, value, index) {
var parts = string.split(rWhitespace);
parts[index] = value;
return parts.join(" ");
}
$.cssHooks.boxShadowBlur = {
get: function ( elem, computed, extra ) {
return $.css(elem, 'boxShadow').split(rWhitespace)[5];
},
set: function( elem, value ) {
elem.style[ 'boxShadow' ] = insert_into($.css(elem, 'boxShadow'), value, 5);
}
};
$.fx.step[ "boxShadowBlur" ] = function( fx ) {
$.cssHooks[ "boxShadowBlur" ].set( fx.elem, fx.now + fx.unit );
};
})(jQuery);
Basically I have this code in MS Visual studio 2012 for a windows 8 JavaScript+jQuery app.
<script>
window.setInterval(function () {
var currentx = $(".ball").css("left");
var currenty = $(".ball").css("top");
$(".ball").css("top", currentx + 1);
$(".ball").css("left", currenty + 1);
//debug
var time=1;
$("p.test").text("Has been called " +time);
var time=time+1;
}, 100);
</script>
Yes, I am using jQuery 2.0
Now I looked at the API's here http://www.w3schools.com/js/js_timing.asp
and here http://api.jquery.com/css/
My code compiles, but it just is not updating the position of the ball. It appears it is only being called once. If it helps the ball is a DIV element. Maybe windows 8 Apps don't fully support DOM manipulation, or just the Window global variable, I don't really know.
What code would I need to achieve my goal of updating this element of class ball's top and left CSS rules at set intervals?
.css("left") and .css("top") return a string (e.g. 0px) and not a number so you need to parse it with parseInt otherwise the currentx + 1 results in e.g. 0px1
And it looks like it is only called once because time is defined and set to 1 in the setIntervalcallback, you need to define and initialize it outside of the callback of setInterval.
instead of .css("left") you could also think over using .position().left.
(function() {
var time=1;
window.setInterval(function () {
var currentx = parseInt($(".ball").css("left"),10);
var currenty = parseInt($(".ball").css("top"),10);
$(".ball").css("top", currentx + 1);
$(".ball").css("left", currenty + 1);
//debug
$("p.test").text("Has been called " +time);
time=time+1;
}, 100);
})();
I recently downloaded a nice mootools plugin to provide a rating system for search results on my site: MooStarRating.
It works quite well, but it is very slow to initialize. Here are the execution times I have logged (for pulling back 50 search results).
======== starrating ========
init: 0.06ms 50
img: 5.40ms 50
str: 0.54ms 50
each: 3.04ms 50
inject: 0.86ms 50
end: 1.52ms 50
subtotal: 11.42ms 50
-----------------
total: 571.00ms
Here is the initialize function these logs refer to (just for reference):
initialize: function (options) {
lstart("starrating");
// Setup options
this.setOptions(options);
// Fix image folder
if ((this.options.imageFolder.length != 0) && (this.options.imageFolder.substr(-1) != "/"))
this.options.imageFolder += "/";
// Hover image as full if none specified
if (this.options.imageHover == null) this.options.imageHover = this.options.imageFull;
lrec("init");
// Preload images
try {
Asset.images([
this.options.imageEmpty,
this.options.imageFull,
this.options.imageHover
]);
} catch (e) { };
lrec("img");
// Build radio selector
var formQuery = this.options.form;
this.options.form = $(formQuery);
if (!this.options.form) this.options.form = $$('form[name=' + formQuery + "]")[0];
if (this.options.form) {
var uniqueId = 'star_' + String.uniqueID();
this.options.form.addClass(uniqueId);
this.options.selector += 'form.' + uniqueId + ' ';
}
this.options.selector += 'input[type=radio][name=' + this.options.radios + "]";
// Loop elements
var i = 0;
var me = this;
var lastElement = null;
var count = $$(this.options.selector).length;
var width = this.options.width.toInt();
var widthOdd = width;
var height = this.options.height.toInt();
if (this.options.half) {
width = (width / 2).toInt();
widthOdd = widthOdd - width;
}
lrec("str");
$$(this.options.selector).each(function (item) {
// Add item to radio list
this.radios[i] = item;
if (item.get('checked')) this.currentIndex = i;
// If disabled, whole star rating control is disabled
if (item.get('disabled')) this.options.disabled = true;
// Hide and replace
item.setStyle('display', 'none');
this.stars[i] = new Element('a').addClass(this.options.linksClass);
this.stars[i].store('ratingIndex', i);
this.stars[i].setStyles({
'background-image': 'url("' + this.options.imageEmpty + '")',
'background-repeat': 'no-repeat',
'display': 'inline-block',
'width': ((this.options.half && (i % 2)) ? widthOdd : width),
'height': height
});
if (this.options.half)
this.stars[i].setStyle('background-position', ((i % 2) ? '-' + width + 'px 0' : '0 0'));
this.stars[i].addEvents({
'mouseenter': function () { me.starEnter(this.retrieve('ratingIndex')); },
'mouseleave': function () { me.starLeave(); }
});
// Tip
if (this.options.tip) {
var title = this.options.tip;
title = title.replace('[VALUE]', item.get('value'));
title = title.replace('[COUNT]', count);
if (this.options.tipTarget) this.stars[i].store('ratingTip', title);
else this.stars[i].setProperty('title', title);
}
// Click event
var that = this;
this.stars[i].addEvent('click', function () {
if (!that.options.disabled) {
me.setCurrentIndex(this.retrieve('ratingIndex'));
me.fireEvent('click', me.getValue());
}
});
// Go on
lastElement = item;
i++;
}, this);
lrec("each");
// Inject items
$$(this.stars).each(function (star, index) {
star.inject(lastElement, 'after');
lastElement = star;
}, this);
lrec("inject");
// Enable / disable
if (this.options.disabled) this.disable(); else this.enable();
// Fill stars
this.fillStars();
lrec("end");
return this;
},
So, the slowest part of the function is this:
// Preload images
try {
Asset.images([
this.options.imageEmpty,
this.options.imageFull,
this.options.imageHover
]);
} catch (e) { };
Which is strange. What does Asset.images do? Does the script block until these images have been loaded by the browser? Is there a way to preload images that runs faster?
How can I make the scripts on my page execute faster? It is a big problem for them to take 800ms to execute, but 200ms is still quite bad. At the moment, my search results all pop into existence at once. Is it possible to make it so that individual search results are created separately, so that they don't block the browser while being created? Similarly, is it possible to do this for the individual components of the search results, such as the MooStarRating plugin?
no. Asset.images is non-blocking as each of these gets loaded separately and a singular event is being dispatched when all done.
the speed for loading will be dependent on the browser but it be will multi-threaded to whatever capability it has for parallel downloading from the same host.
https://github.com/mootools/mootools-more/blob/master/Source/Utilities/Assets.js#L115-129
immediately, it returns an Element collection with the PROMISE of elements that may still be downloading. that's fine - you can use it to inject els, attach events, classes etc - you just cannot read image properties yet like width, height.
each individual image has it's own onload that fires an onProgress and when all done, an onComplete for the lot - i would advise you to enable that, remove the try/catch block and see which image is creating a delay. you certainly don't need to wait for anything from Asset.images to come back.
you also seem to be using it as a 'prime the cache' method, more than anything - as you are NOT really saving a reference into the class instance. your 'each' iteration can probably be optimised so it uses half the time if objects and functions are cached and so are references. probably more if you can use event delegation.
To answer your questions about not freezing the browser due to the single-threaded nature of javascript, you defer the code via setTimeout (or Function.delay in mootools) with a timer set to 0 or a 10ms due to browser interpretations. You also write the function to to exec a callback when done, in which you can pass the function result, if any (think ajax!).