I have a javascript/jquery function that displays a notification. I want to make this function display a different mode if they aren't on x, y and z page.
This is how I tried to achieve this:
function display_alert(message, type, delay, mode)
{
type = (typeof type === "undefined") ? "danger" : type;
delay = (typeof delay === "undefined") ? 3000 : delay;
mode = (typeof mode === "undefined") ? 'normal' : mode;
var current_location = document.URL;
var home_locations = ['home', 'remote', 'zip'];
for (var i = 0; i < home_locations.length; i++)
{
if (current_location.toString().indexOf(home_locations[i]) == -1)
{
// alert(home_locations[i]); return;
mode = 'top';
break;
}
}
...
So if document.URL doesn't contain one of the array elements, then I want the mode variable to become top.
I think this is a simple problem, but I just can't see how to fix it.
You could use a regular expression built with your home_locations array :
var home_regex = new RegExp('('+home_locations.join('|')+')');
// home_regex = /(home|remote|zip)/;
if (!home_regex.test(document.URL)) mode = 'top';
You need to reverse the logic in your loop...
var current_location = document.URL;
var home_locations = ['home', 'remote', 'zip'];
var found = false;
for (var i = 0; i < home_locations.length; i++)
{
if (current_location.toString().indexOf(home_locations[i]) >= 0)
{
found = true;
break;
}
}
if (!found) {
mode = 'top';
}
Related
I have a MultiSelectDropDown, that is, several RadComboBox controls are used in a combined way. For example, I can have a dropdown for regions, another for depots and another for user. The idea is to change the content of lower levels dynamically whenever items are selected or unselected on a higher level. The problem is that in the case when many items are selected, this becomes brutally slow due to some Telerik functions, but I do not understand why. This is a chunk from the client-side of the MultiSelectDropDown prototype:
changeLowerLevels: function (valueIndex, values, value) {
if (!this.canChange) return;
//Get selected values from combobox
var combo = $find(this.ddlIDs[valueIndex - 1]);
var cbItems = combo.get_checkedItems();
var selectedItems = [];
var change = null;
var counter = 0;
if (cbItems.length) this.filterString = "";
for (var i = 0; i < cbItems.length; i++) {
counter++;
if (this.filterString == "") this.filterString = cbItems[i].get_text();
selectedItems.push(cbItems[i].get_value());
}
if (counter > 1) this.filterString += " with " + (counter - 1) + " other" + ((counter > 2) ? "s" : "");
if (JSON.stringify(selectedItems) === JSON.stringify(this.selectedItems[valueIndex - 1]) || selectedItems == [])
return;
this.selectedItems[valueIndex - 1] = selectedItems;
var controlObject = this;
var combo = $find(this.ddlIDs[valueIndex]);
var comboItems = combo.get_items();
if(!this.disabled) combo.enable();
combo.clearItems();
if (valueIndex == 1) this.twoLevelCache = values;
var val = values;
//break if all items are found
var nrOfSelectedItems = this.selectedItems[valueIndex - 1].length;
var nrOfFoundItems = 0;
var index = 0;
var indexes = [];
var found = false;
while (nrOfFoundItems < nrOfSelectedItems && val[index] !== undefined) {
found = (this.selectedItems[valueIndex - 1].indexOf(val[index].Value) != -1);
if (!(found))
index++;
else {
indexes.push(index)
nrOfFoundItems++;
index++;
}
}
//separators from valuesIndex - 1 level
var controlObject = this;
for (var i = 0; i < indexes.length; i++) {
var separator = new Telerik.Web.UI.RadComboBoxItem();
separator.set_text("<span><a class=\"checkAll tt-multi-uncheck-icon\" index=\"" + index + "\">U</a>" + $find(this.ddlIDs[valueIndex - 1]).findItemByValue(val[indexes[i]].Value).get_text() + "</span>");
separator.set_value("");
separator.set_isSeparator(true);
comboItems.add(separator);
this.twoLevelCache.push(val[indexes[i]].Levels);
//valuesIndex level
var valuesArray = val;
var comboItem = new Telerik.Web.UI.RadComboBoxItem();
for (var depot in valuesArray[indexes[i]].Levels) {
comboItem = new Telerik.Web.UI.RadComboBoxItem();
comboItem.set_text(valuesArray[indexes[i]].Levels[depot].Name);
comboItem.set_value(valuesArray[indexes[i]].Levels[depot].Value);
comboItems.add(comboItem);
comboItem = null;
}
$('#' + this.ddlIDs[valueIndex] + '_DropDown a.checkAll').unbind().on("click", function () {
checkAllLowerItems(this, controlObject.ddlIDs[valueIndex]);
});
}
combo.set_emptyMessage(this.allText);
//$("#" + this.ddlIDs[valueIndex]).html(returnValue);
if (this.ddlIDs.length > valueIndex + 1) {
var paramToPass = (((val == undefined) || (val[index] === undefined)) ? ("") : (val[index]));
if (this.allText.length > 0)
this.changeLowerLevels(valueIndex + 1, paramToPass, "");
else {
if (paramToPass !== "")
paramToPass = paramToPass.Levels;
if ((val[index] == undefined) || (val[index].Levels[0] === undefined) || (val[index].Levels[0].Value === "")) {
this.changeLowerLevels(valueIndex + 1, paramToPass, "");
}
else {
this.changeLowerLevels(valueIndex + 1, paramToPass, val[index].Levels[0].Value);
}
}
}
else {
if (this.allText.length > 0)
this.selectedItems[valueIndex] = "";
else
if ((val[index] == undefined) || (val[index].Levels[0] === undefined) || (val[index].Levels[0].Value === "")) {
this.selectedItems[valueIndex] = "";
}
else {
this.selectedItems[valueIndex] = val[index].Levels[0].Value;
}
}
this.setText();
}
combo.clearItems() is extremeley slow. I have take a look on how it is implemented:
function (){var f=this._parent._getControl();?if(f._checkBoxes){f._checkedIndicesJson="[]";?f._checkedIndices=[];?var g=f.get_items();?for(var d=0,e=g.get_count();?d<e;?d++){var c=f.get_items().getItem(d);?c.set_checked(false);?}f.updateClientState();?}a.RadComboBoxItemCollection.callBaseMethod(this,"clear");?}
How can I make sure that this Javascript function speeds up?
I have finally solved the problem by rewriting Telerik client-side functionalities. It was a long and difficult debugging, but it yielded a large performance boost in the most difficult circumstances. From ~30 000 milliseconds, to ~300. Let's see the parts of the optimization:
The actual rewrite
/* Overriding Telerik functions Start */
var overridenTelerikControls = false;
function overrideTelerikFunctionalities() {
if (!overridenTelerikControls) {
overridenTelerikControls = true;
Telerik.Web.UI.RadComboBox.prototype.clearItems = function (isMultiSelectDropDown) {
this.get_items().clear(isMultiSelectDropDown);
this._itemData = null;
};
Telerik.Web.UI.RadComboBoxItemCollection.prototype.clear = function (isMultiSelectDropDown){
var f=this._parent._getControl();
if(f._checkBoxes){
f._checkedIndicesJson="[]";
f._checkedIndices=[];
var g = f.get_items();
for(var d=0,e=g.get_count();d<e;d++){
var c=f.get_items().getItem(d);
c.set_checked(false, isMultiSelectDropDown);
}
if (isMultiSelectDropDown) {
f._updateComboBoxText();
if (f._checkAllCheckBoxElement != null) {
f._updateCheckAllState();
}
}
f.updateClientState();
}
Telerik.Web.UI.RadComboBoxItemCollection.callBaseMethod(this, "clear");
};
Telerik.Web.UI.RadComboBoxItem.prototype.set_checked = function (d, isMultiSelectDropDown){
if(!this.get_enabled()){
return;
}
this._setChecked(d);
var c=this.get_comboBox();
if(c){
if(d){
c._registerCheckedIndex(this.get_index());
}else{
c._unregisterCheckedIndex(this.get_index());
}
if (!isMultiSelectDropDown) {
c._updateComboBoxText();
}
if((!isMultiSelectDropDown) && (c._checkAllCheckBoxElement!=null)){
c._updateCheckAllState();
}
}
};
}
}
/* Overriding Telerik functions End*/
My approach was to keep the old way of their working by default, but if an isMultiSelectDropDown parameter is passed, then work in the optimized manners. So we have a switch materialized as a parameter and we can turn it on/off. The main difference was that the old way was to change the label text showing the selected elements each time a checkbox is checked/unchecked. The main improvement was to do this change after all the checkboxes were checked/unchecked. This extremely simple idea was the driving force behind the boost of performance.
Actual usage
overrideTelerikFunctionalities();
combo.clearItems(true);
This was the functionalities were overriden if they were not already and the parameter was true, therefore the new approach was chosen.
Test, test, test
I'm trying the following code:
var var1 = "";
var var2 = "test";
var var3 = "";
vars = new Array('var1','var2','var3');
var count = 0;
for (var i = 0; i < vars.length; ++i) {
var name = vars[i];
if (field_is_empty(name)) {
count++;
}
}
console.log(count);
function field_is_empty(sValue) {
if (sValue == "" || sValue == null || sValue == "undefined")
{
return true;
}
return false;
}
The result here should have been count = 2 because two of the variables are empty but it's always 0. I guess it must something when using if (field_is_empty(name)) because it might not getting the name converted to the name of the actual var.
PROBLEM 2# Still related
I've updated the code as Karthik Ganesan mentioned and it works perfectly.
Now the code is:
var var1 = "";
var var2 = "test";
var var3 = "";
vars = new Array(var1,var2,var3);
var count = 0;
for (var i = 0; i < vars.length; ++i) {
var name = vars[i];
if (field_is_empty(name)) {
count++;
}
}
console.log(count);
function field_is_empty(sValue) {
if (sValue == "" || sValue == null || sValue == "undefined")
{
return true;
}
return false;
}
And the problem is that if add a new if statement something like this:
if (count == '3') {
console.log('AllAreEmpty');
} else {
for (var i = 0; i < vars.length; ++i) {
var name = vars[i];
if (field_is_empty(name)) {
//Set the empty variables as "1900-01-01"
variableService.setValue(name,"test");
}
}
}
It does nothing and I've tested using variableService.setValue('var1',"test") and it works.
PS: The variableService.setValue is a function controlled by the software I don't know exactly what it does I know if use it like mentioned on above line it works.
In your first attempt you used the variable names as strings when you created an array. You need to either use the values themselves:
vars = new Array(var1,var2,var3);
or if you insist to use them by their names, then you need to find them by names when you use them:
if (field_is_empty(window[name])) {
It does nothing
That's not really possible. It could throw an error, or enter the if or enter the else, but doing nothing is impossible. However, since you intended to use the variables by name in the first place (probably not without a reason) and then you intend to pass a name, but it is a value and it does not work as expected, I assume that your initial array initialization was correct and the if should be fixed like this:
var var1 = "";
var var2 = "test";
var var3 = "";
vars = new Array(var1,var2,var3);
var count = 0;
for (var i = 0; i < vars.length; ++i) {
var v = window[vars[i]]; //You need the value here
if (field_is_empty(v)) {
count++;
}
}
console.log(count);
if (count == '3') {
console.log('AllAreEmpty');
} else {
for (var i = 0; i < vars.length; ++i) {
var v = window[vars[i]];
if (field_is_empty(v)) {
//Set the empty variables as "1900-01-01"
variableService.setValue(vars[i],"test");
}
}
}
function field_is_empty(sValue) {
if (sValue == "" || sValue == null || sValue == "undefined")
{
return true;
}
return false;
}
You definitely incorrectly initialize array, you put strings "var1", "var2", "var3" instead of references to strings (variables).
Try this:
vars = new Array(var1,var2,var3);
Your array is wrong
it should be
vars = new Array(var1,var2,var3);
here is the jsfiddle
I would like to know if the way I have assigned values to the 'Deval' and 'Reval' variables in the 'datevalidate' method is correct?
If you notice my code, I am assigning values by specifying the entire chain pointing to the method like so 'x9.validator.check_element_val()'. Can I make a less explicit call? Since I am trying to access a function outside the immediate lexical scope of these variables, is there some way I can use a closure to better approach this?
Kindly correct my understanding of closures if it is not apt for the current scenario.
var x9 = {} || x9;
x9.validator = {
mode : 1,
check_element_val : function(el){
var returnval = 0;
if (el.value == 0 || el.value == undefined || el.value == null || el.value == ''){
returnval = 0;
}else{
returnval = 1;
}
return returnval;
},
datevalidate : function(mode, dep_el, ret_el){
var returnobj = new Object();
if (mode == 1){
Deval = x9.validator.check_element_val(dep_el);
Reval = x9.validator.check_element_val(ret_el);
if (Deval == 0 || Reval == 0){
returnobj.returnval = false;
}else{
returnobj.returnval = true;
}
}
return JSON.stringify(returnobj);
}
};
Thanks in advance.
Perhaps you would benefit from the Module pattern (see this simple example). You could do something like this:
var x9 = {} || x9;
x9.validator = (function() {
var mode = 1;
var check_element_val = function(el){
var returnval = 0;
if (el.value == 0 || el.value == undefined || el.value == null || el.value == ''){
returnval = 0;
}else{
returnval = 1;
}
return returnval;
};
var datevalidate = function(mode, dep_el, ret_el){
var returnobj = new Object();
if (mode == 1){
Deval = check_element_val(dep_el);
Reval = check_element_val(ret_el);
if (Deval == 0 || Reval == 0){
returnobj.returnval = false;
}else{
returnobj.returnval = true;
}
}
return JSON.stringify(returnobj);
}
return {
mode : mode,
check_element_val : check_element_val,
datevalidate : datevalidate
};
})();
As a side note, I'm not sure what you were trying to do with the mode variable, but be aware that the datevalidate function will not be using it unless you supply it yourself as an argument, for instance:
var validation = x9.validator.datevalidate(x9.validator.mode,someValue1,someValue2);
If you want the function to only use the mode variable from within the validator, remove mode from the argument list. If you want to keep the ability to provide different modes, though, you can write an additional function. For example:
var datevalidate_default_mode = function(dep_el,ret_el) {
return datevalidate(mode, dep_el, ret_el);
};
I think it looks nicer than adding x9.validator.mode to the datevalidate function every time you want to use the default value. And that way you can even remove mode from the module output. Either way, if you're adding a new public function, don't forget to expose it in the module output as well!
I am making a javascript script that wants to do something like this:
elementObject.style.transform.replace('...','...');
elementObject.style.webkitTransform.replace('...','...');
And just to clear this up, yes, I have set both of those styles earlier in the script. However, this causes errors because in Chrome, for example, it does not recognize the transform style. Therefore, replace fails because elementObject.style.transform is undefined, and undefined has no method replace. Is there any way to do this without causing these errors? I just want the webkit transform, i do not need moz, o, or any other prefix.
var st = elementObject.style;
if (st.transform !== undefined) st.transform = st.transform.replace('...','...');
// ...
or more general:
function replaceStyle(element, style, text, replacement) {
var vendors = ['webkit', 'moz', 'o', 'ms'];
var st = element.style;
if (st[style] !== undefined) st[style] = st[style].replace(text, replacement);
style = style.charAt(0).toUpperCase()+style.substring(1);
for (var i=0, l=vendors.length; i<l; i++) {
var vendorStyle = vendors[i]+style;
if (st[vendorStyle] !== undefined)
st[vendorStyle] = st[vendorStyle].replace(text, replacement);
}
}
// sample call (setting width from "40px" to "100%")
replaceStyle( myElementObject, 'with', '40px', '100%' );
You must use the Adapter design pattern.
For example:
function transformStyle() {
var tempEl = document.createElement('div'),
elStyle = tempEl.style;
if (typeof elStyle.transform !== 'undefined') {
transformStyle = function (el, val) {
val != null && (el.style.transform = val);
return el.style.transform;
};
} else if (typeof elStyle.webkitTransform !== 'undefined') {
transformStyle = function (el, val) {
val != null && (el.style.webkitTransform = val);
return el.style.webkitTransform;
};
} else {
transformStyle = function () { return ''; }; //ignore when not supported
}
tempEl = null;
elStyle = null;
return transformStyle.apply(this, arguments);
}
var el = document.createElement('div');
transformStyle(el, 'rotate(-2deg)'); //set style
transformStyle(el); //rotate(-2deg)
Obviously you could write something more generic such as a style method that allows accessing or modifying any styles. You could use a list of vendor prefixes to make the code more DRY as well. The previous code was just an example.
The following line is giving me trouble in IE8, while working in Chrome and Firefox:
this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex];
IE8 returns "unexpected call to method or property access". I tried a fix recommended elsewhere, using getCellIndex(this) instead of this.cellIndex, and added:
function getCellIndex(aCell) {
aRow = aCell.parentNode;
for (i = 0; i != aRow.cells.length; i++) {
if (aRow.cells[i] == aCell) return i;
}
}
...and was told that "cells.length is null or not an object".
Any recommendations on how to proceed would be appreciated. Relevant part of the function below, trouble is on line 6:
$tableHeaders = $(c.selectorHeaders, table)
.wrapInner("<div class='tablesorter-header-inner' />")
.each(function(index) {
$t = $(this);
ch = c.headers[index];
this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex];
this.order = formatSortingOrder( ts.getData($t, ch, 'sortInitialOrder') || c.sortInitialOrder ) ? [1,0,2] : [0,1,2];
this.count = -1; // set to -1 because clicking on the header automatically adds one
if (ts.getData($t, ch, 'sorter') === 'false') { this.sortDisabled = true; }
this.lockedOrder = false;
lock = ts.getData($t, ch, 'lockedOrder') || false;
if (typeof(lock) !== 'undefined' && lock !== false) {
this.order = this.lockedOrder = formatSortingOrder(lock) ? [1,1,1] : [0,0,0];
}