So I have this really weird issue which I did not find any solution online.
No matter what page I create, either .html or .php I get this Promises javascript in the head section. Has anyone seen this before or what is this?
// Promises
var _eid_promises = {};
// Turn the incoming message from extension
// into pending Promise resolving
window.addEventListener("message", function(event) {
if(event.source !== window) return;
if(event.data.src && (event.data.src === "background.js")) {
console.log("Page received: ");
console.log(event.data);
// Get the promise
if(event.data.nonce) {
var p = _eid_promises[event.data.nonce];
// resolve
if(event.data.result === "ok") {
if(event.data.signature !== undefined) {
p.resolve({hex: event.data.signature});
} else if(event.data.version !== undefined) {
p.resolve(event.data.extension + "/" + event.data.version);
} else if(event.data.cert !== undefined) {
p.resolve({hex: event.data.cert});
} else {
console.log("No idea how to handle message");
console.log(event.data);
}
} else {
// reject
p.reject(new Error(event.data.result));
}
delete _eid_promises[event.data.nonce];
} else {
console.log("No nonce in event msg");
}
}
}, false);
function TokenSigning() {
function nonce() {
var val = "";
var hex = "abcdefghijklmnopqrstuvwxyz0123456789";
for(var i = 0; i < 16; i++) val += hex.charAt(Math.floor(Math.random() * hex.length));
return val;
}
function messagePromise(msg) {
return new Promise(function(resolve, reject) {
// amend with necessary metadata
msg["nonce"] = nonce();
msg["src"] = "page.js";
// send message
window.postMessage(msg, "*");
// and store promise callbacks
_eid_promises[msg.nonce] = {
resolve: resolve,
reject: reject
};
});
}
this.getCertificate = function(options) {
var msg = {type: "CERT", lang: options.lang};
console.log("getCertificate()");
return messagePromise(msg);
};
this.sign = function(cert, hash, options) {
var msg = {type: "SIGN", cert: cert.hex, hash: hash.hex, hashtype: hash.type, lang: options.lang};
console.log("sign()");
return messagePromise(msg);
};
this.getVersion = function() {
console.log("getVersion()");
return messagePromise({
type: "VERSION"
});
};
}
This is Selenium extension.
Selenium Record and Playback tool for ease of getting acquainted with Selenium WebDriver.
extension id: mooikfkahbdckldjjndioackbalpho...
Related
I'm using the TomTom FuzzySearch/Autocomplete API, to allow users to search for an address on a form and then the address input fields will prepopulate (with the address values), when the user selects an address.
My API call works absolutely fine and the input fields display the correct values.
The problem I have, is the input fields remain untouched, despite the fields having a value. (If I type document.getElementById("house-number-textbox").value, a value is returned).
How can I turned the input fields to be touched, when the input values are applied?
I noticed, if I type something in the input field, after my input values have been added, only then does the form register my inputs as valid/touched.
PS - The reason I am injecting my scripts is because I'm using an AB Testing tool. So despite the form/application being AngularJS, I can only manipulate the form via the AB Testing tool, (on top of the compiled codebase - hence why I'm using vanilla JS).
Here's my code:
function waitForElement(className, callBack){
window.setTimeout(function(){
var element = document.getElementById(className);
if(element) {
callBack(className, element);
} else {
waitForElement(className, callBack);
}
},2000)
};
// LOAD API SCRIPTS
function loadScript(scriptUrl) {
const script = document.createElement('script');
script.src = scriptUrl;
document.body.appendChild(script);
return new Promise((res, rej) => {
script.onload = function() {
res();
}
script.onerror = function () {
rej();
}
});
};
// RESULTS MANAGER
function appendParentSelector(parentSelector, selector) {
return parentSelector ? parentSelector + ' ' + selector : selector;
}
function ResultsManager(resultsElementSelector) {
this.resultsElement = document.querySelector(appendParentSelector(resultsElementSelector, '.js-results'));
this.resultsPlaceholder =
document.querySelector(appendParentSelector(resultsElementSelector, '.js-results-placeholder'));
this.resultsLoader = document.querySelector(appendParentSelector(resultsElementSelector, '.js-results-loader'));
}
ResultsManager.prototype.loading = function() {
this.resultsLoader.removeAttribute('hidden');
this.resultsElement.setAttribute('hidden', 'hidden');
this.resultsPlaceholder.setAttribute('hidden', 'hidden');
this.resultsElement.innerHTML = '';
};
ResultsManager.prototype.success = function() {
this.resultsLoader.setAttribute('hidden', 'hidden');
this.resultsElement.removeAttribute('hidden');
};
ResultsManager.prototype.resultsNotFound = function() {
this.resultsElement.setAttribute('hidden', 'hidden');
this.resultsLoader.setAttribute('hidden', 'hidden');
this.resultsPlaceholder.removeAttribute('hidden');
};
ResultsManager.prototype.append = function(element) {
this.resultsElement.appendChild(element);
};
ResultsManager.prototype.clear = function() {
for (var i = 0; i < this.resultsElement.children.length; i++) {
this.resultsElement.removeChild(this.resultsElement.children[i]);
}
};
waitForElement("house-number-textbox",function(){
console.log("WAIT FOR ELEMENT DONE");
window.ResultsManager = window.ResultsManager || ResultsManager;
console.log("document.getElementById(component)", document.getElementById("house-number-textbox") );
// use
loadScript('https://api.tomtom.com/maps-sdk-for-web/cdn/plugins/SearchBox/2.24.2//SearchBox-web.js')
.then(() => {
console.log('Script loaded!');
})
.catch(() => {
console.error('Script loading failed! Handle this error');
});
// use
loadScript('https://api.tomtom.com/maps-sdk-for-web/cdn/5.x/5.64.0/services/services-web.min.js')
.then(() => {
console.log('Script loaded!');
// HANDLE RESULTS
tt.setProductInfo('ABTest', '1');
// Options for the fuzzySearch service
var searchOptions = {
key: 'XXX',
language: 'en-Gb',
limit: 10,
countrySet: "GB"
};
var searchBoxOptions = {
minNumberOfCharacters: 1,
searchOptions: searchOptions
// autocompleteOptions: autocompleteOptions
};
var ttSearchBox = new tt.plugins.SearchBox(tt.services, searchBoxOptions);
document.querySelector('.tt-side-panel__header').appendChild(ttSearchBox.getSearchBoxHTML());
let componentForm = {
// streetName: "house-number-textbox",
municipalitySubdivision: "street-name-textbox",
localName: "town-city-textbox",
extendedPostalCode: "postcode-textbox"
};
function SidePanel(selector) {
// this.map = map;
this.element = document.querySelector(selector);
}
new SidePanel('.tt-side-panel');
var resultsManager = new ResultsManager();
ttSearchBox.on('tomtom.searchbox.resultscleared', handleResultsCleared);
ttSearchBox.on('tomtom.searchbox.resultsfound', handleResultsFound);
ttSearchBox.on('tomtom.searchbox.resultfocused', handleResultSelection);
ttSearchBox.on('tomtom.searchbox.resultselected', handleResultSelection);
function handleResultsCleared() {
resultsManager.clear();
}
// HANDLE RESULST
function handleResultsFound(event) {
// Display fuzzySearch results if request was triggered by pressing enter
if (event.data.results && event.data.results.fuzzySearch && event.data.metadata.triggeredBy === 'submit') {
var results = event.data.results.fuzzySearch.results;
if (results.length === 0) {
handleNoResults();
}
resultsManager.success();
console.log("results", results);
}
if (event.data.errors) {
console("event.data.errors", event.data.errors);
}
}
// RESPONSE
function handleResultSelection(event) {
if (isFuzzySearchResult(event)) {
// Display selected result on the map
var result = event.data.result;
console.log("THIS result", result);
;
resultsManager.success();
for (const component in componentForm) {
console.log("componentForm", componentForm);
document.getElementById(componentForm[component]).value = result.address[component];
document.getElementById(componentForm[component]).disabled = false;
console.log('component', componentForm[component]);
if (document.getElementById(componentForm[component]).value === 'undefined') {
document.getElementById(componentForm[component]).value = "";
}
};
if (result.address.streetNumber) {
document.getElementById("house-number-textbox").value = result.address.streetNumber + " " + result.address.streetName;
} else {
document.getElementById("house-number-textbox").value = result.address.streetName;
};
};
}
function isFuzzySearchResult(event) {
return !('matches' in event.data.result);
}
function handleNoResults() {
resultsManager.clear();
resultsManager.resultsNotFound();
searchMarkersManager.clear();
infoHint.setMessage(
'No results for "' +
ttSearchBox.getValue() +
'" found nearby. Try changing the viewport.'
);
};
document.querySelector(".tt-search-box-input").setAttribute("placeholder", "Enter your address...");
})
.catch(() => {
console.error('Script loading failed! Handle this error');
});
});
I want to assign videoLoaded to true right after myVideo.mp4 is fully loaded. I can do this at the last lines of the code (This is our promise):
preload.fetch([
clipSource
]).then(items => {
// Using a promise it'll fire when we are sure that video clip has finished loading completely
videoLoaded = true;
});
The first issue is if our URL is not valid we get a 404 response status code. the 404 itself is a valid response so we will not trigger xhr.onerror() because technically it's not an error.
we can track 404 status using:
xhr.onloadend = function() {
if(xhr.status == 404) { // do something }
}
The issue is onloadend event fired only after the promise .then(items => { .... so if there is not a valid URL we can not prevent the promise to resolve and videoLoaded will be assigned to true although there is not a valid URL...
I want to resolve the promise and assign videoLoaded to true only if xhr.status !== 404 in this situation we can be sure that we have a valid URL.
Here is the code (I have used a setInterval and it works but I think there are cleaner solutions that you can share):
let onLoadPassed = false;
let videoLoaded = false;
let clipSource = 'https://mysite/myVideo.mp4';
preload();
// Make sure the video clip is fully loaded
function preload(){
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.Preload = factory());
}(this, (function () { 'use strict';
function preloadOne(url, done) {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onprogress = event => {
if (!event.lengthComputable) return false
let item = this.getItemByUrl(event.target.responseURL);
item.completion = parseInt((event.loaded / event.total) * 100);
item.downloaded = event.loaded;
item.total = event.total;
this.updateProgressBar(item);
};
xhr.onload = event => {
let type = event.target.response.type;
let blob = new Blob([event.target.response], { type: type });
let url = URL.createObjectURL(blob);
let responseURL = event.target.responseURL;
let item = this.getItemByUrl(responseURL);
item.blobUrl = url;
item.fileName = responseURL.substring(responseURL.lastIndexOf('/') + 1);
item.type = type;
item.size = blob.size;
done(item);
};
xhr.onerror = event => {
console.log('Error has happend so we restart the video preloading..');
preload();
};
xhr.onloadend = function() {
if(xhr.status == 404){
console.log('404 not found');
onLoadPassed = false;
} else {
console.log('File exist');
onLoadPassed = true;
}
}
xhr.send();
}
function updateProgressBar(item) {
var sumCompletion = 0;
var maxCompletion = this.status.length * 100;
for (var itemStatus of this.status) {
if (itemStatus.completion) {
sumCompletion += itemStatus.completion;
}
}
var totalCompletion = parseInt((sumCompletion / maxCompletion) * 100);
if (!isNaN(totalCompletion)) {
this.onprogress({
progress: totalCompletion,
item: item
});
}
}
function getItemByUrl(rawUrl) {
for (var item of this.status) {
if (item.url == rawUrl) return item
}
}
function fetch(list) {
return new Promise((resolve, reject) => {
this.loaded = list.length;
for (let item of list) {
this.status.push({ url: item });
this.preloadOne(item, item => {
this.onfetched(item);
this.loaded--;
if (this.loaded == 0) {
this.oncomplete(this.status);
resolve(this.status);
}
});
}
})
}
function Preload() {
return {
status: [],
loaded: false,
onprogress: () => {},
oncomplete: () => {},
onfetched: () => {},
fetch,
updateProgressBar,
preloadOne,
getItemByUrl
}
}
return Preload;
})));
const preload = Preload();
preload.fetch([
clipSource
]).then(items => {
// Fired when we are sure that video clip has finished loading completely
let check = setInterval(passedFunc, 50);
function passedFunc() {
if(onLoadPassed === true){
videoLoaded = true;
clearInterval(check);
console.log('videoLoaded: ' + videoLoaded);
};
}
});
};
You can intercept the promise and throw an error if the status code is 404, this way the subsequent .then statements will be ignored and the result will be captured by the .catch statement.
preload.fetch([
clipSource
])
.then(response => {
if(!response.ok) //better to use response.ok as it checks a range of status codes
throw Error(response.statusText);
return response;
})
.then(items => {
// Using a promise it'll fire when we are sure that video clip has finished loading completely
videoLoaded = true;
})
.catch(error => {
//do something
console.log(error)
});
Given the following snippet of code
var empowerInstance = null;
function onClick_btnSendMessage() {
var childIFrame = window.document.getElementById("editorFrame");
if (!empowerInstance) {
empowerInstance = EditorAPI.getInstance(childIFrame.contentWindow, window.location.origin);
}
empowerInstance.document.hasChanged(hasChangedCallback);
}
function hasChangedCallback(returnValue) {
console.log("empowerInstance.document.hasChanged = " + returnValue.isDirty);
if (returnValue.success === true && returnValue.isDirty === true) {
empowerInstance.document.save(saveCallback);
}
}
function saveCallback(returnValue) {
console.log("empowerInstance.document.save = " + returnValue.success);
if (returnValue.success === false) {
console.log(returnValue.message);
}
}
window.addEventListener("DOMContentLoaded", function (event) {
console.log("DOM fully loaded and parsed");
if (typeof location.origin === "undefined")
window.location.origin = window.location.protocol + "//" + window.location.host;
document.getElementById("btnSendMessage").addEventListener("click", onClick_btnSendMessage);
});
Instead of wiring the button up , I'd like to fire the code from the activation of a Bootstrap tab event.
$('a[data-toggle="tab"]').on("shown.bs.tab", function (e) {
onClick_btnSendMessage(); // Naive way, as this does not wait
var target = $(e.target).attr("data-EditorUrl"); // activated tab
var childIFrame = $("#editorFrame");
childIFrame.attr("src", target);
});
So my question is "How do I wait on this function to complete before changing the source of childIFrame?".
empowerInstance.document.hasChanged(hasChangedCallback);
I conceptually understand the use of Promises and Callbacks, but writing one that functions correctly is a different story.
UPDATED
This version is refactored to eliminate the button handler, thus improving readability.
The usage is also important. When the page loads for the first time it is positioned on a tab. This tab is associated to a document that is hosted in an iFrame. If the user edits this document then tries to change tabs, I'd like to invoke the check for being dirty/save, then once saved, move to the next tab/document. There is also the case that switching between tabs/documents won't cause a save because the document is not dirty.
var empowerInstance = null;
function hasChangedCallback(returnValue) {
console.log("empowerInstance.document.hasChanged = " + returnValue.isDirty);
if (returnValue.success === true && returnValue.isDirty === true) {
empowerInstance.document.save(saveCallback);
}
}
function saveCallback(returnValue) {
console.log("empowerInstance.document.save = " + returnValue.success);
if (returnValue.success === false) {
console.log(returnValue.message);
}
}
$(function () {
if (typeof location.origin === "undefined") {
window.location.origin = window.location.protocol + "//" + window.location.host;
}
$('a[data-toggle="tab"]').on("shown.bs.tab", function (e) {
var childIFrame = $("#editorFrame");
if (!empowerInstance) {
empowerInstance = EditorAPI.getInstance(childIFrame[0].contentWindow, window.location.origin);
}
empowerInstance.document.hasChanged(hasChangedCallback);// Need to wait for completion
var target = $(e.target).attr("data-EditorUrl"); // activated tab
childIFrame.attr("src", target);
});
});
Thank you,
Stephen
I've refactored your code to show how this can be done using promises.
function onClick_btnSendMessage() {
var childIFrame = window.document.getElementById("editorFrame");
if (!empowerInstance) {
empowerInstance = EditorAPI.getInstance(childIFrame.contentWindow, window.location.origin);
}
var doc = empowerInstance.document;
return hasChanged(doc).then(function() { return save(doc) })
}
function hasChanged(doc) {
return new Promise(function(resolve, reject) {
doc.hasChanged(function(returnValue) {
if (returnValue.success === true && returnValue.isDirty === true) {
resolve(returnValue)
} else {
reject(returnValue)
}
})
})
}
function save(doc) {
return new Promise(function(resolve, reject) {
doc.save(function(returnValue) {
if (returnValue.success === false) {
console.log(returnValue.message);
reject(returnValue)
} else {
resolve(returnValue)
}
})
})
}
// ------
$('a[data-toggle="tab"]').on("shown.bs.tab", function(e) {
onClick_btnSendMessage().then(function() {
var target = $(e.target).attr("data-EditorUrl"); // activated tab
var childIFrame = $("#editorFrame");
childIFrame.attr("src", target);
}).catch(function(error) {
// handle the error
console.error('Error!', error)
})
});
You can use some higher order functions to do what you want. Instead of passing the hasChangedCallback and saveCallback directly to the empowerInstance.document methods, you'll instead invoke a function that returns those callbacks, but also passes along your own callback that you'll call once all the async operations have finally completed. Here's what it'll look like:
$('a[data-toggle="tab"]').on("shown.bs.tab", function (e) {
var target = $(e.target).attr("data-EditorUrl"); // activated tab
onClick_btnSendMessage(function () {
var childIFrame = $("#editorFrame");
childIFrame.attr("src", target);
});
});
function onClick_btnSendMessage(myCallback) {
var childIFrame = window.document.getElementById("editorFrame");
if (!empowerInstance) {
empowerInstance = EditorAPI.getInstance(childIFrame.contentWindow, window.location.origin);
}
empowerInstance.document.hasChanged(getHasChangedCallback(myCallback));
}
function getHasChangedCallback(myCallback) {
return function hasChangedCallback(returnValue, myCallback) {
console.log("empowerInstance.document.hasChanged = " + returnValue.isDirty);
if (returnValue.success === true && returnValue.isDirty === true) {
empowerInstance.document.save(getSaveCallback(myCallback));
}
}
}
function getSaveCallback(myCallback) {
return function saveCallback(returnValue) {
console.log("empowerInstance.document.save = " + returnValue.success);
if (returnValue.success === false) {
console.log(returnValue.message);
}
myCallback && myCallback(); // make sure myCallback isn't null before invoking
}
}
It's not exactly attractive, but it should get you what you want.
I currently have a chrome packaged app that we have also ported to iPad, but I want to make it install-able using node-webkit (nw.js) and I need to abstract the chrome packaged app API for use with chrome.fileSystem. The code I am currently using to save is as follows.
var downloadFile = function (readUrl, next) {
var xhr = new XMLHttpRequest();
xhr.open('GET', readUrl);
xhr.responseType = 'arraybuffer';
xhr.onload = function (e) {
if (this.status == 200) {
var response = this.response;
var params = {
type : 'saveFile',
suggestedName : fileNameNoExtension,
//my code will inject the extension but in this case i just put in txt
accepts : [{
extensions : ['.txt']
}
]
}
chrome.fileSystem.chooseEntry(params, function (writableFileEntry) {
debugger;
writableFileEntry.createWriter(function (writer) {
debugger;
writer.onwriteend = function (e) {
return next(null)
};
writer.onerror = function (e) {};
writer.write(new Blob([response], {
type : 'application/octet-stream'
}));
});
});
} else {
//alert
}
};
xhr.onprogress = function (evt) {
if (evt.lengthComputable) {
console.log('progress: ' + Math.round(evt.loaded * 100 / evt.total));
}
}
xhr.addEventListener("error", function () {
return next('error')
}, false);
xhr.addEventListener("abort", function () {
return next('abort')
}, false);
xhr.send();
}
I have created a file that I am calling interop.js I load this script into my index.html and it will handle all of the chrome packaged app API calls for fileStorage if it's a nw.js project. If it's a chrome packaged app, then chrome will handle it's own API.
//if process is undefined then it is not an nw.js project and we can ignore the rest of the code;
if (typeof process == 'undefined') {}
//this is a nw.js project, spoof the chrome packaged app API
else {
var fs = require('fs')
chrome = new function () {
var fileSystem = {
//callback return readableFileEntry, which has a
chooseEntry : function (params, callback) {
if (params.type == 'openFile') {
//open file choose
chooseFile(params, function (files) {
//this is technically an html5 "filelist" we need to turn it into an array if there is more
//than one, and just return the single file if there isn't
if (!files) {
return callback(null)
}
async.map(files, function (file, cb) {
//normally chrome provides a 'readablefileentry' that will only give you the file
//asynchronously using the file() function
file.file = function (next) {
return next(this);
}
cb(null, file)
}, function (err, files) {
if (files.length > 1) {
return callback(files);
} else {
return callback(files[0]);
}
})
})
} else if (params.type == 'saveFile') {
chooseFile(params, function (files) {
var file = files[0];
debugger;
file.createWriter = function (next) {
var writer = {
write : function (blob) {
debugger;
var reader = new FileReader()
reader.readAsArrayBuffer(blob)
reader.addEventListener('loadend', function (e) {
var binary = new Uint8Array(reader.result)
debugger;
fs.writeFile(file.path, new Buffer(binary), function (err) {
//if the on error and writeend has been defined then callback, otherwise throw the error and log success
if (err && writer.onerror) {
writer.onerror(err)
} else if (err) {
throw err
} else if (writer.onwriteend) {
writer.onwriteend()
} else {
console.log('file was written but no callback was defined')
}
})
});
}
}
return next(writer)
}
return callback(file)
})
}
function chooseFile(params, next) {
var fileHtml = '<input type="file"'
debugger;
if (params.acceptsMultiple)
fileHtml += ' multiple';
if (params.accepts && params.accepts.length > 0 && params.accepts[0].extensions) {
fileHtml += ' accept="'
for (var i = 0; i < params.accepts[0].extensions.length; i++) {
if (i != 0)
fileHtml += ','
fileHtml += '.' + params.accepts[0].extensions[i]
}
fileHtml += '"'
}
if (params.suggestedName) {
fileHtml += ' nwsaveas="' + params.suggestedName + '"'
}
fileHtml += '>'
var chooser = $(fileHtml);
chooser.change(function (evt) {
debugger;
return next(chooser[0].files)
});
chooser.click();
}
}
}
return {
fileSystem : fileSystem,
}
};
}
i have call the below function in my application
function workerCall() {
debugger;
if (typeof (Worker) !== "undefined") {
var worker = new Worker("Scripts/worker.js");
worker.onmessage = workerResultReceiver;
worker.onerror = workerErrorReceiver;
worker.postMessage({ 'username': Username });
function workerResultReceiver(e) {
$('.NotificationCount').html(e.data);
if (parseInt(e.data) != 0 && currentPage == "Alert") {
StateFlag = false;
$('.Notification').show();
$('.Drildown').each(function () {
var temp = this.id;
if ($('#' + temp).attr('expand') == "true") {
currentTab = temp;
StateFlag = true;
}
});
currentScrollPosition = $('body').scrollTop();
GetAlerts();
} else {
$('.Notification').hide();
}
}
function workerErrorReceiver(e) {
console.log("there was a problem with the WebWorker within " + e);
}
}
else {
}
}
the method will execute in IE,Chrome but when comes to Mozilla i got an error ReferenceError: workerResultReceiver is not defined.How can i resolve this error?
This happens because you are making reference to function that is not created yet. You need to put this:
worker.onmessage = workerResultReceiver;
worker.onerror = workerErrorReceiver;
Above
function workerErrorReceiver
line or at the end of the scope.