Javascript Global Variables used in different instances aka adSense - javascript

I have created a simple ad serving script, that you would call with global parameters, then call an external script that uses the parameters to display the adverts.
<script>
var ad_width = 100;
var ad_height = 200;
var ad_div = 'someDivID';
</script>
<script src='./js/ads.js'></script>
The ads.js has a function like:
(function(){
displayads = function(){
// do stuff here
}
displayads();
});
This works but when I have a second implementation the global variables are just over written, I need some form of encapsulation, javascript is not my foremost language so I am not sure what I am looking for.

I suppose if you want to allow multiple easy to configure ads then you could store them in an array:
var ads = [
{
width: 100,
height: 200,
div: 'someDivID'
},
...
];
Or if you think that's too hard for your customers you could allow them to write their variables like the following:
var ad1_width = 100;
var ad1_height = 200;
var ad1_div = 'someDivID';
var ad2_width = 200;
var ad2_height = 100;
var ad2_div = 'someOtherDivID';
Then in your code, you could check for their variables by checking against the window object:
for (var i = 1; ; i++) {
var widthKey = 'ad' + i + '_width',
heightKey = 'ad' + i + '_height',
divKey = 'ad' + i + '_div';
if (window.hasOwnProperty(widthKey)) {
displayAd(window[widthKey], window[heightKey], window[divKey]);
} else {
break;
}
}
It's weird and not exactly The Right Way(tm) but it does make it easy for end users to configure. Just make sure your customers always number them sequentially if you follow that way and that they're not using any other JS that could possible use any of the same variable names.
Another possibility would be to setup a property on the window to listen for when those variables are being set:
var adWidths = [],
adHeights = [],
adContainers = [];
Object.defineProperty(window, 'ad_width', {
set: function(val) {
adWidths.push(val);
}
});
Object.defineProperty(window, 'ad_height', {
set: function(val) {
adHeights.push(val);
}
});
Object.defineProperty(window, 'ad_div', {
set: function(val) {
adContainers.push(val);
}
});
Now your customers can set their ads just by doing:
ad_width = 200;
ad_height = 100;
ad_div = 'someDivID';
ad_width = 100;
ad_height = 200;
ad_div = 'someOtherDivID';
And you can access each ad with something like:
for (var i = 0, len = adWidths.length; i < len; i++) {
displayAd(adWidths[i], adHeights[i], adContainers[i]);
}
But this does require you to run some code both before they run there's and after. This solution is not compatible with older versions of IE either.

Related

How to properly structure class in Node.js

I have a class called TileStreamer that I am currently defining as follows:
function TileStreamer {
};
This class has constants, which I define as follows:
// Tiles are 256 x 256 pixels
TileStreamer.prototype.TILE_SIZE = 256;
// Header size in bytes
TileStreamer.prototype.HEADER_SIZE = 28;
// Various table entry sizes in bytes
TileStreamer.prototype.RESOLUTION_ENTRY_SIZE = 12;
TileStreamer.prototype.TILE_COUNT_SIZE = 4;
TileStreamer.prototype.TILE_ENTRY_SIZE = 12;
// Offsets within header
TileStreamer.prototype.WIDTH_OFFSET = 3;
TileStreamer.prototype.HEIGHT_OFFSET = 4;
TileStreamer.prototype.NUM_TABLES_OFFSET = 7;
TileStreamer.prototype.UNPOPULATED_OFFSET = 12092;
There also other variables. These variables are important because they need to be accessible from other classes. They get their values within the methods of this class. This is what I am unsure of as far as structure. What I'm currently trying is:
TileStreamer.prototype.header;
TileStreamer.prototype.resolutionEntry;
TileStreamer.prototype.resolutionTable;
TileStreamer.prototype.filepath;
TileStreamer.prototype.s3;
TileStreamer.prototype.level;
TileStreamer.prototype.ncols;
TileStreamer.prototype.nrows;
TileStreamer.prototype.nlevels;
TileStreamer.prototype.toffset;
TileStreamer.prototype.tsize;
TileStreamer.prototype.modifiedTime;
TileStreamer.prototype.tile;
TileStreamer.prototype.host;
TileStreamer.prototype.bucket;
This class also has methods such as:
TileStreamer.prototype.Init = function(filepath, index, s3config){
var retval = false;
AWS.config.update({accessKeyId: s3config.access_key, secretAccessKey: s3config.secret_key});
var blc = new BlockLibraryConfigs();
var awsConfig = blc.awsConfig;
AWS.config.update({region: awsConfig.region});
var aws = new AWS.S3();
var params = {
Bucket: s3config.bucket,
Key: s3config.tile_directory + filepath,
Range: 'bytes=0-' + (this.HEADER_SIZE - 1)
};
aws.getObject(params, function(err, data){
if(err == null){
TileStreamer.modifiedTime = data.LastModified;
var header = bufferpack.unpack('<7I', data.Body);
TileStreamer.header = header;
TileStreamer.nlevels = header[TileStreamer.NUM_TABLES_OFFSET];
if(TileStreamer.nlevels == 5){
TileStreamer.level = 0;
TileStreamer.ncols = Math.ceil((header[TileStreamer.WIDTH_OFFSET] * 1.0) / TileStreamer.TILE_SIZE);
TileStreamer.nrows = Math.ceil((header[TileStreamer.HEIGHT_OFFSET] * 1.0) / TileStreamer.TILE_SIZE);
}
}
});
};
The method above should set some of the values of the variables, such as modifiedTime so that I can access it in another class such as:
TileStreamer = require('tilestreamer.js');
var ts = new TileStreamer();
ts.Init(parPath, index, config);
var last_modified = ts.modifiedTime;
Just put any public properties you want to initialise when the object is created, directly in the init function. Here's a small example...
function TileStreamer() {
};
TileStreamer.prototype.Init = function() {
this.modifiedTime = new Date();
};
var ts = new TileStreamer();
ts.Init();
console.log(ts);
jsfiddle example
https://jsfiddle.net/v6muohyk/
To get around the issue you're having with setting the object properties in a callback from an asynchronous function, just create a locally accessible variable to reference the object that you are creating at that time...
TileStreamer.prototype.Init = function() {
var thisTileStreamer = this;
asynchFunction(function(err, data) {
thisTileStreamer.modifiedTime = data.lastModified;
});
};
To take it one step further, if you need to execute some code after the init function has completed, then that will require waiting for the asynchronous function to complete, as well. For that, pass a further parameter to init, that is a function to be executed after all the work is done...
TileStreamer.prototype.Init = function(callback) {
var thisTileStreamer = this;
asynchFunction(function(err, data) {
thisTileStreamer.modifiedTime = data.lastModified;
callback();
});
};
var ts = new TileStreamer();
ts.Init(function() {
// put code here that needs to be executed *after* the init function has completed
alert(ts.modifiedTime);
});

Js function always return the same values

Js beginner here.
I have a function like this:
generateSteps: function() {
var stepsLength = this.data.steps.length;
var dataStepsInit = this.data.steps;
for (var i = 0; i < stepsLength; i++) {
var stepsItem = dataStepsInit[i].ITEM;
var arrayItem = this.animationNodes[stepsItem - 1];
var transition = this.animationParameters[i].transition;
var options = this.animationParameters[i].options;
var speed = this.animationParameters[i].speed;
var delay = this.animationParameters[i].delay;
arrayItem.delay(delay).show(transition, options, speed);
if (dataStepsInit[i].AUDIOID) {
var audioClass = dataStepsInit[i].AUDIOID;
var audioPlayer = this.template.find("audio." + audioClass);
setTimeout(playAudioOnDelay,delay);
};
var playAudioOnDelay = function() {
audioPlayer[0].pause();
audioPlayer[0].currentTime = 0;
audioPlayer[0].play();
};
}
}
What it does is generate data from JSON and display animated elements one by one on delay. Animation part work fine. I can assign required animations and delay to DOM elements and show them in right order.
But what I want to do in the same time is also to play an audio on delay (so I use setTimeout). Everything is almost fine, I play audio in right time (correct delay value) but I always play the same audio (which is last element) because audioPlayer always is the same DOM node.
I think this have something to do with this or I mixed a scope?
Try this:
generateSteps: function() {
var stepsLength = this.data.steps.length;
var dataStepsInit = this.data.steps;
for (var i = 0; i < stepsLength; i++) {
var stepsItem = dataStepsInit[i].ITEM;
var arrayItem = this.animationNodes[stepsItem - 1];
var transition = this.animationParameters[i].transition;
var options = this.animationParameters[i].options;
var speed = this.animationParameters[i].speed;
var delay = this.animationParameters[i].delay;
arrayItem.delay(delay).show(transition, options, speed);
if (dataStepsInit[i].AUDIOID) {
var audioClass = dataStepsInit[i].AUDIOID;
var audioPlayer = this.template.find("audio." + audioClass);
setTimeout(playAudioOnDelay(audioPlayer),delay);
};
}
function playAudioOnDelay(audioPlayer){
return function(){
audioPlayer[0].pause();
audioPlayer[0].currentTime = 0;
audioPlayer[0].play();
}
}
}
Essentially, your problem looks like this: http://jsfiddle.net/po0rLnwo/
The solution is : http://jsfiddle.net/gpfuo1s8/
Check the console in your browser.

Javascript Function is not getting called when using modular pattern

I am trying to write my javascript code using modular pattern, but i am facing problem while calling the functions inside and also there are some security problems. I can easily open the console and type in my namespace name . variable and change the variable value.
JS
Below JS Code is working fine, but as i said i can change the gridValue from console. How do i avoid this. i will be using this variable across all my functions.
var myTicTacToe = {
turn:'X',
score: {
'X': 0,
'O': 0
},
gridValue: 0,
fnLoad:function () {
var select = document.getElementById("grid");
for (i = 3; i <= 100; i += 1) {
var option = document.createElement('option');
select.options[select.options.length] = new Option(i + ' X ' + i, i);
}
}
}
window.onload = function(){
myTicTacToe.fnLoad();
}
Below one is giving me problem while calling the fnLoad.
var myTicTacToe = function(){
var turn = 'X',
score = {
'X': 0,
'O': 0
},
gridValue = 0,
fnLoad = function () {
var select = document.getElementById("grid");
for (i = 3; i <= 100; i += 1) {
var option = document.createElement('option');
select.options[select.options.length] = new Option(i + ' X ' + i, i);
}
}
}
window.onload = function(){
myTicTacToe.fnLoad();
}
How can i protect my gridValue or any of the variable in First pattern ?
Why i am not able to call fnLoad just like first one ? how do i call it ?
Whats the difference between these 2 patterns ?
In the first code when i declared any variable using var, it gave me error. Why is it so ?
What you are referring to is the Revealing Module Pattern. Everything is private unless you explicitly return it
var myTicTacToe = (function(){
var turn = 'X',
score = {
'X': 0,
'O': 0
},
gridValue = 0,
fnLoad = function () {
var select = document.getElementById("grid");
for (i = 3; i <= 100; i += 1) {
var option = document.createElement('option');
select.options[select.options.length] = new Option(i + ' X ' + i, i);
}
};
return {
load: fnLoad //fnLoad is now publicly named "load".
};
})();
window.onload = function(){
myTicTacToe.load();
}
/* Or even
window.onload = myTicTacToe.load; //Because it's a single function.
*/
As for your concrete questions:
You can't. All object members are public by default with the normal Module Pattern.
Because you haven't returned it, see the example above.
One allows for private members, and one does not. The revealing pattern allows for privates.
I didn't understand which variable we are talking about. But if it's an object member, it should not be declared with a var.
You can use a closure to make gridValue a private variable. Consider this pattern:
var myTicTacToe = (function(){
var turn = 'X'.
score = {
'X': 0,
'O': 0
},
gridValue = 0;
return {
fnLoad: function () {
var select = document.getElementById("grid");
for (i = 3; i <= 100; i += 1) {
var option = document.createElement('option');
select.options[select.options.length] = new Option(i + ' X ' + i, i);
}
}
};
})();
window.onload = function(){
myTicTacToe.fnLoad();
}
Here we use an IIFE to close in the local variables so that only the fnLoad function has access to them. Later the fnLoad function is returned and invoked fill the namespace so it can be public ally accessed by other parts of your program.
This pattern can be extremely useful. Read more here: http://css-tricks.com/how-do-you-structure-javascript-the-module-pattern-edition/
This links is my constant reference when working with javascript. It does an amazing job of explaining the different patterns to use with javascript and I bet will help solve your issue.
http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/#designpatternsjavascript
Here is your code refactored to protect your private variables and only allow methods to be public that you declare. I am using the "Revealing Modular Pattern" below.
var myTicTacToe = (function () {
// PRIVATE AREA
var turn = 'X';
var score = {
'X': 0,
'O': 0
};
var gridValue = 0;
function fnLoad() {
var select = document.getElementById("grid");
for (i = 3; i <= 100; i += 1) {
var option = document.createElement('option');
select.options[select.options.length] = new Option(i + ' X ' + i, i);
}
}
// PUBLIC METHODS
return {
Load: fnLoad
}
})();
then call it like
myTicTacToe.Load();
If you need to pass a dependency in such as jQuery or another module you've created then you would create the parameter in the (function(HERE) and then pass it in at the bottom in the last set of parentheses. Here is an example of your code with jQuery.
var myTicTacToe = (function ($) {
// PRIVATE AREA
var turn = 'X';
var score = {
'X': 0,
'O': 0
};
var gridValue = 0;
function fnLoad() {
var select = $('#grid');
for (i = 3; i <= 100; i += 1) {
var option = document.createElement('option');
select.options[select.options.length] = new Option(i + ' X ' + i, i);
}
}
// PUBLIC METHODS
return {
Load: fnLoad
}
})($);

Javascript array results returning undefined

I have been working on a simple math game and am having problems getting the overall answer results to return after the end of the game.
Here is what my return function looks like
function pShowResults() {
var pNumResults = document.getElementById("results");
for (var i = 0; i <= 10; i++) {
pNumStore.push(pNumGuess[i]);
var pNumTable = document.createElement("div");
pNumTable.innerHTML = (pNumGuess[i]);
pNumResults.appendChild(pNumTable);
}
}
Here is the full script
Pretty much need debugging help. I new to this so I'm guessing there is a ton that's off, but as long as I can get the results fed back I should be fine.
You are not passing the value of x in many placess
$(document).ready(function () {
//declare arrays and variables for use below
var pNum1 = [];
var pNum2 = [];
var pNumAns = [];
var pNumGuess = [];
var pNumStore = [];
var pNumCarry = 0;
var pNumTrack = 0;
var pNumMessageRight = ['Awesome Job!', 'Correct!', 'Great Job!'];
var pNumMessageWrong = ['Oh No! That Was Wrong!', 'Incorrect!', 'That\'s Wrong'];
$(".Play").click(function () {
$("#popup").attr("class", "on");
pNumTrack = 0;
pNumGen(pNumTrack);
});
$(".pNumSubmit").click(function () {
pNumCalc(pNumTrack-1);
});
$(".pNumNext").click(function () {
pNumGen(pNumTrack);
});
function pNumGen(x) {
pNum1[x] = (Math.round(Math.random() * 51));
pNum2[x] = (Math.round(Math.random() * 51));
pNumAns[x] = pNum1[x] + pNum2[x];
$(".pNum1").html(pNum1[x]);
$(".pNum2").html(pNum2[x]);
$(".pNumGuess").val("");
$(".pNum1").html(pNumTrack[x]);
if (pNumTrack == 2) {
$(".pNumNext").html("");
$(".pNumSubmit").html("Close");
pShowResults();
}
pNumTrack++;
}
function pNumCalc(x) {
pNumGuess[x] = $(".pNumGuess").val();
if (pNumGuess[x] == pNumAns[x]) {
$(".message").html(pNumMessageRight[Math.floor(Math.random() * pNumMessageRight.length)]);
$(".pNumNext").html("Next Question >")
} else {
$(".message").html(pNumMessageWrong[Math.floor(Math.random() * pNumMessageWrong.length)]);
$(".pNumNext").html("Maybe The Next Question >")
}
}
function pShowResults() {
var pNumResults = document.getElementById("results");
for (var i = 0; i < pNumGuess.length; i++) {
pNumStore.push(pNumGuess[i]);
var pNumTable = document.createElement("div");
pNumTable.innerHTML = (pNumGuess[i]);
pNumResults.appendChild(pNumTable);
}
}
});
Demo: Fiddle
There is a function called pNumCalc in your code which you have set to take in an argument, but you never pass one in. You use the argument to store the results in the pNumGuess array, but since the argument is never passed in, the guesses are never stored, and you end up with undefined as the answers the user gave.
Updated fiddle: http://jsfiddle.net/dwdX9/2/. Not sure how close this is to what you actually want though, but hopefully it gets you on the right track.
Because StackOverflow wants code to to be included when JSFiddle is...:
pNumCalc(pNumTrack)
You forget to define array before use it.
function pShowResults() {
var pNumStore = new Array();
var pNumResults = document.getElementById("results");
for (var i = 0; i <= 10; i++) {
pNumStore.push(pNumGuess[i]);
var pNumTable = document.createElement("div");
pNumTable.innerHTML = (pNumGuess[i]);
pNumResults.appendChild(pNumTable);
}
}
I must suggest you should use jquery instead.
After visiting your Fiddle seems like there are many problems with the code. and also your question is unclear.
for e.g.
$(".pNumSubmit").click(function () {
//why x value not passed?
pNumCalc();
});
function pNumCalc(x) {
pNumGuess[x] = $(".pNumGuess").val();
if (pNumGuess[x] == pNumAns[x]) {
$(".message").html(pNumMessageRight[Math.floor(Math.random() * pNumMessageRight.length)]);
$(".pNumNext").html("Next Question >")
} else {
$(".message").html(pNumMessageWrong[Math.floor(Math.random() * pNumMessageWrong.length)]);
$(".pNumNext").html("Maybe The Next Question >")
}
}
Please clear which array is returning undefined so that others can help you.

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