I need to add some functionality to a core JavaScript object function, without touching the original file.
How can I extend the following object function from my object below while keeping the namespace intact?
core object
(function() {
var DOM = tinymce.DOM;
tinymce.create('tinymce.plugins.WordPress', {
// i need to extend this function
_hideButtons : function() {
// stuff here
};
});
tinymce.PluginManager.add('wordpress', tinymce.plugins.WordPress);
})();
my object
I tried this, but it doesn't work:
(function() {
tinymce.create('tinymce.plugins.Mine', {
init : function(ed, url) {
ed.plugins.wordpress._hideButtons.prototype = function() {
// new function stuff
}
},
});
tinymce.PluginManager.add('mine', tinymce.plugins.Mine);
})();
Am I on the right track?
extending was, in fact, not what i needed.
by just removing .prototype above, allowed me to completely over write the function in question. this is exactly what i wanted to do.
check it...
(function() {
tinymce.create('tinymce.plugins.Mine', {
init : function(ed, url) {
ed.plugins.wordpress._hideButtons = function() {
// new function stuff
}
},
});
tinymce.PluginManager.add('mine', tinymce.plugins.Mine);
})();
Related
I try to change some way to call methods into namespace.
Calling parent methods (I dont think its possible)
Creating and call inheritance function
Calling inside another method (mostly jquery onReady event function) (this.MyFunction() not working)
I split every namespace in files (want to keep it that way)
I try How to call function A from function B within the same namespace? but I didn't succed to split namespaces.
my fiddle sample got only 1 sub-namespace but could be more.
https://jsfiddle.net/forX/kv1w2rvc/
/**************************************************************************
// FILE Master.js
***************************************************************************/
if (!Master) var Master = {};
Master.Print= function(text){
console.log("master.Print :" + text);
$("body").append("<div>master.Print : " + text + "</div>");
}
/**************************************************************************
// FILE Master.Test1.js
***************************************************************************/
if (!Master) var Master = {};
if (!Master.Test1) Master.Test1 = {};
/**************************************************************************
* Descrition :
* Function for managing event load/documentReady
**************************************************************************/
Master.Test1.onReady = function () {
$(function () {
Master.Test1.Function1(); //try to replace because need all namespace.
try {
this.Function2(); //not working
}
catch(err) {
console.log("this.Function2 not working");
$("body").append("<div>this.Function2 not working</div>");
}
try {
this.Print("onReady"); //not working
}
catch(err) {
console.log("this.Print not working");
$("body").append("<div>this.Print not working</div>");
}
try {
Print("onReady"); //not working
}
catch(err) {
console.log("Print not working");
$("body").append("<div>Print not working</div>");
}
});
}
Master.Test1.Function1 = function () {
console.log("Function1");
$("body").append("<div>Function1</div>");
this.Function3(); //working because not inside another function
}
Master.Test1.Function2 = function () {
$("body").append("<div>Function2</div>");
console.log("Function2");
}
Master.Test1.Function3 = function () {
$("body").append("<div>Function3</div>");
console.log("Function3");
Master.Print("Function3"); //try to replace because need all namespace.
}
Master.Test1.onReady();
I use Master.Test1.Function1(); and I want to change that because Function1 is inside the same namespace.
I use Master.Print("Function3"); I dont think I can change that. the way I try to use it, it's more an inheritance function. but I dont know if theres a way to do that?
Maybe I should change the my namespace methode? maybe prototype will do what I want?
You can capture the this in a variable because this inside $(function() {}) will point to document object. The below will work provided you never change the calling context of onReady -- i.e. it is always called on the Test1 object and not called on other context:
Master.Test1.onReady = function () {
var self = this;
$(function () {
self.Function1();
// ..
});
}
To access Print you have to reference using the Master object like: Master.Print() as it won't be available in the Test1 object
this is document within .ready() or jQuery() alias for .ready() where function(){} is parameter $(function() {}). this at this.Function2() will reference document.
"Objects" in javascript are not built the same way as in most object-oriented languages. Essentially, what you are building is a hierarchy of static methods that have no real internal state in-and-of themselves. Therefore, when one of the defined methods is invoked, the context (or state) of that method depends on what object invoked the method.
If you want to have any internal context, you will need to create an "instance" of an "object prototype". At that point, you can use "this.otherFunction" within your other functions. Here is a small example:
var MyObject = function() {};
MyObject.functionOne = function() {
console.log("Function 1");
this.functionTwo();
};
MyObject.functionTwo = function() {
console.log("Function 2");
};
var instanceOne = new MyObject();
instanceOne.functionOne();
You might get some more information about object definition here
How should I best go about overriding a JavaScript class method when it has been set up as per below. In this snippet, if I want to override the _other method from another JS file, loaded after this one, what is the correct way to go about it?
var review = {};
"use strict";
(function ($) {
review.list = {
_init: function () {
// The code I want to leave intact
},
_other: function () {
// The code I want to override
},
init: function () {
$(document).ready(function () {
review.list._init();
review.list._other();
});
}
};
review.list.init();
})(jQuery);
You can just assign to review.list._other. If you want to have access to the previous version, grab that first:
var oldOther = review.list._other;
review.list._other = function() {
// Your new code here, perhaps calling oldOther if you like
console.log("The new other code ran.");
};
Example:
// The original file
var review = {};
"use strict";
(function($) {
review.list = {
_init: function() {
// The code I want to leave intact
},
_other: function() {
// The code I want to override
},
init: function() {
$(document).ready(function() {
review.list._init();
review.list._other();
});
}
};
review.list.init();
})(jQuery);
// Your file after it
(function($) {
var oldOther = review.list._other;
review.list._other = function() {
// Your new code here, perhaps calling oldOther if you like
console.log("The new other code ran.");
};
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You're actually quite lucky it was written that way. It could easily have been written such that you couldn't override _other at all...
Slightly off-topic, but you've asked below:
Actually, does this class structure look reasonably sensible to you? Trying to dip toes into more OOP JS
I don't know your design constraints, so take anything that follows with a grain of salt... I should note that there's no "class" there at all (neither in the ES5 and earlier sense nor the ES2015 and later sense), just an object. (Which is fine.) But it looks like _init and _other are meant to be private; they could be genuinely private instead of pseudo-private without any cost — except then you wouldn't be able to override _other! :-) Separately, I would allow the overall controlling code to determine when the initialization happened instead of doing it on ready. (Separately, on a pure style note, I don't hold at all with this two-spaces-indentation nonsense so many of the l33t types seem to be promoting. If your code is so deeply nested that using only two spaces for an indent is necessary, it needs refactoring; four spaces is a good solid clear indent, in my view, without being so big it pushes your code off the right-hand side.)
So something like this if ES5 is required:
(function($) {
var list = {
init: function() {
_init();
_other();
}
};
function _init () {
// Can use `list` here to refer to the object
}
function _other() {
// Can use `list` here to refer to the object
}
review.list = list;
})(jQuery);
...but again, that makes it impossible (well, unreasonable) to override _other.
Or this if ES2015 and above is okay (for code this short, the differences are quite minor):
(function($) {
let list = {
init() {
_init();
_other();
}
};
function _init () {
// Can use `list` here to refer to the object
}
function _other() {
// Can use `list` here to refer to the object
}
review.list = list;
})(jQuery);
Just add your new override below... It will work...
var review = {};
"use strict";
(function($) {
review.list = {
_init: function() {
console.log('I\'m init')
},
_other: function() {
//This original will be overridden
console.log('Original')
},
init: function() {
$(document).ready(function() {
review.list._init();
review.list._other();
});
}
};
review.list.init();
})(jQuery);
review.list._other = function() {
console.log('overridden')
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Say I'm using a library with the code that looks like below:
(function($)
{
function Library(el, options)
{
return new Library.prototype.init(el, options);
}
Library.fn = $.Library.prototype = {
init: function(el, options) {
this.$elm.on('keydown.library', $.proxy(this.keydown.init, this));
}
keydown: function() {
return {
init: function(e) {
... somecode
},
checkStuff: function(arg1, arg2) {
...someCode
}
}
};
}
})(jQuery);
It has a plugin system that provides access to this where this is an Object {init: function, keydown: function...}. I want to override the keydown.init function. Normally I could see using something like _.wrap to do it:
somefunc = _.wrap(somefuc, function(oldfunc, args) {
donewstuff();
oldfunc.call(this.args);
});
but that doesn't seem to work on the returned nested method e.g.:
this.keydown.init = _.wrap(this.keydown.init, function(oldfunc, args) {
donewstuff();
oldfunc.call(this.args);
});
The question might be answered on here but I don't really know the right words to use to describe this style of coding so its hard to search. Bonus points if you let me know if it is even correct to call it a nested returned method?
This pattern is called a module. The best thing you can do here is cache the method you want to override and call the cached method inside your override:
somefunc._init = somefunc.init;
somefunc.init = function () {
doStuff();
this._init();
};
I checked _.wrap and it does the same thing, what your missing as pointed out by another answer is you're losing the context of somefunc. In order to prevent that you can do:
somefunc.init = _.wrap(_.bind(somefunc.init, somefunc), function (oldRef, args) {
doStuff();
oldRef.call(this.args);
});
You will need to decorate (read: wrap) the keydown function so that you can wrap the init method of the object it returns:
somefunc.keydown = _.wrap(somefunc.keydown, function(orig) {
var module = orig(); // it doesn't seem to take arguments or rely on `this` context
module.init = _.wrap(module.init, function(orig, e) {
donewstuff();
return orig.call(this, e);
});
return module;
});
The problem is that your method is run out of context.
You need to set its this context (use .bind() for this)
somefunc.init = _.wrap(somefuc.init.bind(somefunc), function(oldfunc, args) {
donewstuff();
oldfunc.call(this.args);
});
JSFiddle: http://jsfiddle.net/M2ALY/3/
My goal is to make a module that I can use and distribute. Therefore I must not pollute the global namespace. The module I'm making is also going to be used multiple times on one web page. That's why I chose to use OOP, but this introduced a problem.
I want my object to bind a function to be run when the user clicks an element in the DOM. In this simplified example I made, I want an alert box to pop up when the user clicks a paragraph. As an example, one of the things I need in the real project I'm working on is: The user clicks a canvas, the function figures out where the user clicked and saves it to this.clientX and this.clientY.
Instead of doing
this.bind = function() {
$("p1").bind('click', function() {
// code here
});
}
I figured it would work if I did:
this.bind = function() {obj.codeMovedToThisMethod()}
The problem is that this isn't a good design. Inside the "class" you shouldn't need to know the name of the object(s) that is going to be made of this "class". This doesn't get better when I'm making multiple objects of the "class"...
So I figured I could do
$("p1").bind('click', function(this) {
// code here
});
}
But it didn't work because sending this into the function didn't work as I thought.
How should I solve this problem?
Here is a simplified sample problem. (Same as JSFiddle.)
var test = function() {
this.alert = function() {
alert("Hi");
}
this.bind = function() {
$("#p1").bind('click', function() {
obj.alert();
});
}
}
window.obj = new test();
obj.bind();
// What if I want to do this:
var test2 = function() {
// Private vars
this.variable = "This secret is hidden.";
this.alert = function() {
alert(this.variable);
}
this.bind = function() {
$("#p2").bind('click', function(this) {
obj2.alert();
this.alert();
});
}
}
window.obj2 = new test2();
obj2.bind();
Thanks!
Read MDN's introduction to the this keyword. As it's a keyword, you can't use it as a parameter name.
Use either
this.bind = function() {
var that = this;
$("#p2").on('click', function(e) {
that.alert();
// "this" is the DOM element (event target)
});
}
or $.proxy, the jQuery cross-browser equivalent to the bind() function:
this.bind = function() {
$("#p2").on('click', $.proxy(function(e) {
this.alert();
}, this));
}
Is there way to override jQuery's core functions ?
Say I wanted to add an alert(this.length) in size: function()
Instead of adding it in the source
size: function() {
alert(this.length)
return this.length;
},
I was wondering if it would be possible to do something like this :
if (console)
{
console.log("Size of div = " + $("div").size());
var oSize = jQuery.fn.size;
jQuery.fn.size = function()
{
alert(this.length);
// Now go back to jQuery's original size()
return oSize(this);
}
console.log("Size of div = " + $("div").size());
}
You almost had it, you need to set the this reference inside of the old size function to be the this reference in the override function, like this:
var oSize = jQuery.fn.size;
jQuery.fn.size = function() {
alert(this.length);
// Now go back to jQuery's original size()
return oSize.apply(this, arguments);
};
The way this works is Function instances have a method called apply, whose purpose is to arbitrarily override the inner this reference inside of the function's body.
So, as an example:
var f = function() { console.log(this); }
f.apply("Hello World", null); //prints "Hello World" to the console
You can override plugins method by prototype it in a separate file without modifying original source file as below::
(function ($) {
$.ui.draggable.prototype._mouseDrag = function(event, noPropagation) {
// Your Code
},
$.ui.resizable.prototype._mouseDrag = function(event) {
// Your code
}
}(jQuery));
Now put your logic here or original code with your new idea that is needed in your project.