passing an array in a message from content script to background page in google chrome extension - arrays

I am writing a Google Chrome extension.
I want to pass a small array from a content script to background page in a message. Can I simply reference the array name or need I construct a JSON object from it first?
Here is the code:
IN THE CONTENT SCRIPT
var req;
var detailWin;
//drag off the f_foto class
var searchResult = document.getElementsByClassName("f_foto");
alert("Found Class f_foto "+searchResult.length+" times.");
//collect profile links
for (var i = 0; i<searchResult.length; ++i)
{
var profileLink=searchResult[i].getElementsByTagName("a");
profileLinks[i]=profileLink[0].href;
// alert(i+1+" of "+searchResult.length+" "+profileLinks[i]+" length of "+profileLinks[i].length);
}
for (var i = 0; i<searchResult.length; ++i)
{
//tell bkgd page to open link
chrome.extension.sendRequest({cmd: "openProfile", url: profileLinks[i]});
//BETTER TO SEND WHOLE ARRAY.
//LIKE THIS? chrome.extension.sendRequest({cmd: "openProfile", urlList: profileLinks});
//OR SHOULD I MAKE A JSON OBJECT OUT OF IT?
}
//IN THE BACKGROUND PAGE
var detailTabId = null;
var profileLinks = new Array();
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if(request.cmd == "openProfile") {
//IF RECEIVING AN ARRAY, PROCESS IT LIKE THIS?
// profileLinks= request.urlList;
// console.log=("Received "+ urlList.length + " links.");
chrome.tabs.create({url: request.url}, function(tab){
//save tab id so we can close this tab later
detailTabId = tab.id;
//profile tab is created, inject profile script
chrome.tabs.executeScript(tab.id, {file: "profile.js"});
});
}
});

An Array is a construct of a JSON object so there is no need to do anything other than what you are doing now.

Related

Highlight text as you type in textarea Reactjs

I need to perform a behavior in FrontEnd but I don't know how to do it: Inside the textarea I have to put a background on certain keywords like "+project", "#context", while the user types, as if it were a markup text similar to testing tools for Regex.
Its not the complete solution, but you can adapt this example:
https://jsfiddle.net/julmot/hdyLpy37/
It uses the markjs library:
https://markjs.io/
Here is the javascript code:
// Create an instance of mark.js and pass an argument containing
// the DOM object of the context (where to search for matches)
var markInstance = new Mark(document.querySelector(".context"));
// Cache DOM elements
var keywordInput = document.querySelector("input[name='keyword']");
var optionInputs = document.querySelectorAll("input[name='opt[]']");
function performMark() {
// Read the keyword
var keyword = keywordInput.value;
// Determine selected options
var options = {};
[].forEach.call(optionInputs, function(opt) {
options[opt.value] = opt.checked;
});
// Remove previous marked elements and mark
// the new keyword inside the context
markInstance.unmark({
done: function(){
markInstance.mark(keyword, options);
}
});
};
// Listen to input and option changes
keywordInput.addEventListener("input", performMark);
for (var i = 0; i < optionInputs.length; i++) {
optionInputs[i].addEventListener("change", performMark);
}

Creating new HTML images using a For loop through an array of image URLs

I have an array of 40 different image URLs being returned from an AJAX request. I'm trying to create a new HTML image element for each URL in the array using a For loop, as seen in the below code. For some reason, it's only displaying the image at the first URL and that's it. Any idea why the other 39 aren't showing up?
$(document).ready(function() {
$.ajax({
type: 'GET',
dataType: 'json',
url: 'https://****/images',
success: function(data) {
console.log(data);
let container = document.getElementById('feed');
let image = document.createElement("img");
for (let i = 0; i < data.length; i++) {
image.setAttribute('src', data[i]);
container.appendChild(image);
}
}
});
});
<body>
<div id="feed">
</div>
</body>
Try to create the element inside the loop.
for (let i = 0; i < data.length; i++) {
let image = document.createElement("img");
image.setAttribute('src', data[i]);
container.appendChild(image);
}
The way to create images is with new Image() and when appending multiple nodes to the DOM at once, it's better to first append the image nodes into a document fragment, and only when all the images have been appended to the fragment, then append the fragment itself into the Document (prevents redundant repaints)
// dummy data
const data = ['http://placekitten.com/100/100',
'http://placekitten.com/100/150',
'http://placekitten.com/100/180',
'http://placekitten.com/100/200']
// create a dumpster-node for the images to reside in
const fragment = document.createDocumentFragment();
// iterate the data and create <img> elements
data.forEach(url => {
let image = new Image()
image.src = url;
fragment.appendChild(image);
})
// dump the fragment into the DOM all the once (FTW)
document.body.appendChild(fragment);
I've used Array forEach iterator in my example, because it's easier in my opinion, but you can use a for loop (or for..of loop)

Routing in SAPUI5: How to implement passing of URL? Model data not initialy loaded

My goal is to write a SAPUI5 Fiori app with routing support. One mail goal is to have passable URLs. For example in an E-Mail like "please approve this: link". The link is an URL matched by my rounting config, e.g.index.html#/applicants/8.
I use a typical sap.m.SplitApp kind of application. Clicking a list item in masterview changes the URL to index.html#/applicants/[id of entry in JSON]. I can click on the list, my defined routes are getting matched and the apps loads the (applicant) data as expected.
However, and here comes my question, this doeas not work when using an URL directly, say pasting [my url]/index.html#/applicants/8 into my browser. The app is launched but no detail data is loaded. I have to click on another list item again to get the data.
Actually, the controller is called when passing the URL, but it seems the model is not initiated and undefined. My JSON model is bound in the createContent function of my Component.js
// Update 2015-05-14
The problems seems to be around the getData() function. I have the model, it has the entries, but getData() returns undefined for the first time my app is loaded. I recently read getData() is deprecated. How should I improve my coding below?
// Component.js
ui5testing.Component.prototype.createContent = function(){
// create root view
var oView = sap.ui.view({
id : "app",
viewName : "ui5testing.view.Main",
type : "JS",
viewData : {
component : this
}
var oModel = new sap.ui.model.json.JSONModel("model/mock_applicants.json");
oView.setModel(oModel);
[...]
return oView;
});
// Master controller
handleApplicantSelect : function (evt) {
var oHashChanger = sap.ui.core.routing.HashChanger.getInstance();
var context = evt.getParameter("listItem").getBindingContext();
var path = context.getPath();
var model = this.getView().getModel();
var item = model.getProperty(path);
oHashChanger.setHash("applicants/" + item.id);
},
// Detail controller
onInit: function() {
this.router = sap.ui.core.UIComponent.getRouterFor(this);
this.router.attachRoutePatternMatched(this._handleRouteMatched, this);
},
_handleRouteMatched : function(evt){
var objectId = evt.getParameter("arguments").id;
var model = this.getView().getModel();
var data = model.getData()["applicants"];
var pathId;
if (data) {
for (var i = 0; data.length; i++) {
if ( objectId == data[i].id ) {
pathId = i;
break;
}
}
var sPath = "/applicants/" + pathId;
var context = new sap.ui.model.Context(model, sPath)
this.getView().setBindingContext(context);
}
},
As you've figured out that getData() returns undefined for the first time, which means the model data is still not yet loaded. So you can make use of attachRequestCompleted method of the model & fire an event from the component & listen to that event in the detail controller to ensure the routerPatternMatched() gets executed only after the data is loaded.
//Component.js
var oModel = new sap.ui.model.json.JSONModel("model/mock_applicants.json");
oModel.attachRequestCompleted(jQuery.proxy(function(){
this.fireEvent("MockDataLoaded"); // fireEvent through component
},this));
oView.setModel(oModel);
//Detail controller
onInit : function(){
this.router = sap.ui.core.UIComponent.getRouterFor(this);
var oComponent = this.getOwnerComponent();
oComponent.attachEvent("MockDataLoaded",jQuery.proxy(function(){
this.router.attachRoutePatternMatched(this._handleRouteMatched, this);
},this));
}
Or the simplest & but the dirty way would be to make an synchronous request instead of an async request to load data.
var oModel = new sap.ui.model.json.JSONModel();
oModel.loadData(""model/mock_applicants.json",{bAsync:false});
oView.setModel(oModel);

EXT JS store.loadData() is not appending the data

I am trying to use store.loadData(data, true) to append data to an existing store but for some reason it is clearing the store and replacing it with the new data which should only happen if the boolean is set to false which it is not. Is there something I am missing that I need to do to make sure the data is appended to the old data and not replacing it entirely?
Edit Additional code. Currently I am pulling a row from a grid and creating a new window with additional information for that object that is pulled from a database. The idea is that all the possible data for the rows is stored in one store and then when the window appears the store has a filter added so that you only see data that pertains to that particular object. At some point I iterate every single object in the grid and check to see if it has data that was edited. Which is an issue if I only have data from the last object that was edited.
editSelectedNode: function(grid, rowIndex, colIndex){
var store = Ext.getStore('EditStore');
var win = Ext.create('BOMGeneratorSencha.view.EditMenu', {});
var item = grid.getStore().getAt(rowIndex).get('original');
console.debug(item);
win.show();
var el = win.getEl();
store.clearFilter(true);
console.debug(store.getCount());
if(store.getCount() == 0){
el.mask('Loading Values');
console.debug(store.getCount());
Ext.Ajax.request({
url : 'EditPart.jsp',
timeout: 300000,
params : {
item: item
},
success: function (response, opt) {
el.unmask();
var res = Ext.JSON.decode(response.responseText);
if (res.success) {
console.debug(res.results);
store.loadData(res.results,true);
console.debug(store);
}
else {
console.debug("JSON failure");
Ext.Msg.alert('Error', 'Invalid part number');
}
},
failure: function(response,options){
console.debug("major failure");
el.unmask();
Ext.Msg.alert('Error', 'Connection failed<br>' + response.responseText);
}
});
}
}
I have a code that is similat to your one. But when i get response, I dont use
store.loadData(someData)
instead I am using following steps to load data(piece of my code placed here):
success: function(response, opts){
var obj = Ext.decode(response.responseText)
,data = obj.data
,$ = Ext.ComponentQuery;
var store = Ext.create('MyApp.store.SomeStore',{
data : data
});
$.query('SomeGrid')[0].bindStore(store);
$.query('SomeGrid')[0].refresh();
}

How to print ExtJS component?

How do I pop up the Print dialog that will print out a component when OK-ed?
var targetElement = Ext.getCmp('PrintablePanelId');
var myWindow = window.open('', '', 'width=200,height=100');
myWindow.document.write('<html><head>');
myWindow.document.write('<title>' + 'Title' + '</title>');
myWindow.document.write('<link rel="Stylesheet" type="text/css" href="http://dev.sencha.com/deploy/ext-4.0.1/resources/css/ext-all.css" />');
myWindow.document.write('<script type="text/javascript" src="http://dev.sencha.com/deploy/ext-4.0.1/bootstrap.js"></script>');
myWindow.document.write('</head><body>');
myWindow.document.write(targetElement.body.dom.innerHTML);
myWindow.document.write('</body></html>');
myWindow.print();
write your extjs printable component into document.
I like Gopal Saini's answer! I took his approach and wrote a function for one of my apps. Here's the code. Tested on FF and Safari. Haven't tried it on IE but it should work.
print: function(el){
var win = window.open('', '', 'width='+el.getWidth()+',height='+el.getHeight());
if (win==null){
alert("Pop-up is blocked!");
return;
}
Ext.Ajax.request({
url: window.location.href,
method: "GET",
scope: this,
success: function(response){
var html = response.responseText;
var xmlDoc;
if (window.DOMParser){
xmlDoc = new DOMParser().parseFromString(html,"text/xml");
}
else{
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.loadXML(html);
}
win.document.write('<html><head>');
win.document.write('<title>' + document.title + '</title>');
var xml2string = function(node) {
if (typeof(XMLSerializer) !== 'undefined') {
var serializer = new XMLSerializer();
return serializer.serializeToString(node);
} else if (node.xml) {
return node.xml;
}
}
var links = xmlDoc.getElementsByTagName("link");
for (var i=0; i<links.length; i++){
win.document.write(xml2string(links[i]));
}
win.document.write('</head><body>');
win.document.write(el.dom.innerHTML);
win.document.write('</body></html>');
win.print();
},
failure: function(response){
win.close();
}
});
}
ExtJS 4.1:
https://github.com/loiane/extjs4-ux-gridprinter
Printing in ExtJS is not paticularly easy. The best resource I've found on making components printable can be found on a Sencha architect's blog. The post describes how to set up custom print renderers for components, and other details about printing. However, this information is for ExtJS 3.x; it's possible that ExtJS 4 has made printing easier.
You can also add a component to be printed to the Ext.window.Window with a modal property set to true and just open a standard print dialog which will only print the desired component.
var view = this.getView();
var extWindow = Ext.create('Ext.window.Window', { modal: true });
extWindow.add(component); // move component from the original panel to the popup window
extWindow.show();
window.print(); // prints only the content of a modal window
// push events to the event queue to be fired on the print dialog close
setTimeout(function() {
view.add(component); // add component back to the original panel
extWindow.close();
}, 0);
Another option to consider is to render the component to an image or pdf. While the pop-up window/print option is nice, some browsers don't print correctly. They tend to ignore background images, certain css properties, etc. To get the component to print exactly the way it appears in the pop-up window, I ended up writing some server side code to transform the html into an image.
Here's what the client code looks like:
print: function(el){
var waitMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
waitMask.show();
//Parse current url to set up the host and path variables. These will be
//used to construct absolute urls to any stylesheets.
var currURL = window.location.href.toString();
var arr = currURL.split("/");
var len = 0;
for (var i=0; i<arr.length; i++){
if (i<3) len+=(arr[i].length+1);
}
var host = currURL.substring(0, len);
if (host.substring(host.length-1)=="/") host = host.substring(0, host.length-1);
var path = window.location.pathname;
if (path.lastIndexOf("/")!=path.length-1){
var filename = path.substring(path.lastIndexOf("/")+1);
if (filename.indexOf(".")!=-1){
path = path.substring(0, path.lastIndexOf("/")+1);
}
else{
path += "/";
}
}
//Start constructing an html document that we will send to the server
var html = ('<html><head>');
html += ('<title>' + document.title + '</title>');
//Insert stylesheets found in the current page. Update href attributes
//to absolute URLs as needed.
var links = document.getElementsByTagName("link");
for (var i=0; i<links.length; i++){
var attr = links[i].attributes;
if (attr.getNamedItem("rel")!=null){
var rel = attr.getNamedItem("rel").value;
var type = attr.getNamedItem("type").value;
var href = attr.getNamedItem("href").value;
if (href.toLowerCase().indexOf("http")!=0){
if (href.toString().substring(0, 1)=="/"){
href = host + href;
}
else{
href = host + path + href;
}
}
html += ('<link type="' + type + '" rel="' + rel+ '" href="' + href + '"/>');
}
}
html += ('</head><body id="print">');
html += (el.dom.innerHTML);
html += ('</body></html>');
//Execute AJAX request to convert the html into an image or pdf -
//something that will preserve styles, background images, etc.
//This, of course, requires some server-side code. In our case,
//our server is generating a png that we return to the client.
Ext.Ajax.request({
url: "/WebServices/Print?action=submit",
method: "POST",
rawData: html,
scope: this,
success: function(response){
var url = "/WebServices/Print?action=pickup&id="+response.responseText;
window.location.href = url;
waitMask.hide();
},
failure: function(response){
win.close();
waitMask.hide();
var msg = (response.responseText.length>0 ? response.responseText : response.statusText);
alert(msg);
}
});
}
Again, this requires some server-side magic to transform the html into an image. In my case, I implemented a "Print" service. Clients submit job requests via the "submit" action and retrieve output products via the "pickup" action.
To convert html to images, I ended up using a free command line app called Web Screen Capture. It only works on windows and I don't know how scalable it is so use at your risk.

Resources