We have Javascript library:
(function (global, factory) {
factory(global);
}(window , function() {
var MyLib = function(elem) {
return new MyLib.foo.init(elem);
}
MyLib.foo = {
init: function(elem) {
elem = typeof elem == 'string' ? window.document.getElementById(elem) : elem;
this[0] = elem;
return this;
},
test1: function() { // (1)
window.console.log('test1 ' + this[0].nodeName);
this[0].innerHTML = this[0].nodeName;
},
};
MyLib.foo.init.prototype = MyLib.foo;
MyLib.test2 = function() { // (2)
window.console.log('test2');
}
window.MyLib = window.ml = MyLib;
}));
function outerFunc(elem) {
ml(elem).test1();
ml.test2();
}
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
</head>
<body>
<script type="text/javascript" src="example.js"></script>
<div onclick="outerFunc(this)">button</div>
</body>
</html>
When should we create functions like (1) and when like (2)?
Of course, if it needs to get an element, we would always use (1), like MyLib().myFunc(), am I right?
And for all situations, where an element is not affected, we should create (2) ,like MyLib.myFunc()?
May be we miss something with variables' protection?
Related
I already imported
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
under the head section. But still I got,
RelatedObjectLookups.js:142 Uncaught TypeError: $ is not a function
at RelatedObjectLookups.js:142
at RelatedObjectLookups.js:175
(anonymous) # RelatedObjectLookups.js:142
(anonymous) # RelatedObjectLookups.js:175
(index):177 Uncaught TypeError: $ is not a function
at (index):177
Relavant html looks like,
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script crossorigin="anonymous" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script crossorigin="anonymous" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<link crossorigin="anonymous" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" rel="stylesheet">
</head>
<body>
<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="/static/admin/js/core.js"></script>
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"> </script>
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
<script type="text/javascript" src="/static/admin/js/actions.min.js"></script>
<script type="text/javascript" src="/static/admin/js/calendar.js"></script>
<script type="text/javascript" src="/static/admin/js/admin/DateTimeShortcuts.js"></script>
{{form.media}}
<div class="row">
<div class="col-6">
<form method="post" id="extendTrialForm" class="form">
{% csrf_token %}
{% bootstrap_field form.user %}
{% bootstrap_field form.core_instance %}
{% bootstrap_field form.expiry_datetime %}
{% buttons %}
<button type="submit" class="btn btn-primary">Submit</button>
{% endbuttons %}
</form>
</div>
</div>
<script>
$( document ).ready(function() { // line no 177
Removing the script tags above {{form.media}} won't throw any error related to jquery but it misses the widget functionality. I need that script tags but I don't want Jquery to return $ is not a function. I have tried adding $.noconflict, jQuery(document).ready but nothing works.
RelatedObjectsLookups.js
/*global SelectBox, interpolate*/
// Handles related-objects functionality: lookup link for raw_id_fields
// and Add Another links.
(function($) {
'use strict';
// IE doesn't accept periods or dashes in the window name, but the element IDs
// we use to generate popup window names may contain them, therefore we map them
// to allowed characters in a reversible way so that we can locate the correct
// element when the popup window is dismissed.
function id_to_windowname(text) {
text = text.replace(/\./g, '__dot__');
text = text.replace(/\-/g, '__dash__');
return text;
}
function windowname_to_id(text) {
text = text.replace(/__dot__/g, '.');
text = text.replace(/__dash__/g, '-');
return text;
}
function showAdminPopup(triggeringLink, name_regexp, add_popup) {
var name = triggeringLink.id.replace(name_regexp, '');
name = id_to_windowname(name);
var href = triggeringLink.href;
if (add_popup) {
if (href.indexOf('?') === -1) {
href += '?_popup=1';
} else {
href += '&_popup=1';
}
}
var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
win.focus();
return false;
}
function showRelatedObjectLookupPopup(triggeringLink) {
return showAdminPopup(triggeringLink, /^lookup_/, true);
}
function dismissRelatedLookupPopup(win, chosenId) {
var name = windowname_to_id(win.name);
var elem = document.getElementById(name);
if (elem.className.indexOf('vManyToManyRawIdAdminField') !== -1 && elem.value) {
elem.value += ',' + chosenId;
} else {
document.getElementById(name).value = chosenId;
}
win.close();
}
function showRelatedObjectPopup(triggeringLink) {
return showAdminPopup(triggeringLink, /^(change|add|delete)_/, false);
}
function updateRelatedObjectLinks(triggeringLink) {
var $this = $(triggeringLink);
var siblings = $this.nextAll('.change-related, .delete-related');
if (!siblings.length) {
return;
}
var value = $this.val();
if (value) {
siblings.each(function() {
var elm = $(this);
elm.attr('href', elm.attr('data-href-template').replace('__fk__', value));
});
} else {
siblings.removeAttr('href');
}
}
function dismissAddRelatedObjectPopup(win, newId, newRepr) {
var name = windowname_to_id(win.name);
var elem = document.getElementById(name);
if (elem) {
var elemName = elem.nodeName.toUpperCase();
if (elemName === 'SELECT') {
elem.options[elem.options.length] = new Option(newRepr, newId, true, true);
} else if (elemName === 'INPUT') {
if (elem.className.indexOf('vManyToManyRawIdAdminField') !== -1 && elem.value) {
elem.value += ',' + newId;
} else {
elem.value = newId;
}
}
// Trigger a change event to update related links if required.
$(elem).trigger('change');
} else {
var toId = name + "_to";
var o = new Option(newRepr, newId);
SelectBox.add_to_cache(toId, o);
SelectBox.redisplay(toId);
}
win.close();
}
function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) {
var id = windowname_to_id(win.name).replace(/^edit_/, '');
var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
var selects = $(selectsSelector);
selects.find('option').each(function() {
if (this.value === objId) {
this.textContent = newRepr;
this.value = newId;
}
});
win.close();
}
function dismissDeleteRelatedObjectPopup(win, objId) {
var id = windowname_to_id(win.name).replace(/^delete_/, '');
var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
var selects = $(selectsSelector);
selects.find('option').each(function() {
if (this.value === objId) {
$(this).remove();
}
}).trigger('change');
win.close();
}
// Global for testing purposes
window.id_to_windowname = id_to_windowname;
window.windowname_to_id = windowname_to_id;
window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup;
window.dismissRelatedLookupPopup = dismissRelatedLookupPopup;
window.showRelatedObjectPopup = showRelatedObjectPopup;
window.updateRelatedObjectLinks = updateRelatedObjectLinks;
window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup;
window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup;
window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup;
// Kept for backward compatibility
window.showAddAnotherPopup = showRelatedObjectPopup;
window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup;
$(document).ready(function() {
$("a[data-popup-opener]").click(function(event) {
event.preventDefault();
opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener"));
});
$('body').on('click', '.related-widget-wrapper-link', function(e) {
e.preventDefault();
if (this.href) {
var event = $.Event('django:show-related', {href: this.href});
$(this).trigger(event);
if (!event.isDefaultPrevented()) {
showRelatedObjectPopup(this);
}
}
});
$('body').on('change', '.related-widget-wrapper select', function(e) {
var event = $.Event('django:update-related');
$(this).trigger(event);
if (!event.isDefaultPrevented()) {
updateRelatedObjectLinks(this);
}
});
$('.related-widget-wrapper select').trigger('change');
$('body').on('click', '.related-lookup', function(e) {
e.preventDefault();
var event = $.Event('django:lookup-related');
$(this).trigger(event);
if (!event.isDefaultPrevented()) {
showRelatedObjectLookupPopup(this);
}
});
});
})(django.jQuery);
I’m pretty sure your whole problem is that the very end of your RelatedObjectsLookups.js JS file says django.jQuery, which doesn’t exist (or at least, the googleapis jQuery file you’re loading in isn’t going to define that). Change it to window.jQuery and things should work for you.
EDIT based on your reply
Since you can’t change the line that says django.jQuery, then let’s define that.
Right after you include your jQuery file, add the following tag.
<script>
django = django || {};
django.jQuery = django.jQuery || jQuery;
</script>
This will set django.jQuery to jQuery (which is included by your googleapis file), if it’s not been set yet. Now it will exist for your later scripts to use.
When using Selenium IDE to record actions on a web page the application is stopping the JavaScript and displays the error message "too much recursion."
I'm using Selenium IDE 2.9.1.1 on FireFox 54.0.1
I wrote a simple javascript alert for testing, but it is also being stopped by Selenium.
<html>
<head>
<script>
function hello(){
alert("Hello\nHow are you?");
}
</script>
</head>
<body>
<input type="button" onclick="hello();" value="Say Hi" />
</body>
</html>
enter image description here
selenium-ide/content/recorder.js
Recorder.prototype.reattachWindowMethods = function() {
var window = this.getWrappedWindow();
//this.log.debug("reattach");
if (!this.windowMethods) {
this.originalOpen = window.open;
}
this.windowMethods = {};
['alert', 'confirm', 'prompt', 'open'].forEach(function(method) {
this.windowMethods[method] = window[method];
}, this);
var self = this;
window.alert = function(alert) {
self.windowMethods['alert'].call(self.window, alert);
self.record('assertAlert', alert);
}
}
This is because the function calls are actually being overridden at runtime by Selenium’s own JavaScript.
Add below Javascript code to selenium core user extension, after restart can fix this problem.
//http://docs.seleniumhq.org/docs/08_user_extensions.jsp
Selenium.prototype.doExecute = function(script) {
this.browserbot.getCurrentWindow().eval(script);
};
Selenium.prototype.getExecute = function(script) {
return this.browserbot.getCurrentWindow().eval(script);
};
Selenium.prototype.getJqMethod = function(selector, method) {
return this.getExecute('$("' + selector + '").' + method + '();');
};
Selenium.prototype.getJqText = function(selector) {
return this.getJqMethod(selector, "text");
};
Selenium.prototype.getJqHtml = function(selector) {
return this.getJqMethod(selector, "html");
};
Selenium.prototype.getJqVal = function(selector) {
return this.getJqMethod(selector, "val");
};
PageBot.prototype.locateElementByJq = function(selector, inDocument) {
// FF/Chrome/IE9+: defaultView, OldIE: parentWindow
return (inDocument.defaultView || inDocument.parentWindow)
.eval("jQuery('" + selector.replace(/'/g, "\\'") + "')[0];");
};
i got a ajax procedure that is working ok, but now i need to add a new function to be called just once. so i add this to my current script to get the apex collection clean, but now nothing happens, i placed an alert to verify, but no alert is shown, i guess is because i am placing my clean script in wrong place or there must be something else missing.
// Clean Collection
function()
{
alert('Clean All');
var ajaxRequestd = new htmldb_Get(null,&APP_ID.,"APPLICATION_PROCESS=DEL_PRODUCTS",&APP_PAGE_ID.);
ajaxResult = ajaxRequestd.get();
}
here is my full script. thanks for your value tips !!
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Totals</title>
<script type="text/javascript">
$(function()
{
$("#Calculate").click
(
function()
{
// Clean Collection
function()
{
alert('Clean All');
var ajaxRequestd = new htmldb_Get(null,&APP_ID.,"APPLICATION_PROCESS=DEL_PRODUCTS",&APP_PAGE_ID.);
ajaxResult = ajaxRequestd.get();
}
$("input[name=f_qty]").each
(
function()
{
var valueInCurrentTextBox = $(this).val();
var productId = $(this).parents('tr').find("input[name=f_prod_id]").val();
$("#P12_PRODUCT_ID").val(productId);
if (valueInCurrentTextBox != '')
{
$("#P12_QTY").val(valueInCurrentTextBox);
var ajaxRequest = new htmldb_Get(null,&APP_ID.,"APPLICATION_PROCESS=ADD_PRODUCTS",&APP_PAGE_ID.);
ajaxRequest.add('P12_PRODUCT_ID',html_GetElement('P12_PRODUCT_ID').value);
ajaxRequest.add('P12_QTY',html_GetElement('P12_QTY').value);
ajaxResult = ajaxRequest.get();
}
}
);
alert('Updated!');
}
);
}
);
</script>
</head>
<body>
<div id="totals"></div>
<p align="center" style="clear: both;">
<button type="button" style="font-weight: bold;background-color:lightgray;margin-left:auto;margin-right:auto;display:block;margin-top:0%;margin-bottom:0%" id="Calculate">Add Products</button>
</p>
</body>
</html>
You're declaring that inner function, but never actually calling it. You could assign it to a variable and then call that, but it's actually not needed at all.
Try:
$(function()
{
$("#Calculate").click
(
function()
{
// Clean Collection
alert('Clean All');
var ajaxRequestd = new htmldb_Get(null,&APP_ID.,"APPLICATION_PROCESS=DEL_PRODUCTS",&APP_PAGE_ID.);
ajaxResult = ajaxRequestd.get();
$("input[name=f_qty]").each
(
function()
{
var valueInCurrentTextBox = $(this).val();
var productId = $(this).parents('tr').find("input[name=f_prod_id]").val();
$("#P12_PRODUCT_ID").val(productId);
if (valueInCurrentTextBox != '')
{
$("#P12_QTY").val(valueInCurrentTextBox);
var ajaxRequest = new htmldb_Get(null,&APP_ID.,"APPLICATION_PROCESS=ADD_PRODUCTS",&APP_PAGE_ID.);
ajaxRequest.add('P12_PRODUCT_ID',html_GetElement('P12_PRODUCT_ID').value);
ajaxRequest.add('P12_QTY',html_GetElement('P12_QTY').value);
ajaxResult = ajaxRequest.get();
}
}
);
alert('Updated!');
});
});
I have tested quite a bit about making classes, now I finally discovered how it works, that's what I want to make class simple and clear, without spamming 'this'
The result is like that, now I only have 2 questions:
redsheep.options.show().sizes, is to call out this variable, now I think it is too long. How do I make it like redsheep.sizes?
redsheep.options.show().eat is not inherit from the sheepclass grass, and became undefined. How do I make default values for newly created objects?
<html>
<head>
<meta charset='utf-8'>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<title>A simple javascript function</title>
<script type="text/javascript">
$(document).ready(function(){
var sheepclass = function(options){
this.options = {'sizes' : 'thin',
'eat' : 'grass',
'color' : 'white',
show : function(){
return {'color':options.color,
'eat':options.eat,
'sizes':options.sizes
};
}
}
}
var blacksheep = new sheepclass({'color':'black'});
var redsheep = new sheepclass({'color':'red','sizes':'fat'});
$('div').append('<p>blackcsheep color : ' +
blacksheep.options.show().color);
$('div').append('<p>redsheep color : ' +
redsheep.options.show().color +
'<p>redsheep size:' +
redsheep.options.show().sizes +
'<p> redsheep eat:' +
redsheep.options.show().eat);
})
</script>
<style>
div{display:block;width:800px;height:400px;border:2px solid red;}
</style>
</head>
<body>
<div>
Result:
</div>
</body>
</html>
Adding a method to an object that returns its own properties is useless. Remove that and access the properties normally:
var sheepclass = function(options) {
this.options = $.extend({
'sizes': 'thin',
'eat': 'grass',
'color': 'white',
}, options);
}
You can access it like this:
redsheep.options.eat
Something like that would do:
var sheepclass = function(options) {
this.sizes = options.sizes || 'thin';
this.eat = options.eat || 'grass';
this.color = options.color || 'white';
}
That way, you can access properties directly (by using for example blacksheep.sizes):
var blacksheep = new sheepclass({'color':'black'});
console.log(blacksheep.sizes); // prints 'thin'
<!--
Copyright (c) 2008 Google Inc.
You are free to copy and use this sample.
License can be found here: http://code.google.com/apis/ajaxsearch/faq/#license
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
</style>
<script src="https://www.google.com/jsapi?key=ABQIAAAAeEJvEumzGBw8dvenGPw1bRTcyTBaKMmwi780-Sh78Ay3Pg36mBRsO3t_v4eega6kiiiRMl84WG-4eA"></script>
<script type="text/javascript">
google.load('search', '1');
onload = function() {
google.search.Search.getBranding('branding');
//google branding
var searchResultsContainer = document.getElementById('searchResults');
var newsSearch = new google.search.NewsSearch();
newsSearch.setSearchCompleteCallback(this, function() {
if (newsSearch.results && newsSearch.results.length > 0) {
searchResultsContainer.style.display = 'block';
for (var i=0; i<newsSearch.results.length; i++) {
var wrapper = document.createElement('div');
var node = newsSearch.results[i].html.cloneNode(true);
wrapper.className = 'gs-result';
wrapper.appendChild(node);
searchResultsContainer.appendChild(wrapper);
}
}
},null);
newsSearch.execute("sport");
//keyword
}
</script>
</head>
<body>
<div>
<div id="branding" style="float:left;"></div>
<div id="searchResults"></div>
</div>
</body>
</html>
Hi, I want to make a Google news search, the above code runs well. However, I want to separate a js function. I use the following code, but the result shows nothing. How to modify it correctly?
<!--
Copyright (c) 2008 Google Inc.
You are free to copy and use this sample.
License can be found here: http://code.google.com/apis/ajaxsearch/faq/#license
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
</style>
<script src="https://www.google.com/jsapi?key=ABQIAAAAeEJvEumzGBw8dvenGPw1bRTcyTBaKMmwi780-Sh78Ay3Pg36mBRsO3t_v4eega6kiiiRMl84WG-4eA"></script>
<script type="text/javascript">
google.load('search', '1');
function searchcomplete() {
var newsSearch = new google.search.NewsSearch();
if (newsSearch.results && newsSearch.results.length > 0) {
searchResultsContainer.style.display = 'block';
for (var i=0; i<newsSearch.results.length; i++) {
var wrapper = document.createElement('div');
var node = newsSearch.results[i].html.cloneNode(true);
wrapper.className = 'gs-result';
wrapper.appendChild(node);
searchResultsContainer.appendChild(wrapper);
}
}
}
onload = function() {
google.search.Search.getBranding('branding');
//google branding
var searchResultsContainer = document.getElementById('searchResults');
var newsSearch1 = new google.search.NewsSearch();
newsSearch1.setSearchCompleteCallback(this, searchcomplete ,null);
newsSearch1.execute("sport");
//keyword
}
</script>
</head>
<body>
<div>
<div id="branding" style="float:left;"></div>
<div id="searchResults"></div>
</div>
</body>
</html>
A couple of problems here:
function searchcomplete() {
// you create a... uh new empty search here?
var newsSearch = new google.search.NewsSearch();
...
// searchResultsContainer is NOT defined in this scope
searchResultsContainer.style.display = 'block';
...
}
onload = function() {
// this defines searchResultsContainer in the scope of the onload callback,
// but NOT in the global scope
var searchResultsContainer = document.getElementById('searchResults');
...
// the first param is the thing that 'this' in the callback will refer to
// in this case it's the window but you need to change this in order
//to get access to the results
newsSearch1.setSearchCompleteCallback(this, searchcomplete ,null);
...
}
And here's a fixed version:
function searchcomplete() {
// Huh, why this? See below...
if (this.results && this.results.length > 0) {
// get 'searchResultsContainer' here
var searchResultsContainer = document.getElementById('searchResults');
searchResultsContainer.style.display = 'block';
for (var i=0; i < this.results.length; i++) {
var wrapper = document.createElement('div');
....
}
window.onload = function() {
...
// here we supply newsSearch itself as the 'this' so we can access
// its properties inside the callback
newsSearch.setSearchCompleteCallback(newsSearch, searchcomplete ,null);
...
}
You should read up a bit on this and scoping.
I don't know why you tried to do it in this way, but it's the working code:
...
<script type="text/javascript">
google.load('search', '1');
var newsSearch, searchResultsContainer;
function searchcomplete() {
// var newsSearch = new google.search.NewsSearch();
if (newsSearch.results && newsSearch.results.length > 0) {
searchResultsContainer.style.display = 'block';
for (var i=0; i<newsSearch.results.length; i++) {
var wrapper = document.createElement('div');
var node = newsSearch.results[i].html.cloneNode(true);
wrapper.className = 'gs-result';
wrapper.appendChild(node);
searchResultsContainer.appendChild(wrapper);
}
}
}
onload = function() {
google.search.Search.getBranding('branding');
//google branding
searchResultsContainer = document.getElementById('searchResults');
newsSearch = new google.search.NewsSearch();
newsSearch.setSearchCompleteCallback(this, searchcomplete ,null);
newsSearch.execute("sport");
//keyword
}
</script>
...
you don't have to define new variable newsSearch
you should define newsSearch and searchResultsContainer globally.
Happy coding :-)