This question already has answers here:
"Cannot read property of undefined" when using chrome.tabs or other chrome API in content script
(4 answers)
Closed 4 years ago.
I tried to follow a tutorial to create a chrome extension (https://github.com/apatrida/kotlin-example-chrome-ext/blob/master/src/main/kotlin/com/collokia/browserplugin/chrome/GoogleImageTest/Extension.kt)
But it seems to be outdated for the latest kotlinjs version.
I'm trying to get the active tab URL with this code
fun getActiveTabURL(): String {
var url = "NotInit"
chrome.tabs.query(chrome_tabs_CurrentTabQuery()) {
tabs ->
println("tabsssssssss")
url = tabs[0].url ?: "NULL"
println("print url $url")
}
println(url)
return url
}
But it doesn't seems to work the tutorial uses keywords like native but I can't use them on my IDE (IntelliJ)
external object chrome {
object tabs {
object Tab {
var status: String?
var index: Number
var openerTabId: Number?
var title: String?
var url: String?
var pinned: Boolean
var highlighted: Boolean
var windowId: Number
var active: Boolean
var favIconUrl: String?
var id: Number
var incognito: Boolean
}
public fun query(queryInfo: Any, callback: (result: Array<Tab>) -> Unit): Unit = definedExternally
}
}
class chrome_tabs_CurrentTabQuery() {
val active = true;
val currentWindow = true
}
Do you know what's wrong or a more recent example?
I obtain a
Uncaught TypeError: Cannot read property 'query' of undefined
at getActiveTabURL (kotlinextensiontest.js:61)
at main (kotlinextensiontest.js:20)
at kotlinextensiontest.js:122
at kotlinextensiontest.js:125
It works if I click on the extension button, I was testing in on a separate tab and it wasn't working. Thanks for the help
Related
I followed a tutorial on how to make a live chat room. But now the problem is that the messages will dissapear after a refresh. So instead I tried to store those messages that get submitted by the user in localStorage. But I can't get it to work. Because when I try it it would just keep showing me the whole array instead of the lastest new string that was added to the array. The chatroom is made with socket.io and I am using nodejs.
This is what I tried first:
function appendMessage(message) {
const messageElement = document.createElement('div')
messageContainer.append(messageElement)
var a = []
if (localStorage.getItem('session') == null) {
} else {
a = JSON.parse(localStorage.getItem('session'))
}
a.push(message)
localStorage.setItem('session', JSON.stringify(a))
messageElement.innerText = a
}
But it would just show me the whole array. So then I tried this:
function appendMessage(message) {
const messageElement = document.createElement('div')
messageContainer.append(messageElement)
var a = []
if (localStorage.getItem('session') == null) {
} else {
a = JSON.parse(localStorage.getItem('session'))
}
a.push(message)
localStorage.setItem('session', JSON.stringify(a))
messageElement.innerText = a[a.length -1]
}
But this won't show it correctly because after a refresh the text is gone. How could I make it so that it would only show the latest new string that is stored in the localStorage inside the array that stays there after a page refresh?
I'm new to Angular and I'm trying to call my function setCenter2() from the AppComponent class in the ngOnInit function in the same class, is this possible ? When I click on my map, basically when it tries to call my function, (I use OpenStreetMap) I get this error : ERROR TypeError: Object doesn't support property or method 'setCenter2'. Tell me if you need more of my code, thank you. Do I need to look out for something in particular when doing this ?
I've seen about the bug with internet explorer but it doesn't seem to be this, I'm using Edge and using the latest version of Angular.
export class AppComponent {
[…]
setCenter2() {
var view = this.map.getView();
view.setCenter(ol.proj.fromLonLat([this.longi1, this.lati1]));
view.setZoom(this.zoom);
}
[…]
ngOnInit() {
[…]
this.map.on('click', function (args) {
console.log(args.coordinate);
var lonlat = ol.proj.transform(args.coordinate, 'EPSG:3857', 'EPSG:4326');
console.log(lonlat);
// var lon = lonlat[0];
// var lat = lonlat[1];
//alert(`lat: ${lonlat[1]} et long: ${lonlat[0]}`);
eval("this.longi1 = lonlat[0];");
eval("this.lati1 = lonlat[1];");
this.setCenter2();
alert(`lati: ${this.lati1} et longi: ${this.longi1}`);
});
}
Use fat arrow function because you loose value of this:
this.map.on('click', args => {
I've been trying to get my head around query parameters with UI Router and think I have finally figured out why I'm having such a hard time with it. I'm building a small search app that has 2 states:
$stateProvider
.state('home', {
url: '/',
.state('search', {
url: '/search',
},
The home state has its own template (view) and so does the search state. They share the same controller. Basically all home state does is provide a search box to enter your search query or choose from autocomplete.
Once you have submitted your search query it goes to the search state via
$state.go('search');
I've tried many ways to get the user's search term(s) in the url on the search page using UI Router's query parameter syntax in the url: '/search?q' combined with $stateParams in the controller set as
vm.searchTerms = $stateParams.q || '';
I had switched it to $state.params.q but that didn't fix it.
I have successfully been able to get the query parameters in the url, however, when I do, it breaks search functionality. The autocomplete and query parameters work and display, but search function stops.
However, I think I finally understand why its not working the way I'd like it to. I believe it has to do with the fact that I'm using 2 states and not one parent state with a nested child state and that the templates are not nested - so $scope doesn't inherit. I'm getting close to this working... it transitions from the home state to the search state displaying query parameters in the search state's url... its simply that search breaks, but autocomplete and query parameters are working.
What I'm trying to achieve is to have the user enter search terms from the home state and then have results display in the search state along with query parameters in the url. Is there anything I need to do with home state or search state that I'm not doing?
OR
Is there anything in my search() in my controller that could be the problem
//search()
vm.search = function() {
//$state.go('search', {q: vm.searchTerms});
$state.go('search');
console.log(vm.searchTerms);
console.log('success - search');
vm.currentPage = 1;
vm.results.documents = [];
vm.isSearching = true;
return coreService.search(vm.searchTerms, vm.currentPage)
.then(function(es_return) {
console.log('success - return');
var totalItems = es_return.hits.total;
var totalTime = es_return.took;
var numPages = Math.ceil(es_return.hits.total / vm.itemsPerPage);
vm.results.pagination = [];
for (var i = 0; i <= 10; i++) {
console.log('success - for');
vm.results.totalItems = totalItems;
vm.results.queryTime = totalTime;
vm.results.pagination = coreService.formatResults(es_return.hits.hits);
vm.results.documents = vm.results.pagination.slice(vm.currentPage, vm.itemsPerPage);
console.log('success - documents');
}
vm.noResults = true;
}),
function(error){
console.log('ERROR: ', error.message);
vm.isSearching = false;
},
vm.captureQuery();
console.log('success - captureQuery');
};
You can add a parameter to your URL in two ways, use colon:
'url': '/search/:query'
or curly braces:
'url': '/search/{query}'
Then you can use the go method of $state with parameter to transition:
$state.go('search', {'query', 'foobar'});
You can access the parameter's value from your controller by using the params member of your $state object:
console.log($state.params.query);
or directly from the $stateParams object:
console.log($stateParams.query);
Reference: https://github.com/angular-ui/ui-router/wiki/URL-Routing#url-parameters
I am beginner in Orchard CMS and i need add voting functionality to content. I have installed Contib.Vote and Contrib.Review modules. After that i have added Review part to page content type. Also, i have executed recipe. At the first look everything is fine, but link for review refer to the same page with # symbol and nothing is happenning by clicking on it. It seems like module does not work or work incorrectly. Please help with my problem.
UPD.
Hi devqon and thanx for your help. Your answer was really useful for me. According to your advice i was looking around javascript inside Review Part view file (Parts_Reviews.cshtml). Just for a test i changed its source code a little bit.
#using (Script.Foot())
{
<script type="text/javascript">
//<![CDATA[
(function () {
var numberOfReviewsToShowByDefault = 5;
var $showAllReviewsLink = $('#showAllReviewsLink');
var $deleteReviewConfirmationDialogDiv = $('#deleteReviewConfirmationDialogDiv');
$deleteReviewConfirmationDialogDiv.dialog({ autoOpen: false, modal: true, resizable: false });
$('#deleteReviewLink').click(function () {
$('#reviewId').val($(this).attr("data-review-id"));
ShowDeleteReviewDialog();
return false;
});
$('#showReviewFormLink').click(function () {
$('#createReviewLinkDiv').slideToggle('fast', function () { $('#reviewFormDiv').slideToggle('fast'); });
return false;
});
$('#cancelCreateReviewLink').click(function () {
$('#reviewFormDiv').slideToggle('fast', function() { $('#createReviewLinkDiv').slideToggle('fast'); });
return false;
});
$('#deleteReviewForm').submit(function () {
$('input[type=submit]', this).attr('disabled', 'disabled');
});
$('#cancelDeleteReviewButton').click(function () {
CloseConfirmationDialogDiv();
return false;
});
var rowCount = $('#reviewsList li').length;
if (rowCount > numberOfReviewsToShowByDefault) {
SetupToggle();
}
if (document.location.hash === '#Reviews') {
var topPx = $('#reviews-heading').position().top;
$('body,html').animate({ scrollTop: topPx }, 'slow');
}
if ($("#comment").length) {
var characterCountUpdater = new CharacterCountUpdater($("#comment"), $("#commentCharactersLeft"));
setInterval(function() { characterCountUpdater.UpdateCharacterCount(); }, 100);
$("#comment").keypress(function() { characterCountUpdater.UpdateCharacterCount(); });
if ($("#comment").val().length) {
$("#showReviewFormLink").trigger("click");
}
}
function CharacterCountUpdater(commentBox, charactersLeftBox)
{
this.commentBox = commentBox;
this.charactersLeftBox = charactersLeftBox;
this.maxLength = commentBox.attr("maxlength");
commentBox.removeAttr("maxlength");
return this;
}
Now form for review is displayed. The form looks good, submit button works, character counter works too. But i still can't apply my rating. Stars not react on clicking. That is why submit operation ends with error 'In order to submit a review, you must also submit a rating.'. Look like something inside Parts.Stars.NoAverage.cshtml does not work. Please, help me.
According to the project's site it is a known issue: broken from version 1.7.2.
When looking at the code of the Parts_Reviews.cshtml it says the following on lines 20-24:
string showReviewUri = "#";
if (!Request.IsAuthenticated)
{
showReviewUri = Url.Action("LogOn", "Account", new { area = "Orchard.Users", ReturnUrl = Context.Request.RawUrl });
}
and on line 29:
<div id="createReviewLinkDiv"><span id="createReviewLinkSpan">#noReviewsYetText<a id="showReviewFormLink" href="#showReviewUri">#reviewLinkText</a></span></div>
Therefore, it was intended to let the anchor be # when the request is authenticated (you are logged on). This means it probably will be handled in JavaScript, which can be seen on lines 105-112:
$('#showReviewFormLink').click(function () {
$('#createReviewLinkDiv').slideToggle('fast', function () { $('#reviewFormDiv').slideToggle('fast'); });
return false;
});
$('#cancelCreateReviewLink').click(function () {
$('#reviewFormDiv').slideToggle('fast', function() { $('#createReviewLinkDiv').slideToggle('fast'); });
return false;
});
This piece of code should let you see the form to write a review, so something is going wrong there presumably. When there's something wrong in this jQuery code it probably gives an error in the console, so check out the browser's console when you click the 'Be the first to write a review' link.
This should get you further, if you don't know what to do please provide the error and I will try to dig more. I haven't downloaded the module so I don't have live feed.
Console of Firefox tells: $(...).live is not a function. It refers to Contrib.Stars.js source code file. This function is not supported in jquery now and i replaced it by .on() function in all places api.jquery.com/on. Now module works fine.
Check out my comment at the site below to see how I was was able to get it working again on Orchard 1.8.1:
Orchard Reviews Project Site
You basically just need to change 3 different lines in the Contrib.Stars.js file but I would recommend copying the .js file along with the Review module's different views to a custom theme directory, in order to override everything and force the Reviews module to use your edited .js file:
On line 12 & 13:
Change this:
$(".stars-clear").live(
"click",
To this:
$("body").on(
"click", ".stars-clear",
On line 44 & 45:
Change this:
.live(
"mouseenter",
To this:
.mouseenter(
On line 48 & 49:
Change this:
.live(
"mouseleave",
To this:
.mouseleave(
My extension adds a context menu whenever a user selects some text on the page.
Then, using info.selectionText, I use the selected text on a function executed whenever the user selects one of the items from my context menu. (from http://code.google.com/chrome/extensions/contextMenus.html)
So far, all works ok.
Now, I got this cool request from one of the extension users, to execute that same function once per line of the selected text.
A user would select, for example, 3 lines of text, and my function would be called 3 times, once per line, with the corresponding line of text.
I haven't been able to split the info.selectionText so far, in order to recognize each line...
info.selectionText returns a single line of text, and could not find a way to split it.
Anyone knows if there's a way to do so? is there any "hidden" character to use for the split?
Thanks in advance... in case you're interested, here's the link to the extension
https://chrome.google.com/webstore/detail/aagminaekdpcfimcbhknlgjmpnnnmooo
Ok, as OnClickData's selectionText is only ever going to be text you'll never be able to do it using this approach.
What I would do then is inject a content script into each page and use something similar to the below example (as inspired by reading this SO post - get selected text's html in div)
You could still use the context menu OnClickData hook like you do now but when you receive it instead of reading selectionText you use the event notification to then trigger your context script to read the selection using x.Selector.getSelected() instead. That should give you what you want. The text stays selected in your extension after using the context menu so you should have no problem reading the selected text.
if (!window.x) {
x = {};
}
// https://stackoverflow.com/questions/5669448/get-selected-texts-html-in-div
x.Selector = {};
x.Selector.getSelected = function() {
var html = "";
if (typeof window.getSelection != "undefined") {
var sel = window.getSelection();
if (sel.rangeCount) {
var container = document.createElement("div");
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
container.appendChild(sel.getRangeAt(i).cloneContents());
}
html = container.innerHTML;
}
} else if (typeof document.selection != "undefined") {
if (document.selection.type == "Text") {
html = document.selection.createRange().htmlText;
}
}
return html;
}
$(document).ready(function() {
$(document).bind("mouseup", function() {
var mytext = x.Selector.getSelected();
alert(mytext);
console.log(mytext);
});
});
http://jsfiddle.net/richhollis/vfBGJ/4/
See also: Chrome Extension: how to capture selected text and send to a web service