Building an Omnibox extension for Google Chrome - google-chrome

I'm trying to build an Omnibox that matches what the user types against suggestions taken from an external data source, via jQuery. No luck so far.
In essence, the whole thing would function just like an autocomplete in jQuery, assuming this how the Omnibox is supposed to work (details are scarce, even in Google's Chrome developer resources).
Warning: I am not a proficient jQuery developer by any means, and most of what I've written is an exercise in brute force cut-paste trial and error until either success or exhaustion.
So far, I only have an example taken from an article by a user here, Ido Green:
chrome.omnibox.onInputChanged.addListener(
function(text, suggest) {
suggest([
{content: "CRM", description: " fetch the internal CRM"},
{content: "ERP", description: " fetch the internal ERP"},
{content: "sales", description: " fetch the lastest sales report"}
]);
}
);
chrome.omnibox.onInputEntered.addListener(
function(text) {
if (text.indexOf("/") < 1) {
text += "/";
}
if (text.indexOf("http") < 0) {
text = "http://our-internal-portal/" + text;
}
alert('We are taking you to: "' + text + '"');
navigate(text);
});
function navigate(url) {
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.update(tab.id, {url: url});
});
}
However, I cannot make this do anything else, despite the various other sample code examples I've found.
Firstly, I have a data source which I'm presently using for an autocomplete in jQuery, which is working fine, and returns the data in JSON format:
$(function(){
$('#link-bookmarks').autocomplete({
source: base_url + "bookmarks/jq_get_bookmarks_by_search_as_object/",
appendTo: ".bookmark-link-results",
open: function(event, ui) {
$('ul.ui-autocomplete#link-bookmarks')
.removeAttr('style')
.hide()
.appendTo('.bookmark-link-results')
.show();
$('#links-bookmarks').show();
},
select: function(event, ui) {
$('.bookmark-link-results')
.append('<div class="bookmark-link-box" id="bookmark-link-box-' + ui.item.bookmark_id + '"><input type="checkbox" id="bookmark-link-item-' + ui.item.bookmark_id + '" name="bookmark-links-add[]" value="' + ui.item.bookmark_id + '" checked="checked">' + ui.item.title + ' [View] [Link] <textarea class="comment" id="bookmark-link-comment-box-' + ui.item.bookmark_id + '" name="bookmark-link-comments[]"></textarea></div>');
}
}).data("autocomplete")._renderItem = function(ul, item) {
return $('<li></li>')
.data("item.autocomplete", item)
.append('<a>' + item.snippet + '</a>')
.appendTo(ul);
};
});
So I'd like to use that as the source. I know that needs to go in the onInputChanged method, but everything I've tried has so far failed.
If anyone has any ideas or Omnibox examples, that would help tremendously.

Related

Double processing after context menu click

I have an extension that inserts text into textarea and similar.
The user can choose text from the popup or the contextmenu.
I have "all_frames" : true so that my content script can see all the iframes - in case a textarea is in an iframe.
After a save to the database (more on this in a bit), if the user uses the contextmenu to add text (handled via messaging from background.js to content.js) to a text area the text is added twice.
If the user uses the popup.html mechanism, which passes text to the same content.js, the text is only entered once (the desired outcomes!).
The message is only passed once by background.js.
For instance, if there are five iframes on a page, and therefore 5 instances of content.js, the contextmenu listener script runs 10 times (not 5, as it should).
If I remove "all_frames" : true from the manifest then the text only adds once.
But I need to keep this setting so I can reach textareas in iFrames. And the popup insert works beautifully everywhere.
The save to the database is what triggers the behavior - and that process is a simple json write to a php file. I wipe the contextmenu as part of that process - but again, it isn't a question of the background.js sending 2 messages. One message is sent, and for some reason the code runs through the messaging routine 2x.
I've tried creating flags to mark once a single successful insertion has happened, but everything is asynch and I don't think this would be helpful even if I could get it to work in some cases.
I feel like I need to kill some old content.js processes or something...
The kicker: if I Reload the Extension (in developer mode) the contextmenu works properly and inserts selected text only once. It's only after I save to the db that the problem occurs.
I'm very close to throwing out contextmenus as a feature and just using the elegant popup.html. But this seems like some weird edge case that would be worth understanding.
Many thanks for taking a look. I've included some code and also a screenshot of the console showing the 10x repeats of the content.js code when inserting into a Google Doc.
background.js
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {method: "insertComment", comment: tempText}, function(response) {
// console.log(response.status);
});
});
content.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.method == 'insertComment'){
var sValue = request.comment;
var currentEltag = document.activeElement.tagName.toLowerCase(); //Checking for currently selected area
console.log("currentEltag before logic: " + currentEltag + " / id: " + document.activeElement.id);
console.log("activeTag: " + activeTag);
// console.log("activeEl: " + activeEl.id + ' / name: ' + activeEl.name + ' /value: ' + activeEl.value);
if (activeTag === undefined || activeTag === null){
console.log('currentEltag in logic: ' + currentEltag);
if (currentEltag === 'iframe'){
activeTag = 'iframe';
console.log('Making activeTag equal iframe');
}
}
var sField = activeEl;
if (activeTag === 'input' || activeTag === 'textarea'){
console.log('Dealing with plain input/textarea - yes! sField is: ' + sField);
var nStart = sField.selectionStart;
var nEnd = sField.selectionEnd;
if (nStart || nEnd == '0'){
console.log("Inside insert sub with starting point: " + nStart + ' and end ' + nEnd + ' with value ' + sValue);
console.log('Print and increment...');
sField.value = sField.value.substring(0, nStart) + sValue + sField.value.substring(nEnd, sField.value.length);
sField.selectionStart = nStart + sValue.length;
sField.selectionEnd = nStart + sValue.length;
console.log('Printed value1...and flag is now: ');
chrome.storage.sync.get("flag", function(data) {
console.log("Flag", data.flag);
});
}
else {
sField.value = sValue;
console.log('Printed value2...');
}
} //End if input or textarea

Why IE gives "show all content" warning? How to avoid this warning programatically?

I Have implemented jquery autocomplete functionality on HTTPS page and that works fine for all browser except Internet Explorer.
While on IE, it does not shows auto popup list for and shows warning as "Show all content".
I have used JSON for cross domain request.
Here is my code :
function zipAutoCompletet(prefix){
jQuery( "#"+prefix+"_zip" ).autocomplete({
source: function (request, response) {
$.getJSON("http://ws.geonames.org/postalCodeSearchJSON",
{ 'postalcode_startsWith': request.term, maxRows: 12, style: "full" },
function(data) {
if(data.postalCodes){
var x = $.map( data.postalCodes, function( item ){
console.log(item)
return {
label: item.placeName + (item.adminCode1 ? ", " + item.adminCode1 : "") + ", " + item.postalCode + ", "+item.countryCode,
value: item.postalCode
}
});
response(x);
}
}
);
},
Can any one tell me that how can I enable autocomplete in IE also without "show all content" warning??
Thanks In advance.
To prevent IE from showing that message, you need to have everything secure, i.e. everything should be https.
So the first thing i'd try is changing your json url to https.
$.getJSON("https://ws.geonames.org/postalCodeSearchJSON",

getting data from MySQL on jquerymobile only when I refresh the page

ok so I'm trying to load data and move to another page once I'm clicking on a search button in my index.html
this is my search button
<a href="results.html" data-role="button" data-icon="search"
data-iconpos="notext">search</a>
and while it's loading I want the page to run this function and get data
$(function () { $.getJSON("API.php", {
command: "getBusiness",
orig_lat: myPos.lat,
orig_long: myPos.lon,
distance: 0.05 },
function (result) {
$("#locations").html("");
for (var i = 0; i < result.length; i++) {
$("<a href='business.html?ID=" + result[i].id + "&bsnName=" + "'>
<div>" + result[i].bsnName + " " + (parseInt(result[i].distance * 1000))
"</div></a>").appendTo("#locations");}});});
The page is loading without the DB only when I hit refresh it's showing me the result
I'm not sure what's wrong here, should I not use getJSON?? I have seen people talking about .Ajax() is it the same as getJSON() ?
is there a better idea on how to move to another page and simultaneously grab data from DB to the page your going to load on jquerymobile?
I tried to use the same function using onclick it worked when I gave it a div
the rest of the head
<link rel="stylesheet" href="styles/jquery.mobile.structure-1.1.0.min.css" />
<link rel="stylesheet" href="styles/jquery.mobile.theme-1.1.0.min.css" />
<link rel="stylesheet" href="styles/my.css" />
<script src="scripts/jquery-1.7.2.min.js"></script>
<script src="scripts/jquery.mobile-1.1.0.min.js"></script>
<script src="scripts/cordova-1.8.1.js"></script>
<script>
// Wait for Cordova to load
//
document.addEventListener("deviceready", onDeviceReady, false);
var watchID = null;
var myPos = { lat: 32.0791, lon: 34.8156 };
// Cordova is ready
//
function onDeviceReady() {
// Throw an error if no update is received every 30 seconds
var options = { timeout: 10000 };
watchID = navigator.geolocation.watchPosition(onSuccess, onError, options);
}
// onSuccess Geolocation
//
function onSuccess(position) {
var element = document.getElementById('geolocation');
//myPos.lat=position.coords.latitude;
//myPos.lon=position.coords.longitude;
element.innerHTML = 'Latitude: ' + position.coords.latitude + '<br />' +
'Longitude: ' + position.coords.longitude + '<br />' +
'<hr />' + element.innerHTML;
}
// onError Callback receives a PositionError object
//
function onError(error) {
alert('code: ' + error.code + '\n' +
'message: ' + error.message + '\n');
}
Basically when jQuery mobile loads first or index page it load whole head section (Javascript, CSS etc) and body section. but When the user clicks a link in a jQuery Mobile-driven site, the default behavior of the navigation system is to use that link's href to formulate an Ajax request (instead of allowing the browser's default link behavior of requesting that href with full page load).When that Ajax request goes out, the framework will receive its entire text content, but it will only inject the contents of the response's body element.
There can be multiple solutions to this problem e.g.
The simplest approach when building a jQuery Mobile site is to reference the same set of stylesheets and scripts in the head of every page.
Linking without Ajax by using an attribute data-ajax="false" in your link this attribute will load the next page without ajax and animation so both head and body section would load.
If you need to load in specific scripts or styles for a particular page, It is recommended binding logic to the pageInit e.g. "#aboutPage" is id="aboutPage" attribute .
$( document ).delegate("#aboutPage", "pageinit", function() {
//you can place your getJson script here. that will execute when page loads
alert('A page with an ID of "aboutPage" was just created by jQuery Mobile!');
});
So in your case better solution is to bind your ajax call or other particuler script with pageinit event.
You can get help from these pages of jQuery Mobile documentation.
http://jquerymobile.com/demos/1.1.0/docs/pages/page-links.html
http://jquerymobile.com/demos/1.1.0/docs/pages/page-scripting.html

Force chrome tabs to crash

I'm trying to make an extension that crashes all tabs in chrome window so that they don't load on opening chrome (when having too many tabs).
But when I try to use
chrome.tabs.update(null, {url:"chrome://crash"})
or
chrome.tabs.update(null, {url:"about:crash"})
they don't work, although using
chrome.tabs.update(null, {url:"chrome://tasks"})
works well
Is there any workaround to do that?
when this works too I'd like to loop on all the open tabs to do the same thing and I don't know how.
you can simply getAll active windows and loop through its tabs then change its url to data:text/html
chrome.windows.getAll({populate : true}, function (window_list) {
var list = [];
for(var i=0;i<window_list.length;i++) {
list = list.concat(window_list[i].tabs);
}
for(var y=0;y<list.length;y++) {
var jsRunner = {'code': 'window.stop()'};
chrome.tabs.executeScript(list[y].id, jsRunner);
if(!list[y].url.match(/data\:text\/html/gi)){
chrome.tabs.update(list[y].id, {url:"data:text/html,<meta charset=\"utf-8\"><title>" + list[y].title + "</title><h1 style='text-align:center;'><a style='text-decoration:none;' href='" + list[y].url + "'>" + list[y].url + "</a></h1>"});
}
}
});
you can download the extension and try it http://d.pr/f/wXaZ

Populating dropdown list with JSON data using 2 views/documents

I'm having some trouble populating a dropdownlist with some JSON data, i suspect that the error occurs because of the way im appending the $.post within the #stuff div, but i've tried this a couple of ways and just wont get the hang of it.
The select id="" tag & the div lies within another view (it's not part of this particular document) , is that a problem for populating the dropdown-list this way?
Ive tried to alert out the "listItems" and i've got the option values etc... dont get it why it wont populate.
Any help would be appreciated.
Json-response from the $.post =
{"childrendata":[{"id":"42","parent":"1","fName":"hej","lName":"nisse","birthdate":"2011-10-21"}]}
The jQuery/js:
$("#stuff").append(function(){
$.post("show_relations", {},
function(data)
{
$("#stuff").empty();
json = eval('('+data+')');
if(data == '{"childrendata":[]}')
{
$("#stuff").append("No relations registered.");
}
else
{
var listItems= "";
for (var i = 0; i < json.childrendata.length; i++)
{
listItems+= "<option value='" + json.childrendata[i].fName + "'>" + json.childrendata[i].lName + "</option>";
}
$("#child_list").html(listItems);
}
});
});
});
Edit: Based on your comment, I'll assume your problem is purely single-page.
The problem with that code would appear to be the fact that you're trying to use .append() with a function (which is valid jQuery), but that the function doesn't return anything that jQuery can append to the 'stuff' node; $.post makes an Ajax call, which returns immediately.
Instead, try something like the following (modifying the URL to the Ajax call as required):
$.post("url/to/post/to", {},
function(data) {
$("#stuff").empty(); //Clear your stuff div
var children = data.childrendata; //jQuery automatically unserializes json
if(children.length == 0) {
$("#stuff").append("No relations registered.");
}
else {
$('#stuff').append('<select id="child_list"></select>');
$.each(children,
function(index, value) {
//Append each option to the selectbox
$("#child_list").append("<option value='" + value.fName + "'>" + value.lName + "</option>");
}
);
}
},
'json'
);
$.each() is the generic jQuery iterator, which helps de-clutter the code.
What this does is make an Ajax post to the provided URL, which responds with the serialized json object. The callback takes that response (which jQuery has already unserialized by itself), adds a new select to the '#stuff' div, and then adds the dynamically-created options to the new select.
Endnote: My apologies for not posting the link to the $.each documentation, StackOverflow only allows me to post 2 hyperlinks in a single post currently.