How to create a function to center windows - javascript

I'm using the jqgrid, and to focus the popup to add, delete and edit, I need to use the parameter beforeShowForm that before this show window, shows the center of the screen. The problem is I have to always do the same code for these three functions.
The function is as follows:
{ // edit option
beforeShowForm: function(form) {
var dlgDiv = $("#editmod" + $(this)[0].id);
var parentDiv = dlgDiv.parent();
var dlgWidth = dlgDiv.width();
var parentWidth = parentDiv.width();
var dlgHeight = dlgDiv.height();
var parentHeight = parentDiv.height();
var parentTop = parentDiv.offset().top;
var parentLeft = parentDiv.offset().left;
dlgDiv[0].style.top = Math.round(parentTop / 2) + "px";
dlgDiv[0].style.left = Math.round(parentLeft + (parentWidth-dlgWidth )/2 ) + "px";
}
},
In order to reuse the same code, I would create a separate function to be always writing the same amount of code. I tried to create the following function:
Function:
function test(dlgDiv)
{
var parentDiv = dlgDiv.parent();
var dlgWidth = dlgDiv.width();
var parentWidth = parentDiv.width();
var dlgHeight = dlgDiv.height();
var parentHeight = parentDiv.height();
var parentTop = parentDiv.offset().top;
var parentLeft = parentDiv.offset().left;
dlgDiv[0].style.top = Math.round(parentTop / 2) + "px";
dlgDiv[0].style.left = Math.round(parentLeft + (parentWidth-dlgWidth )/2 ) + "px";
}
In Grid:
{ // edit option
beforeShowForm: function(form) {
var dlgDiv = $("#editmod" + $(this)[0].id);
test(dlgDiv);
}
},
But continued without giving. Says that the value dlgDiv is not defined. Does anyone know how to solve this?

The issue lies in the selector you use here:
var dlgDiv = $("#editmod" + $(this)[0].id);
Whatever element you're trying to get isn't being returned, because the selector can't find it. You should revise your selector to reflect the ID of the element you're attempting to find.
If you've done that and you still have an issue, the problem lies with your context and this doesn't mean what you think it means in the above line of code. You'll have to show us more code before I can elaborate on that, though.

Related

Is there any way of chaining too many document.getElementById on a particular id of javascript object?

function showShape(){
var top=Math.random()*370;
var left=Math.random()*350;
var width=Math.random()*300;
var height=Math.random()*300;
start = new Date().getTime();
document.getElementById("shape").style.display = "block";
document.getElementById("shape").style.top=top + "px";
document.getElementById("shape").style.left=left + "px";
document.getElementById("shape").style.width=width+"px";
document.getElementById("shape").style.height=height+"px";
}
I want to reduce the redundancy.There is too many documentgetelement that I want to get rid of.
1) Cache your element
2) Create an randomise function that accepts a number and returns an integer.
3) Ensure your element has its position property set.
const shape = document.getElementById('shape');
function rnd(seed) {
return Math.round(Math.random() * seed);
}
function showShape(shape) {
var top = rnd(370);
var left = rnd(350);
var width = rnd(300);
var height = rnd(300);
shape.style.position = 'absolute';
shape.style.display = 'block';
shape.style.top = `${top}px`;
shape.style.left = `${left}px`;
shape.style.width = `${width}px`;
shape.style.height = `${height}px`;
}
showShape(shape);
#shape {
background-color: blue;
}
<div id="shape" />
Further documentation:
Template literals
It's called caching. Not only you will write less code, but also greatly improve performance.
const shapeElem = document.getElementById("shape");
function showShape(){
var top=Math.random()*370;
var left=Math.random()*350;
var width=Math.random()*300;
var height=Math.random()*300;
start = new Date().getTime();
shapeElem.style.display = "block";
shapeElem.style.top=top + "px";
shapeElem.style.left=left + "px";
shapeElem.style.width=width+"px";
shapeElem.style.height=height+"px";
}

JS - Get new element after click event

I'm working on a chrome extension to automate some work of mine. Currently it enters a value into a input, then clicks the button.
I want to get a new div element when it gets to the next page (once loaded). But it always looking a div before click event.
I hope that you understanded my problem.
Here is a code:
bSzukaj.onclick = function()
{
var url = "/game.php?screen=place";
var coords = [];
var loaded = false;
var n = inputZakres.value;
var x = parseInt(inputPobierz.value.split("|")[0] - parseInt(n/2+1));
var y = parseInt(inputPobierz.value.split("|")[1] - parseInt(n/2+1));
var newWindow = window.open(url);
var currentX = x;
var currentY = y;
var coord = currentX+"|"+currentY;
var sender = newWindow.addEventListener('load', function(){
var spearInput = newWindow.document.getElementById("unit_input_spear");
spearInput.value = 10;
var coordClass = newWindow.document.getElementsByClassName("target-input-field target-input-autocomplete")[0];
coordClass.value = coord;
var send = newWindow.document.getElementById("target_attack").click();
// NOW SCRIPT RELOAD PAGE AND CREATING SOME COMUNICATS
// AND I WANT TO GET THIS COMUNICATS TO VARIABLE
// BUT EVEN THIS ALERT BELOW DOESN'T WORK :/
newWindow.addEventListener('load', function() {
alert("now");
});
}, false);
//}
//}
}
}

Using wildcards in js function

I have a function using which I am getting the auto sum for a particular field in a row.
$(function () {
$('#add_iaDetails_table').on('change', '[name=days_0]', function () {
var $row = $(this).closest('tr');
var $rate = $row.find('input[name=rate_0]');
var $days = $row.find('input[name=days_0]');
var $cost = $row.find('input[name=cost_0]');
var rate = parseFloat($rate.val());
var days = parseFloat($days.val());
$cost.val(rate * days);
});
});
But the thing is I am appending the rows in the table dynamically and I am the name of the fields as well eg. days_1,days_2.....rate_1,rate_2....
My function here will calculate the autosum for only the first row which matches with values given in function.
Is there any way in which I can match all the appended values like days_* , rate_*
Please suggest a solution. Thanks in advance.
A simple
$(function () {
$('#add_iaDetails_table').on('change', '[name=days_0]', function () {
var $row = $(this).closest('tr');
var $rate = $row.find('input[name*=rate_]');
var $days = $row.find('input[name*=days_]');
var $cost = $row.find('input[name*=cost_]');
var rate = parseFloat($rate.val());
var days = parseFloat($days.val());
$cost.val(rate * days);
});
});
would work where * implies that you select any input with attribute containing the given string or you may use the startswith selector from JQUERY where in above code you replace * by ^
To accommodate dynamic content, I would be a bit more flexible with your selector; just filter on the name starting with days_, and then grab that id at the end dynamically.
Something like this:
$('#add_iaDetails_table').on('change', '[name^=days_]', function () {
var name = $(this).attr('name');
var nameId = name.substr(name.indexOf('_') + 1);
var $row = $(this).closest('tr');
var $rate = $row.find('input[name=rate_' + nameId + ']');
var $days = $row.find('input[name=days_' + nameId + ']');
var $cost = $row.find('input[name=cost_' + nameId + ']');
var rate = parseFloat($rate.val());
var days = parseFloat($days.val());
$cost.val(rate * days);
});
you can use starts-with selector, like
$('#add_iaDetails_table').on('change', '[name^=days_]', function () {
var uid = $(this).attr("name").split("_")[1]; //get the unique id from 'name' attribute
var $row = $(this).closest('tr');
var $rate = $row.find('input[name=rate_' + uid + ']');
var $days = $row.find('input[name=days_' + uid + ']');
var $cost = $row.find('input[name=cost_' + uid + ']');
var rate = parseFloat($rate.val());
var days = parseFloat($days.val());
$cost.val(rate * days);
});
jQuery has a whole bunch of different selectors
http://api.jquery.com/category/selectors/
Based on your question you probably want the Starts With refiner
http://api.jquery.com/attribute-starts-with-selector/
$('#add_iaDetails_table').on('change', '[name=^days_]', function () { ... }
The scalable/cross browser solution I can think of is, for every input element add a class that you can identify row/column index. This way you can do horizontal or vertical queries and do whatever you want.

vtip jQuery to display titles

I am using vTip plugin to display titles on hover , here is my example code:
http://jsfiddle.net/bnjSs/
I have a Div#showTitles , When i click on it I wants to toggle display of all div.vtips titles on page just like mouseover.
$("#showTitles").click(function(){
// this I am not sure how to acheive.
return false;
});
UPDATE:
http://jsfiddle.net/bnjSs/2/
I have tried this but its not showing on correct positions as mouseover but once i mouseover on .vtip and then i click on #showTitles its working fine, I also need to toggle this behavior :
$("#showTitles").click(function(e,ui){
this.xOffset = 5;
this.yOffset = 10;
this.top = (e.pageY + yOffset);
this.left = (e.pageX + xOffset);
$('.vtip').each(function(index) {
title = $(this).text();
$('body').append( '<p id="vtip"><img id="vtipArrow" />' + title + '</p>' );
$('p#vtip #vtipArrow').attr("src", 'images/vtip_arrow.png');
$('p#vtip').css("top", this.top+"px").css("left",
this.left+"px").fadeIn("slow");
});
return false;
});
Thanks for any help.
IDs should be unique.finished
I've modified your current code to get it work under the current conditions. The function logic should be obvious because of the descriptive names. Fiddle: http://jsfiddle.net/bnjSs/7/
Update: Added show/hide text + feature to the code, as requested at the comments.
Update2: Taken care of whole code, improved efficiency.
You're overusing this. this.xOffset = 5 attaches xOffset to the element. Use var xOffset = 5 to define xOffset in the scope of the function. The code below has the following scope model:
$(document).ready(function(){
// Variables defined using `var` can be read by
// any function defined within this function
function vtip(){
// variables declared here can be read by any function defined inside vtip
// but cannot be read by methods outside vtip
function(){..} at .hover and .mousemove
// These functions also have an own scope, and variables defined using
// var cannot be read by anything outside these functions, even at vtip
$("#showTitles").click(function(e){
// variables declared here cannot be read by code outside this function
// This function can read any variable which is declared using var at
// $(document).ready
Note: "Declare" means "Define using var".
Final code:
// Run when the DOM is ready
//Note: $(function(){ is short for $(document).ready(function(){
$(function(){
var xOffset = 5; // x distance from mouse
var yOffset = 10; // y distance from mouse
var frozen_vtip = false; //Define it
var vtip = function() {
$(".displaytip").unbind().hover(
function(e) {
if(frozen_vtip) return;
this.t = this.title;
this.title = '';
var top = (e.pageY + yOffset);
var left = (e.pageX + xOffset);
$('<p class="vtip"><img class="vtipArrow" src=""/>' + this.t + '</p>').css("top", top+"px").css("left", left+"px").fadeIn("slow").appendTo(this);
},
function() {
if(frozen_vtip) return;
this.title = this.t;
$("p.vtip", this).fadeOut("slow").remove();
}
).mousemove(
function(e) {
if(frozen_vtip) return;
var top = (e.pageY + yOffset);
var left = (e.pageX + xOffset);
$("p.vtip", this).css("top", top+"px").css("left", left+"px");
}
);
};
vtip();
// Second function, when text is "Hide titles" it should
// prevent runing vtip() on mouseover (above function) and
// when text is "Show titles" It should normally run vtip()
// (mouseover display title.
$("#showTitles").click(function(e){
e.preventDefault();
if($(this).text() == "Hide titles"){
$(this).text("Show titles");
$('p.vtip').fadeOut("slow").remove();
$('.displaytip').each(function(){
this.title = this.t; //Re-attach `title`
});
frozen_vtip = false;
} else {
frozen_vtip = true;
$(this).text("Hide titles");
$('.displaytip').each(function(index) {
if($('p.vtip', this).length) {return;}
this.t = this.title;
this.title = '';
var $this = $(this);
var offset = $this.offset();
var height = $this.height();
var top = offset.top + height;
var left = offset.left + height;
$('<p class="vtip"><img class="vtipArrow" src="images/vtip_arrow.png" />' + this.t + '</p>' ).appendTo(this).css("top", top+"px").css("left", left+"px").fadeIn("slow");
});
}
});
});

Javascript - Designpattern suggestion needed

Hallo,
I have 3 Different function in Javascript, the first one replaces HTML Selectboxs width custom selectbox created with ULs.
and the other 2 replace Checkbox and Radio buttons respectivly.
Now I want to derive classes out of these functions, and need your suggestions, what will be the best way to organize these functions into class, whether inheretance is possible?
I really appriciate your help.
Thanks.
Here is some sample code.
function replaceSelect(formid) {
var form = $(formid);
if (!form) return;
invisibleSelectboes = document.getElementsByClassName("optionsDivInvisible");
if (invisibleSelectboes.length > 0) {
for (var i = 0; i < invisibleSelectboes.length; i++) {
document.body.removeChild(invisibleSelectboes[i]);
}
}
var selects = [];
var selectboxes = form.getElementsByTagName('select');
var selectText = "Bitte auswählen";
var selectRightSideWidth = 21;
var selectLeftSideWidth = 8;
selectAreaHeight = 21;
selectAreaOptionsOverlap = 2;
// Access all Selectboxes in Search mask.
for (var cfs = 0; cfs < selectboxes.length; cfs++) {
selects.push(selectboxes[cfs]);
}
// Replace the select boxes
for (var q = 0; q < selects.length; q++) {
if (selects[q].className == "") continue;
var onchangeEvent = selects[q].onchange;
//create and build div structure
var selectArea = document.createElement('div');
var left = document.createElement('div');
var right = document.createElement('div');
var center = document.createElement('div');
var button = document.createElement('a');
// var text = document.createTextNode(selectText);
var text = document.createTextNode('');
center.id = "mySelectText" + q;
if ( !! selects[q].getAttribute("selectWidth")) {
var selectWidth = parseInt(selects[q].getAttribute("selectWidth"));
} else {
var selectWidth = parseInt(selects[q].className.replace(/width_/g, ""));
}
center.style.width = selectWidth + 'px';
selectArea.style.width = selectWidth + selectRightSideWidth + selectLeftSideWidth + 'px';
if (selects[q].style.display == 'none' || selects[q].style.visibility == 'hidden') {
selectArea.style.display = 'none';
}
button.style.width = selectWidth + selectRightSideWidth + selectLeftSideWidth + 'px';
button.style.marginLeft = -selectWidth - selectLeftSideWidth + 'px';
// button.href = "javascript:toggleOptions( + q + ")";
Event.observe(button, 'click', function (q) {
return function (event) {
clickObserver(event, q)
}
}(q));
button.onkeydown = this.selectListener;
button.className = "selectButton"; //class used to check for mouseover
selectArea.className = "selectArea";
selectArea.id = "sarea" + q;
left.className = "left";
right.className = "right";
center.className = "center";
right.appendChild(button);
center.appendChild(text);
selectArea.appendChild(left);
selectArea.appendChild(right);
selectArea.appendChild(center);
//hide the select field
selects[q].style.display = 'none';
//insert select div
selects[q].parentNode.insertBefore(selectArea, selects[q]);
//build & place options div
var optionsDiv = document.createElement('div');
if (selects[q].getAttribute('width')) optionsDiv.style.width = selects[q].getAttribute('width') + 'px';
else optionsDiv.style.width = selectWidth + 8 + 'px';
optionsDiv.className = "optionsDivInvisible";
optionsDiv.id = "optionsDiv" + q;
optionsDiv.style.left = findPosX(selectArea) + 'px';
optionsDiv.style.top = findPosY(selectArea) + selectAreaHeight - selectAreaOptionsOverlap + 'px';
//get select's options and add to options div
for (var w = 0; w < selects[q].options.length; w++) {
var optionHolder = document.createElement('p');
if (selects[q].options[w].className == "informal") {
var optionLink = document.createElement('a');
var optionTxt = document.createTextNode(selects[q].options[w].getAttribute('text'));
optionLink.innerHTML = selects[q].options[w].getAttribute('text');
optionLink.className = "informal";
cic.addEvent(optionLink, 'click', function (event) {
Event.stop(event);
});
Event.observe(optionLink, 'mouseover', function (event) {
Event.stop(event);
});
Event.observe(optionLink, 'mouseout', function (event) {
Event.stop(event);
});
}
else {
var optionLink = document.createElement('a');
var optionTxt = document.createTextNode(selects[q].options[w].text);
optionLink.appendChild(optionTxt);
cic.addEvent(optionLink, 'click', function (id, w, q, onchangeEvent) {
return function () {
showOptions(q);
selectMe(selects[q].id, w, q, onchangeEvent);
}
}(selects[q].id, w, q, onchangeEvent));
}
//optionLink.href = "javascript:showOptions(" + q + "); selectMe('" + selects[q].id + "'," + w + "," + q + ");";
optionHolder.appendChild(optionLink);
optionsDiv.appendChild(optionHolder);
if (selects[q].options[w].selected) {
selectMe(selects[q].id, w, q);
}
}
document.getElementsByTagName("body")[0].appendChild(optionsDiv);
Event.observe(optionsDiv, 'mouseleave', function (submenuid) {
optionsDiv.className = 'optionsDivInvisible'
});
cic.addEvent(optionsDiv, 'click', function (event) {
if (event.stopPropagation) event.stopPropagation();
else event.cancelBubble = true;
});
}
form.setStyle({
visibility: 'visible'
});
}​
From the sounds of it, you're looking to create a unified API to encapsulate all of this "form enhancing" functionality. Possibly something like this:
var formEnhancement = {
SelectBox: function(){ /* ... */ },
CheckBox: function(){ /* ... */ },
RadioButton: function(){ /* ... */ }
};
formEnhancement.SelectBox.prototype = { /* ... define methods ... */ };
// etc. (other prototypes)
// Call something:
var myEnhancedSelectBox = new formEnhancement.SelectBox(
document.getElementById('id-of-a-select-box')
);
Does this answer your query?
I'd go with
var Library = (function()
{
function _selectBox()
{
// stuff
}
function _checkBox()
{
// stuff
}
function _radioButton()
{
// stuff
}
return {
SelectBox : _selectBox,
CheckBox : _checkBox,
RadioButton : _radioButton
};
})();
or
var Library = (function()
{
return {
SelectBox : function()
{
// stuff
},
CheckBox : function()
{
// stuff
},
RadioButton : function()
{
// stuff
}
};
})();
[Edit]
this way, you can actually declare "private" variables that can be accessible only from the library itself, just declaring var foo="bar"; inside Library's declaration, makes a foo variable that can't be accessed from outside, but can be accessed by anything within Library, this is why functions like _selectBox in my example remain private, but can still be accessed through Library.SelectBox, which would be the "public getter"
[/Edit]
also, instead of
var Library = (function(){})();
you could do something like this:
var Library = Library || {};
Library.UI = (function(){})();
this way, you can keep separate parts of your code library, you can keep them in separate files, which don't care about the order in which they are loaded, as long as they have
var Library = Library || {};
on top of them
the functions would then be called like this:
Library.SelectBox();
or in the case you chose to go with "subclasses"
Library.UI.SelectBox();
All the answers are general patterns I think none of them is really helpful. Just because you put your 3 huge function into an object doesn't make your code modular, reusable, maintainable.
So my first suggestion is to utilize function decomposition. You've mentioned inheritance. Now if your code is basically made of this 3 giant functions nothing can be inherited or shared. You should separate function logic by purpose into smaller, more straighforward ones.
A good example is that you've mentioned the word replacing is relevant in all your cases. Maybe you can set up a function that is responsible for DOM replacement independently of the element's type. Such function can be shared between your modules making your code more robust and allowing you to DRY.
The best way to organize this process is called wishful thinking, when you solve your problem with functions which are intuitive and helpful even though they may not even exist. This is related to how you can design effective interaces.
Put the functions in a namespace:
Declare it like this:
FormUtils = {};
and add its properties, which will be your functions
FormUtils.replaceSelect = function () {/*your code*/};
FormUtils.replaceCheckbox = function () {/*your code*/};
FormUtils.replaceRadio = function () {/*your code*/};
then you call this functions with their namespace:
FormUtils.replaceSelect();
This is a simple and very accepted design pattern to javascript

Categories