how to restore overriden javascript print method - javascript

My previous colleague rewrite window.print method:
function print(data){
var window_print = window.open('', 'my div', 'height=768, width=1024');
window_print.document.write('<!DOCTYPE html><html><head><title>Печать</title></head><body>' + data + '</body></html>');
window_print.print();
window_print.close();
}
My intention was to use default behavior of that function: just print current page, and I added:
if(data) {....} else { window.print() }
And of course I received error: "too much recursion: window.print();"
My question is how to invoke default behavior window.print()?

Edit: Ok, it appears that print is an own property of window in some browsers, and isn't in others. Therefore, just cache the value of window.print:
var printWindow = window.print;
// define your new print function here
var print = function(data) { ... };
// then later:
printWindow.call(window);
NB: If you're doing all this in the global scope, then you'll need to define the new print using a function expression (var print = ...) rather than a function declaration (function print(data) { ... }) because function declarations get hoisted to the top of their scope, and therefore the print redefinition would happen before you had chance to cache it. If you're not doing it in the global scope, then it doesn't matter as the new print won't override window.print regardless of how it's defined.
Original:
Try:
Object.getPrototypeOf(window).print.call(window);
print doesn't appear to be an own property of window, meaning that the newly defined print merely shadows something further up the prototype chain. You can bypass this shadowing by moving up the prototype chain using Object.getPrototypeOf.
You'll also need to use call so that the print method receives the correct value for this.

You need to store the original print method as another property in the window, just before the definition of your own print().
EDIT: You also need to define the new print function specifically as window.print = function(){...} rather than function print(){...} in order to be able to access the original - see answers with nice links here and here. This won't have any impact on how you call the method.
window.originalPrint = window.print;
window.print = function(data)
{
if(data)
{
document.getElementById('foo').innerHTML = data;
}
else
{
window.originalPrint();
}
}
<div id="foo"></div>
<button onclick="window.print('hello')">print('hello')</button>
<button onclick="window.print()">print()</button>

Related

React: Set values in Window coming back as undefined

I'm setting a script in my HTML for a geoplugin, assigning the results to the window, and trying to access the variables in a component. The issue is, in the component, I can console.log(window) and see the variables, but any dot notation results in undefined.
Here's the script in my HTML:
<script type="text/javascript">
setupGeo = (o) => {
//This is one way I've tried it, setting a Geo object
window.Geo = {};
Geo.geoplugin_city = o.city;
Geo.geoplugin_region = o.region;
console.log(Geo.geoplugin_city); //works and returns my city
console.log(Geo.geoplugin_region); //works and return my state
//This is a second way I've tried it, assigning it to a function that
//returns the variable
window.geoplugin_latitude = function() { return o.lat; };
window.geoplugin_longitude = function() { return o.lon; };
console.log(window.geoplugin_longitude); //returns function
console.log(window.geoplugin_longitude); //return function
}
</script>
<script type="text/javascript" src="//extreme-ip-lookup.com/json/?
callback=setupGeo" async></script>
As you can see, the script is working as intended. I tried two different ways to and included them both as examples.
In my React component, I am using a ComponentDidMount method to retrieve the values and will eventually set them to state.
Here's the problem: I can console window and see all values, but when I try to dot notation in I get undefined.
componentDidMount() {
console.log('componentmounted', window)
// Window ...{Geo:{geoplugin_city: "MyCity", geoplugin_region: "MyState"}}
// ...geoplugin_latitude: f() ... geoplugin_longitude: f()
console.log('componentmounted', window.Geo) // undefined
console.log('componentmounted', window.geoplugin_latitude) //returns
//function
console.log('componentmounted', window.geoplugin_latitude()) //gives error
//that window.geoplugin_latitude isn't a function
}
So, I can see the window variables I need, I just get access them inside the Window object. I've done research on how to use the Window Object, but that isn't the issue since I can see the variables in the Window Object. They just become undefined when I try to get to them for use. I've also tried with ComponentWillMount and even UNSAFE_componentWillMount(), but those aren't the issue since I'm retrieving the variables in Window.
Any ideas on how React works that is making this an issue, and how I can go into the Window to get the variables?

Isolating External Javascript from defining methods in the global (window) scope

I need to include a reference to JavaScript written by a third party on my website. Sadly, the developers that wrote this script decided to define all of their functions globally. You know, like this:
function AwesomeStringHelper() {
// ...
}
function MyGreatFunction() {
// ...
}
When I reference this script using a <script> tag, both of those methods will be added to the window object.
Since I prefer to not pollute the global scope, is there a way that I can change the scope of an external script? Ideally I'd like to be able to refer to these methods similar to ExternalLibrary.MyGreatFunction(), etc. I am not able to modify the third party script as it is hosted externally, and it changes frequently.
In the first instance, try to edumacate the third party developers on how to correctly write their modules.
If that doesn't work, do:
var ExternalLibrary = ExternalLibrary || window;
at the top of your code.
You can then use ExternalLibrary.MyGreatFunction() throughout to refer to their functions (even though they remain visible in the global window scope), and then later once the third party devs have fixed their scope issues then at most you need a one line change to maintain compatibility (or no change at all, if they happen to use the same ExternalLibrary name as you do).
Alternatively, use two simple snippets of code either side of the <script> tag which remember the keys of the window object, then move the newly appeared keys into a new object (at the same time deleting them from window):
Pre-load:
var ExternalLibrary = { _current: Object.keys(window) };
Post-load:
Object.keys(window).forEach(function(key) {
if (ExternalLibrary._current.indexOf(key) < 0) {
ExternalLibrary[key] = window[key];
delete window[key];
}
});
delete ExternalLibrary._current;
I've used a similar approach in the past (before strict mode was common) to check for leaking global variables.
If your third-party module assigns to the window object directly (like window.myGlobal = someValue), and you are able to download the source code manually, you should be able to "wrap" the entire script in a function, where the window object has been overloaded:
function wrapModule(code) {
// create a "fake" window object that inherits from the global object
var fakeWindow = Object.create(window);
// create a function wrapping the code
// note that "window" is a parameter name in this function, shadowing
// the global object
var func = Function("window", code);
// call function
func.call(fakeWindow, fakeWindow);
// return fake window object
return fakeWindow;
}
// run code
const fakeWindow = wrapModule(`
var x = 0; // local variable (will not be exported)
y = 1; // global variable (will still be leaked)
window.z = 2; // assignment to window
this.w = 3; // assignment to this
`);
// check what variables are exposed
console.log('window.x', typeof x); // window.x undefined
console.log('window.y', typeof y); // window.y number
console.log('window.z', typeof z); // window.z undefined
console.log('window.w', typeof w); // window.w undefined
// check what variables are exposed in fakeWindow
console.log('fakeWindow.x', typeof fakeWindow.x); // fakeWindow.x undefined
console.log('fakeWindow.y', typeof fakeWindow.y); // fakeWindow.y number
console.log('fakeWindow.z', typeof fakeWindow.z); // fakeWindow.z number
console.log('fakeWindow.w', typeof fakeWindow.w); // fakeWindow.w number
Assuming you know the specific functions being defined, then after the script is loaded, would this not work?
const ThirdPartyLib = {AwesomeStringHelper, MyGreatFunction};
delete window.AwesomeStringHelper;
delete window.MyGreatFunction;
ThirdPartyLib.AwesomeStringHelper(haveFun);
You can wrap the entire script in a function and return an object with the "public" functions you want, it can be tedious and hard to maintain.
var myLib = function() {
//entire script
return {
functionA : functionA,
functionB : functionB,
//rest of functions
}
}
Or like this (inmediately invoked function)
(function(global) {
//entire script
myLib.functionA = functionA;
myLib.functionB = functionB;
//rest of fn
global.myLib = myLib;
})(window);
You could automate this using gulp, i'm not sure if there's a good plugin for this.
Not sure if jQuery is an option or if you care for it but I don't know how to write native JS AJAX calls so bear with me:
$(document).ready(function(){
$.ajax({
url: 'www.example.com/awesome_script.js', // get the contents of the external script
type: 'GET',
crossDomain: true,
dataType: 'html',
success: function(data){
// build our script tag and wrap the contents inside of a function call
var script = "<script>"
script+= "var callMe = function(call_func, var1, var2, var3){";
script+= data;
script+= "return typeof call_func === 'function' ? call_func(var1, var2, var3) : 'You trying to dynamically call a variable? idk how to do that.';";
script+= "};";
script+= "<\/script>";
// assuming this is legal then just append the custom script tag to the <body> :-)
$('body').append($(script)[0]);
// profit?
callMe('AwesomeStringHelper', 'some_var'); // this function accepts one parameter
callMe('MyGreatFunction'); // this function accepts no parameters
}
});
});

Javascript function assigned to object cannot access inherited method

I'm no doubt doing something dumb here, but the following code results in an
error "this.getString is not a function."
This occurs because when unrelatedInstance calls stringGetter, "this" in showCombinedStrings() has the value of Unrelated....which actually seems fair enough, but how could this be set up so that it would work?
function BaseStringGetter() {
this.getString = function () {
return 'this is from BaseStringGetter';
}
}
function DerivedStringGetter() {
this.showCombinedStrings = function () {
console.log( 'this is from DerivedStringGetter and... ' + this.getString() );
}
}
DerivedStringGetter.prototype = new BaseStringGetter();
var stringGetterInstance = new DerivedStringGetter();
function Unrelated() {};
var unrelatedInstance = new Unrelated();
unrelatedInstance.stringGetter = stringGetterInstance.showCombinedStrings;
unrelatedInstance.stringGetter();
One option is this:
unrelatedInstance.stringGetter =
stringGetterInstance.showCombinedStrings.bind(stringGetterInstance);
unrelatedInstance.stringGetter();
Here, you're using Function.prototype.bind() to make this inside of unrelatedInstance.stringGetter() always refer back to stringGetterInstance.
The problem is how you are calling unrelatedInstance.stringGetter();
Even though stringGetter refers to the showCombinedStrings function, this inside showCombinedStrings now refers to the unrelatedInstance instance which does not have the toString() property that is why the error.
Demo: Fiddle
Here the value of this is printed as Unrelated {stringGetter: function} which is not an DerivedStringGetter instance
One easy solution is to use .bind() to give a custom execution context to unrelatedInstance.stringGetter like
unrelatedInstance.stringGetter = stringGetterInstance.showCombinedStrings.bind(stringGetterInstance);
Demo: Fiddle
Now even if you call unrelatedInstance.stringGetter(), this inside showCombinedStrings will refer to the stringGetterInstance instance.
When you call a function on an object, this will refer to the object the function is invoked on even if the function was originally defined elsewhere.
When you call unrelatedInstance.stringGetter();, this inside the function will now refer to unrelatedInstance which doesn't have getString(). The MDN this reference page has more info.
You could do something like this to preserve the original context:
unrelatedInstance.stringGetter = function() {
return stringGetterInstance.showCombinedStrings();
}
Edit: I left out bind that the other answers have now mentioned since it doesn't exist in IE8 but you'd be fine using that if you have a shim or don't care about old browsers.

Accessing a variable within a JavaScript object constructed via a function

My application is accessing a third party external JavaScript file that I cannot alter.
Within the file is an object defined similarly to as follows:
object_1 = (function(){
var object_1_var = 'object_1_var_value';
return {
obj_1_func: function() {
console.log(object_1_var);
}
}
})(window);
I need to be able access the object_1_var within the object, but I'm struggling to access it.
object_1.v // returns undefined
object_1.obj_1_func() // returns the value via console, but I need to assign it to a var.
I have tried extending the object using as follows: (Using jQuerys $.extend())
object_2 = (function(){
return {
obj_2_func: function() {
return object_1_var;
}
}
})(window);
$.extend(object_1, object_2);
var my_var = object_1.obj_2_func(); // returns 'Uncaught ReferenceError: object_1_var is not defined'
What can I do to be able to access object_1_var?
You will not be able to access the variable. It happens to be a private member. Private members of an object can be accessed only by its member functions.
Read this.
object_1_var is a lexically scoped local variable.
That means that it can't be accessed by extending object_1 outside of its original definition.
The only way it can be accessed is by adding functions within the original lexical scope in which it was declared:
object_1 = (function(){
var object_1_var = 'object_1_var_value';
return {
obj_1_func: function() {
console.log(object_1_var);
}
var_1: function(x) {
if (typeof x !== 'undefined') {
object_1_var = x;
} else {
return object_1_var;
}
}
}
})(window);
but since you can't modify object_1, you're out of luck, I'm afraid!
Make it public, like this:
object_1 = (function(){
var object_1_var = 'object_1_var_value';
return {
obj_1_func: function() {
console.log(object_1_var);
},
object_1_var: object_1_var
}
})(window);
EDIT
If unable to edit the javascript (such as in a third party library - sorry for omission) then you will not be able to have access to object_1_var as it's scope is local to the closure object_1.
What you are trying to accomplish is impossible in JS.
With the construction of object_1 the variable goes out of scope of that method. The reason why the logging function can access the variable is what we call 'a closure'.
Sadly, object_1_var isn't accessible in this example. The variable is defined as local to within that particular function - the only reason that the other functions can see it is because they are also defined within that function. This "closure scoping" is an interesting feature in JavaScript that you don't see very often elsewhere, but is the only real way of defining "private" variables in JavaScript Objects.
Hope that helps!
In a worst case scenario, in the past I've worked around this sort of issue by effectively overwriting the definition of an object that was previously defined elsewhere - mainly in Greasemonkey scripts - but I wouldn't condone this for production uses!
The trick here is to just copy the entire piece of script into your own. It's ugly as hell, but it might just work! (YMMV)

How to return name of the property an unnamed function is assigned to

I got following code:
function test () {
this.testFunction = function () {
//code to alert or return the string "testFunction"
}
}
var testVar = new test();
testVar.testFunction();
Is there a way to find out the name of the property, which the unnamed function is assigned to? Whatever I tried yet in conjunction with "caller" and "callee" methods didn't yield any success.
Edit:
The reason why I'd like to retrieve the property name is to use it for debugging messages, where I don't have to manually pass the property name to the logger. Performance would be not an issue since this is just for the developing process.
Actually the suggestion to name the function is a good idea ... I think. Does this have any obvious/well-known side effects, beside having to type in the function name twice? :-P
Additionally this brought me to the idea to add a comment at the start of a function which looks something like
/* $$NAME$$="testFunction" */
and which could also be parsed - but JavaScript comments seem to be trimmed in FireFox (unlike IE), and I rather prefer FF for developing. Would there be a way to also display/use JS comments in FF when using the "caller"/"callee" property?
You can cycle through everything that's available in the instance of the object, e.g.
function test() {
this.testFunction = function () {
for (var i in this) {
if (this[i] === arguments.callee) {
alert(i); // alerts 'testFunction'
}
}
}
}
var x = new test();
x.testFunction();
If your intent is to call the function recursively, you can simply name it
this.testFunction = function inner() {
inner();
}

Categories