Add function to existing JQuery plugin - javascript

Is it possible to add a function to a plugin without modifying the actual plugin? Can I do something like this in my site's js file?
$.fn.Watermark.Refresh = function() {
$.Watermark.HideAll();
$.Watermark.ShowAll();
}
or
(function($){
$.fn.Watermark.Refresh = function() {
$.Watermark.HideAll();
$.Watermark.ShowAll();
};
})(jQuery);
neither worked, the first says $ is undefined, the second that jQuery is undefined...
ideas?
Solution: Either method works, just include the jquery file before the site js file.

You can add those functions if you want to, but you'll have to make sure that you're also loading jQuery itself and the plugin to be modified. If you're getting those errors (that jQuery or "$" are not defined), then you have not correctly done that.
Now, though it's true that you can add those functions, I have to wonder what the point would be. If I were to do this, for example:
$.fn.css.myFunction = function() { return "hello world"; };
then it would be possible to call it:
var str = $.fn.css.myFunction();
but so what? What good does that do me? I don't think it's very useful.

Make sure you are including the plugin after jQuery.

Related

How to deal with DOM elements?

I am learning about writing custom JavaScript for my Odoo 10 addons.
I've written the following piece of code:
odoo.define('ioio.io', function(require) {
'use strict'
const e = $('div.o_sub_menu_footer')
console.log('--testing--'.repeat(7))
console.log(e)
// the "Powered by Odoo" down the secondary menu
e.remove()
})
The code is well loaded and I can see my testing string in the console.
However when this code is being loaded before the target div, so e empty/not yet filled and thus its content is not removed.
Doing it manually from the console works.
My question is what is the right way to do that? And how to know exactly when the code gets executed?
You can
put your html code before the script tag in your file
use jQuery $(document).ready(...);
Place your script at the bottom of the <body> tag to make sure the DOM renders before trying to manipulate it.
This is an Odoo specific question, so you should use the Odoo standard way, which is via its base JS class. That class contains a ready() method which does exactly what you need.
In your case, to use that function, you need to require the class first. Then you can use ready().
Updating your code, it should look like this:
odoo.define('ioio.io', function(require) {
'use strict'
// require base class
var base = require('web_editor.base');
//use its ready method
base.ready().done(function () {
// put all the code you want to get loaded
// once the DOM is loaded within this block
const e = $('div.o_sub_menu_footer')
console.log('--testing--'.repeat(7))
console.log(e)
// the "Powered by Odoo" down the secondary menu
e.remove()
});
})
While your accepted answer leads to the same outcome, you might want to update it to this one since this is the Odoo way. It's generally advised to work within the Odoo framework as much as possible and customise only if really needed. (Though it can be tough to learn what features Odoo already provides because of its poor documentation.)

Jquery No Conflict jquery-1.7.1.min.js

I am not too familiar with jQuery.noConflict. I have tried to implement it a couple times, but I feel I am doing it wrong.
Is there a way to set a noConflict with "jquery-1.7.1.min.js"? Do I put it in the actual file, or in the header of my index or both? I have tried to follow examples but I know I am doing it wrong.
Any guidance or quick examples would help me tremendously!
var foo = $.noconflict();
foo('body').addClass('bar');
You can either assign it a new alias (as shown above) or call $.noConflict and only have jQuery available for use. If you chose an alias though you must use that new alias every time you want to reference jQuery.
Keep in mind though that you can enable noConflict, but still have it available when necessary using an anonymous function:
// disable $ and force use of myJQ
var myJQ = jQuery.noConflict();
(function($){
//
// be able to use $ within this block and have it mean jQuery
//
$('body').addClass('foo');
})(myJQ);
// we're outside the block, now we're back to myJQ
myJQ('body').removeClass('foo');
No conflict mode is easy to use. Include this shortly after loading jQuery and any jQuery-dependent libraries:
var $j = jQuery.noConflict();
Then, instead of using $ for everything, use $j:
var elements = $j('.class-name');
Have you tried the following examples:
http://api.jquery.com/jQuery.noConflict/
I think it says all about it. Check your browser console to see any errors.
I'd recommend using a noConflict call, as well as wrapping your jQuery code with an anonymous function, so you can call jQuery by $:
jQuery.noConflict();
(function ($) {
// Now you can use $ to call jQuery
}(jQuery));

How to isolate different javascript libraries on the same page?

Suppose we need to embed a widget in third party page. This widget might use jquery for instance so widget carries a jquery library with itself.
Suppose third party page also uses jquery but a different version.
How to prevent clash between them when embedding widgets? jquery.noConflict is not an option because it's required to call this method for the first jquery library which is loaded in the page and this means that third party website should call it. The idea is that third party site should not amend or do anything aside putting tag with a src to the widget in order to use it.
Also this is not the problem with jquery in particular - google closure library (even compiled) might be taken as an example.
What solutions are exist to isolate different javascript libraries aside from obvious iframe?
Maybe loading javascript as string and then eval (by using Function('code to eval'), not the eval('code to eval')) it in anonymous function might do the trick?
Actually, I think jQuery.noConflict is precisely what you want to use. If I understand its implementation correctly, your code should look like this:
(function () {
var my$;
// your copy of the minified jQuery source
my$ = jQuery.noConflict(true);
// your widget code, which should use my$ instead of $
}());
The call to noConflict will restore the global jQuery and $ objects to their former values.
Function(...) makes an eval inside your function, it isn't any better.
Why not use the iframe they provide a default sandboxing for third party content.
And for friendly ones you can share text data, between them and your page, using parent.postMessage for modern browser or the window.name hack for the olders.
I built a library to solve this very problem. I am not sure if it will help you of course, because the code still has to be aware of the problem and use the library in the first place, so it will help only if you are able to change your code to use the library.
The library in question is called Packages JS and can be downloaded and used for free as it is Open Source under a Creative Commons license.
It basically works by packaging code inside functions. From those functions you export those objects you want to expose to other packages. In the consumer packages you import these objects into your local namespace. It doesn't matter if someone else or indeed even you yourself use the same name multiple times because you can resolve the ambiguity.
Here is an example:
(file example/greeting.js)
Package("example.greeting", function() {
// Create a function hello...
function hello() {
return "Hello world!";
};
// ...then export it for use by other packages
Export(hello);
// You need to supply a name for anonymous functions...
Export("goodbye", function() {
return "Goodbye cruel world!";
});
});
(file example/ambiguity.js)
Package("example.ambiguity", function() {
// functions hello and goodbye are also in example.greeting, making it ambiguous which
// one is intended when using the unqualified name.
function hello() {
return "Hello ambiguity!";
};
function goodbye() {
return "Goodbye ambiguity!";
};
// export for use by other packages
Export(hello);
Export(goodbye);
});
(file example/ambiguitytest.js)
Package("example.ambiguitytest", ["example.ambiguity", "example.greeting"], function(hello, log) {
// Which hello did we get? The one from example.ambiguity or from example.greeting?
log().info(hello());
// We will get the first one found, so the one from example.ambiguity in this case.
// Use fully qualified names to resolve any ambiguities.
var goodbye1 = Import("example.greeting.goodbye");
var goodbye2 = Import("example.ambiguity.goodbye");
log().info(goodbye1());
log().info(goodbye2());
});
example/ambiguitytest.js uses two libraries that both export a function goodbye, but it can explicitly import the correct ones and assign them to local aliases to disambiguate between them.
To use jQuery in this way would mean 'packaging' jQuery by wrapping it's code in a call to Package and Exporting the objects that it now exposes to the global scope. It means changing the library a bit which may not be what you want but alas there is no way around that that I can see without resorting to iframes.
I am planning on including 'packaged' versions of popular libraries along in the download and jQuery is definitely on the list, but at the moment I only have a packaged version of Sizzle, jQuery's selector engine.
Instead of looking for methods like no conflict, you can very well call full URL of the Google API on jQuery so that it can work in the application.
<script src="myjquery.min.js"></script>
<script>window.myjQuery = window.jQuery.noConflict();</script>
...
<script src='...'></script> //another widget using an old versioned jquery
<script>
(function($){
//...
//now you can access your own jquery here, without conflict
})(window.myjQuery);
delete window.myjQuery;
</script>
Most important points:
call jQuery.noConflict() method IMMEDIATELY AFTER your own jquery and related plugins tags
store the result jquery to a global variable, with a name that has little chance to conflict or confuse
load your widget using the old versioned jquery;
followed up is your logic codes. using a closure to obtain a private $ for convience. The private $ will not conflict with other jquerys.
You'd better not forget to delete the global temp var.

Weird Object Error in Javascript

First, I'm not a javascript developer so I don't have a great deal of experience in this if any.
I have a footer I'm inserting into an HTML page using jQuery that has the following code in it that per the client "NEEDS TO BE THERE".
<script language="JavaScript"><!--
/************* DO NOT ALTER ANYTHING BELOW THIS LINE ! **************/
var s_code=s.t();if(s_code)document.write(s_code)//--></script>
<script language="JavaScript"><!--
if(navigator.appVersion.indexOf('MSIE')>=0)document.write(unescape('%3C')+'\!-'+'-')
//--></script>
I don;t really have to worry about anything except this s.t(); line of code. I need to write a dummy Object or whatever else and include it in the header that doesn't do anything per se except prevent a javascript error from occurring.
So really I need "s" the object to be instantiated and have a function "t" attached to it that basically does nothing.
Any help is appreciated. This isn't something I want to do but given the budget and project constraints of the client I just need for this to work without a javascritp error.
thanks if you can help.
Using javascript prototype:
function s () {
}
function doSomething () {
}
s.prototype.t = doSomething;
edit: typo
var s = {
t: function(){}
};
See it in, hmm, action: http://jsbin.com/oboju
In case you're worried s is defined and don't want to override it, you can check for it first (this doesn't cover the case s.t is defined but isn't a function):
if(!s){ // check if s exists
var s = [];
}
if(!s.t){ // check if s has t
s.t = function(){};
}

Getting jQuery to work in Jetpack

I am experimenting with Jetpack and I would like to parse all the years in a given html page and then wrap the year with a link to the Wiki page. I tried the code in jquery and there it works but now I am using it in Jetpack and it gives an error $(doc).replace is not a function. I am definitely new to Jquery / Jetpack so maybe I am missing something really easy but your help is much appreciated.
EDIT: I have tried the suggestions but I am still stuck. The weird thing is that this
JQuery function works:
(function($) {
$.fn.clickUrl = function() {
var regexp = /([1-2][0-9][0-9][0-9])/gi;
this.each(function() {
$(this).html(
$(this).html().replace(regexp,'<ahref=\"http://nl.wikipedia.org/wiki/$1\">$1<\/a>')
);
});
return $(this);
}
})(jQuery);
and basically, I would like to 'port' this function to Jetpack.
This is the 'old' non-working port of my JQuery function to Jetpack:
jetpack.statusBar.append({
html: "Hyperlink Years",
width: 80,
onReady: function(widget){
$(widget).click(function(){
var regexp = /([1-2][0-9][0-9][0-9])/gi;
var doc = jetpack.tabs.focused.contentDocument;
$(doc).each(function() {
$(this).html(
$(doc).replace(regexp,'<a href=\"http://nl.wikipedia.org/wiki/$1\">$1<\/a>'));
});
return $(doc);
});
}
});
I'm not familiar with jetpack, but your jquery seems to be quite messed up.
If "doc" is an HTML document, then doing $(doc).each() doesn't really make sense. It would only loop once, and "this" would be the same as doc.
Then later you are doing $(doc).replace(regexp, ...), but replace() is not a jquery function. You might have wanted to do .html().replace(regexp, ...); HOWEVER, I do not recommend doing this because it will not work - you will just end up replacing any numbers in the document, even if they are part of another URL or the HTML of the page.
For more information, refer to this question or google for jquery text nodes:
Find text string using jQuery?

Categories

Resources