I am writing a Windows 8 JavaScript Store App (using Cordova). When I use jQuery with Windows 8, why is it I have to modify the jQuery library to use the following for a few of the functions?
MSApp.execUnsafeLocalFunction
Preferably I would prefer not to do this as it is a slight inconvenience whenever a new version of jQuery Mobile is release (which, thankfully, is not often) - is there a setting in the project to disable this?
I am using jQuery v1.9.1 and jQuery Mobile v1.3.2 (which are the latest stable releases). I read this is fixed as of jQuery 2.x - can someone confirm whether this is true?
If so, is it unsafe to use jQuery 2.x in my mobile app project? Are there functions in jQuery v1.9.1 which jQuery Mobile v1.3.2 rely on, which are unavailable in jQuery v2.0?
You need to use MSApp.execUnsafeLocalFunction for certain functions because jQuery adds HTML in an, for Microsoft, unsafe way. Some HTML elements and attributes are considered unsafe and the App crashes when jQuery unsafely adds them to the DOM, using for instance append or innerHTML. The unsafe HTML elements and attributes can be found here.
This problem is as I know not fixed in jQuery 2.x. I'm still struggling to get the async page changes with unsafe keywords to work. I'll let you know when I have a workaround or fix.
Update: MSOpenTech created a JavaScript dynamic content shim which solves this problem. Take a look at my blog post or at their Github page.
Call this function in deviceready event and alert and jQuery html method will work everywhere
function WinAppHack() {
if (MSApp && MSApp.execUnsafeLocalFunction) {
// override jquery html method
var old_html = $.fn.html;
$.fn.html = function () {
var args = arguments;
var This = this;
var result = null;
//$(this).css('font-size', 24)
MSApp.execUnsafeLocalFunction(function () {
result = old_html.apply(This, args);
});
return result;
};
// override alert method
alert = function (msg, Closed) {
if (!Closed)
Closed = function () { };
navigator.notification.alert(
msg,
Closed,
'Message',
'OK'
);
};
}
}
Related
I'm somehow stuck with this code:
$(function () {
$('[data-toggle="tooltip"]').tooltip()
});
I'd like to change it to pure JavaScript. I'm not sure how to call the tooltip function, I already have some ideas like:
var tooltips = document.querySelectorAll("[data-toggle='tooltip']");
for(var i = 0; i < tooltips.length; i++){
//this gives an error
tooltips[i].tooltip();
}
I'm able to get all the tooltips, but I cannot initialize them. If I write something like this:
$(tooltips[i]).tooltip();
Then it works, but I want to remove the jQuery dependency since this is the only jQuery section that I have. Any idea? I've been searching and I cannot find anything useful.
For the new Bootstrap 5, this will be the new option without jQuery:
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
})
More info: https://getbootstrap.com/docs/5.0/components/tooltips/
Note:
In Bootstrap 4, you cannot initialize the Tooltips without jQuery. Here is an example:
https://jsfiddle.net/30c6kmnL/
There is a dependency on the function/class Tooltip that cannot be called (from my knowledge) without jQuery (you might need to rewrite the entire Tooltip function/class). I got errors like this one:
Uncaught TypeError: bootstrap.Tooltip is not a constructor
If you know how to fix it, please do it on the Snippet and share your results.
Thought I'd throw an answer out there using JS that also targets Bootstrap 4.x. The below code snippet will initialize all tooltips on the page in Bootstrap 4.x.
If you're unfamiliar with JavaScript classes and constructors then you may have trouble catching why the initialization didn't work in the original question.
Classes & Constructors: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor
Bootstrap 4.x —requires— JQuery (v3.2.1 slim at minimum) and the Tooltips component specifically require another library, Popper.js (v1.12.3 at minimum). However, the initialization can be written with simple JS (to call the JQuery based constructor for tooltips).
Note: the keyword new is missing from the OP's original question, this is needed to instantiate a new class instance for each element.
function setTooltips() {
let tooltips = document.querySelectorAll('[data-toggle="tooltip"]');
for(let i = 0; i < tooltips.length; i++) {
let tooltip = new bootstrap.Tooltip(tooltips[i]);
}
}
You could also use the mapping method shown by BS5 as it would still be calling the JQuery based constructor. As long as JQuery and Popper are present beforehand.
Also you don't necessarily need to save the instance into memory if you don't need to reference it later, just return it instead.
Preferably call this in a DOMContentLoaded event globally to target any tooltips on any page.
window.addEventListener('DOMContentLoaded', function() {
setTooltips();
}, false);
Bootstrap 5 does things differently, mainly dropping JQuery as a dependency in favor of more modern ES6 JS. Use Federico's answer for Bootstrap 5.x and up, which is the default example from the BS5 docs for initializing tooltips.
Bootstrap 5 is designed to be used without JQuery, but it's still
possible to use our components with JQuery. If Bootstrap detects
jQuery in the window object it will add all of our components in
jQuery’s plugin system...
See: https://getbootstrap.com/docs/5.0/getting-started/javascript/#still-want-to-use-jquery-its-possible
server side background, getting deeper and deeper into client side.
I've got a site with a lot of legacy that I'm new to, and I'm just trying to get a handle on how things are working/what's available.
Is there a way to have jquery tell me(for a page/pages) all its current info and any plugins it can/is use/ing, similar to what phpinfo does?
Some proof of concept how you can get names for all plugins
var plugins = (function() {
var plugins = [];
for(var plugin in jQuery.fn) {
plugins.push(plugin)
}
return plugins;
}());
var filterValue = ['constructor', 'init', 'add', 'parents'] // // you must add all standard methods here
filterValue.forEach(function(value) {
var position = function(value) {
return plugins.indexOf(value);
}
while(position(value) >= 0) {
plugins.splice(position(value), 1)
}
})
console.log(plugins)
You can use the following for jQuery
console.log( jQuery.fn.jquery );
To answer your question directly, No jQuery does not have a mechanism that lists installed plug-ins.
jQuery does not keep such a registry of installed plugins. The jQuery plugin mechanism is to just add a method to the jQuery prototype (right along-side all the other jQuery methods). So, there's no separate list of which methods have been added by some outside agent (e.g. a plug-in). In addition, there's no one-to-one correspondence between methods and a particular plug-in as a single plug-in could add multiple methods.
It would be possible to create a master list (for any specific jQuery version) of what methods are there by default and then enumerate a jQuery object to find out which methods have been added since then, but you'd have to create that master list ahead of time and store it or create the master list immediately after jQuery was loaded before any plug-ins were loaded.
You can always test to see if any specific jQuery plug-in is loaded by just checking to see if any of its signature methods are available on a jQuery object.
So, if you really just wanted to know which of 10 plugins happen to be available in any given page, you could write a quick function that would test for each of the 10 plugins (by looking for the existence of known methods in those plugins) and would return a list of the ones installed, but this has to be done with specific knowledge of each plugin as there is no "generic plugin identification mechanism" since a plug-in is nothing more than a piece of code that adds methods to the jQuery prototype. It doesn't actually have any identity of its own.
Hi I was wondering if there is the ability in node js and zombie js to inject javascript files in to the headless browser, similar to what you can do with phantomjs.
For example in phantom js you would do:
page.injectJs("amino/TVI.js")
I have used phantomjs and it does do what I want it to do but however I am testing other options due to the high memory required by using phantom js.
you can append script tag into document object since it support DOM API in zombie.
The following example shows how to insert jquery into zombie homepage:
var Browser = require("zombie");
var assert = require("assert");
// Load the page from localhost
browser = new Browser()
browser.visit("http://zombie.labnotes.org/", function () {
assert.ok(browser.success);
// append script tag
var injectedScript = browser.document.createElement("script");
injectedScript.setAttribute("type","text/javascript");
injectedScript.setAttribute("src", "http://code.jquery.com/jquery-1.11.0.min.js");
browser.body.appendChild(injectedScript);
browser.wait(function(window) {
// make sure the new script tag is inserted
return window.document.querySelectorAll("script").length == 4;
}, function() {
// jquery is ready
assert.equal(browser.evaluate("$.fn.jquery"), "1.11.0");
console.log(browser.evaluate("$('title').text()"));
});
});
Try to think the other way around. You have already everything at your hand in zombie to inject everything you want.
For example: that.browser.window points to the jsdom window that every part of your site javascript is using as a base. So you can access the dom and all other window objects in the page already loaded.
I don't know what you want to archieve with injecting - you should not use it for testing anway, but it looks this is not your actual goal
In my site I have a jquery function created by using the jQuery.fn method like so:
jQuery.fn.equalHeights = function() {
var currentTallest = 0;
jQuery(this).each(function(){
if (jQuery(this).height() > currentTallest) {
currentTallest = jQuery(this).height();
}
});
jQuery(this).css('min-height', currentTallest);
};
I use this function to equalize the size of sidebars on my site so I call it after the page has finished loading to make sure everything is in place before I do the sizing.
jQuery(window).load(function(){
jQuery('#sidebar-one, #sidebar-two, #content').equalHeights();
});
This works perfectly except for on some of my pages users will add another instance of the jQuery library to their page in the body area (for whatever reason). This second library causes my function to stop working properly. I'm assuming this is because the second jQuery overwrites any functions created with the jQuery.fn method. Is there any way to prevent that from happening?
Notes: My site is running Drupal 7 so I can't easily move the scripts to the bottom of the page. The equalHeights function was not written by me; I believe I found it here on stack so my knowledge of the fn method (and JS in general) is not that extensive.
EDIT: Based on all the great suggestions below, this is how I finally got it to work.
First, I give my "default" instance of jQuery a new variable to reference:
var JQ = jQuery.noConflict();
Second, I call the more efficient version of the equalHeights function using the new jQuery variable:
JQ.fn.equalHeights = function() {
var tallest = 0;
return this.each(function(){
var h = JQ(this).height();
tallest = h > tallest ? h : tallest;
}).css("minHeight", tallest);
};
Third, I call my function using the new jQuery variable:
JQ('#sidebar-one, #sidebar-two, #content').equalHeights();
So now any time I need to reference my original jQuery library I just use JQ and I don't have to worry about another library stepping on any of my functions.
I realize this isn't the best way to fix this problem and I'm going to work on eliminating the additional jQuery libraries but this will at least keep my sidebars properly sized in the mean time.
Wrap your snippet in a module IEFE, passing the "old" jQuery reference:
(function($) {
// $ will always point to the jQuery version with the `equalHeights` method
$(window).load(function(){
$('#sidebar-one, #sidebar-two, #content').equalHeights();
});
}(jQuery));
See also jQuery.noConflict for further tricks.
You could technically copy jQuery to a new variable just for your use - i.e. JQ = jQuery; then do JQ(this)...
Though you may just want to address the insertion of subsequent versions - stopping it, or ensuring your version is added last and all of your code is executed afterwards so they can't override it
This is because the second version of jQuery will overwrite the previous one. Unless you are using a legacy library that isn't compatible with later versions of jQuery, there's no reason to load two different versions.
To use a later version of jQuery with Drupal 7 you need to use the hook_js_alter script and then add something like the following to your Drupal theme (courtesy of oldwildissue):
function MYTHEME_js_alter(&$javascript) {
//We define the path of our new jquery core file
//assuming we are using the minified version 1.8.3
$jquery_path = drupal_get_path('theme','MYTHEME') . '/js/jquery-1.8.3.min.js';
//We duplicate the important information from the Drupal one
$javascript[$jquery_path] = $javascript['misc/jquery.js'];
//..and we update the information that we care about
$javascript[$jquery_path]['version'] = '1.8.3';
$javascript[$jquery_path]['data'] = $jquery_path;
//Then we remove the Drupal core version
unset($javascript['misc/jquery.js']);
}
This will allow you to use any version of jQuery with Drupal 7.
I also noticed that your plugin is using some pretty bad practices. Here's an optimized version of your plugin, using good and well established practices:
(function($){
$.fn.equalHeights = function() {
var tallest = 0;
return this.each(function(){
var h = $(this).height();
tallest = h > tallest ? h : tallest;
}).css("minHeight", tallest);
};
}(jQuery));
At first I made a function that received a parameter and returned jQuery such as:
function getjQuery(window)
{
/*jquery code*/(window);
return window.jQuery;
}
But then I got an email form the review and they told me I have to use jQuery file with the original file name and completely unmodified.
I started to search for an alternative and found this solution, but there is no way it work.
jQuery object is created, but I can't find any elements. $("#id").length is always 0. With the previous method it was always found.
My current code (which doesn't work)
AddonNameSpace.jQueryAux = jQuery;
AddonNameSpace.$ = function(selector,context) {
return // correct window
new AddonNameSpace.jQueryAux.fn.init(selector,context||contentWindow);
};
AddonNameSpace.$.fn =
AddonNameSpace.$.prototype = AddonNameSpace.jQueryAux.fn;
AddonNameSpace.jQuery = AddonNameSpace.$;
The jQuery file is loading on my browser.xul overlay:
<script type="text/javascript" src="chrome://addon/content/bin/jquery-1.5.2.min.js" />
Am I loading in the right place?
How can I use jQuery to modify the content on a page (HTML) with the original jQuery file, is it even possible?
You need pass the e.originalTarget.defaultView on the second parameter on jquery..
If you don't jquery will use window.document, which is the window.document from the xul.
Use
gBrowser.addEventListener("DOMContentLoaded", function (e) {
$("#id", e.originalTarget.defaultView).length
}, true);
instead of
$("#id").length;
And, for avoid conflicts with other extensions don't use script in the xul page, use MozIJSSubScriptLoader.
Components.classes["#mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader)
.loadSubScript("chrome://youraddon/content/jquery-1.5.2.min.js");
If you use this method, you load jquery only when you need, avoiding memory leak.
The preferred way to load it is with mozIJSSubScriptLoader so you don't collide with other's extensions. I'm not sure why you're having problems, I can use jQuery in my addon like $("#id").hide() with no additional code (although from the sidebar, now browser.xul).
Either way, this blog post provides a pretty good guide and even has an example xpi to download.