Loading chrome extension into QWebEngineView - pyqt5

I'm working on integrating the 7tv chrome plugin with QWebEngineView. I have been successful in that i am able to render 7tv images in chat, I have the 7tv button which opens the emote picker, and had to inject the logo onto the button.
The problem is i keep getting this error:
js: %c[7TV] %c[WARN]%c Could not find 7TV global stylesheet (content) color:#ef9234; color:#fac837; color:reset;
This is because i am not loading content.js because if i load it i get the following error:
js: Uncaught TypeError: Cannot read property 'onMessage' of undefined
if i try to load content.js my implementation breaks and i would rather have a partially working solution then one that doesn't.
If i try to go further and eliminate this error by loading background.js i get the following error:
js: Uncaught TypeError: Cannot read property 'onInstalled' of undefined
I'm an amateur at all of this so i'm not sure how to resolve this issue. I'm lucky to have gotten as far as i did. If anyone can help me eliminate this error i would appreciate it. Otherwise i will just have to live with it for now.
Here is the python code that i am using currently to load the partial implementation of the chrome plugin:
def loadWebPlugin(me, plugin):
plugin_path = "assets/plugins/"
if plugin == "7tv":
plugin_path += "7tv-2.2.3/"
me.chatView.loadFinished.connect(lambda: me.chatView.page().runJavaScript(
f"""
var style = document.createElement('style');
style.innerHTML = `{open(plugin_path + "styles/Style.css", 'r').read()}`;
document.head.appendChild(style);
""" +
# open(plugin_path + "background.js", "r").read() +
# open(plugin_path + "content.js", "r").read() +
open(plugin_path + "twitch.js", "r").read() +
f"""
// inject logo into .seventv-menu-button .logo
var logo = document.createElement("img");
logo.src = "data:image/webp;base64,{b64encode(open(plugin_path + "image/7tv.webp", "rb").read()).decode()}";
logo.style = "height: 24px; width: 24px; margin-left: -32px; margin-top: 3px";
// wait for button to load
var observer = new MutationObserver(function(mutations) {{
mutations.forEach(function(mutation) {{
if (mutation.addedNodes.length) {{
var button = document.querySelector(".seventv-menu-button");
if (button) {{
button.appendChild(logo);
observer.disconnect();
}}
}}
}});
}});
observer.observe(document.body, {{
childList: true,
subtree: true
}});
"""))
References:
https://github.com/SevenTV/Extension

Related

Element is undefined because it is not rendered yet. How to wait for it?

In my Vue app I have an image element with a bound src. this code is in a stepper. In one step the user selects a picture to upload an in the next step the image gets shown (which works as intended). However I am trying to initiate a library on the element in the next step (the Taggd library) but the element seems to be undefined.
I tried the nextTick() to wait for the image to load but without luck.
the image element:
<div class="orientation-landscape">
<div class="justify-center q-px-lg">
<img v-if="photo.url" :src="photo.url" id="workingPhoto"
style="width: 80vw;" ref="workingPhoto"/>
</div>
</div>
The functions. I first use uploadFile to set the url of the image element and go to the next step where the image will be loaded. then I call initTaggd() on the nextTick however that fails because the element is undefined.
uploadFile(file) {
const self = this;
self.photo.file = file;
self.setPhotoUrl(file);
self.$refs.stepper2.next();
console.log('We should be at next step now. doing the init');
self.nextTick(self.initTaggd());
},
setPhotoUrl(file) {
const self = this;
self.photo.url = URL.createObjectURL(file);
console.log('ping1');
},
initTaggd() {
const self = this;
const image = document.getElementById('workingPhoto');
console.log('image:', image); //THIS RETURNS UNDEFINED
console.log('Trying ANOTHER element by refs:', self.$refs.stepper2); // This returns the element
console.log('trying the real element by reference', self.$refs.workingPhoto); // Returns undefined again
const taggd = new Taggd(image); //All this here fails because image is undefined.
console.log('ping2.5');
taggd.setTags([
self.createTag(),
self.createTag(),
self.createTag(),
]);
console.log('ping3');
},
I think I am looking for a way to wait for the image to fully load before calling initTaggd() but I am lost on how to achieve this.
You could listen for the load event:
<img
v-if="photo.url"
id="workingPhoto"
ref="workingPhoto"
:src="photo.url"
style="width: 80vw;"
#load="initTaggd"
/>

how to do different tooltips depending on data with Meteor Blaze and Bootstrap?

I'm using Meteor Blaze and Bootstrap 3 to display an img with a tooltip on mouseover. It works fine with a static tooltip text:
<img class="socialMediaIcon" src={{iconPath}} data-toggle="tooltip"
data-placement="right" title={{tooltip}} />
but I want to dynamically change the tooltip depending on the value of a Collection document field.
I've created a template helper to generate the desired text:
Template.SocialMedia.helpers({
getSocialMediaIconTooltip: function(service) {
console.log(">>>>>> Tooltip service =", service);
var smsdata = socialMediaSystem.findOne({service: service});
if (!smsdata.active)
return smsData.tooltip;
else {
var smudata = socialMediaUser.findOne({accountId: Meteor.user()._id, service: service});
if (smudata)
return "Disconnect " + smsData.tooltip;
else
return "Connect " + smsData.tooltip;
}
},
and I'm calling it with:
<img class="socialMediaIcon" src={{iconPath}} data-toggle="tooltip"
data-placement="right" title={{getSocialMediaIconTooltip name}} />
where "name" is a field in the open document (the code is inside a {{#each}} loop). "name" is non-blank and is used successfully later in the #each block. "getSocialMediaIconTooltip" never gets called and no tooltip appears. I've used this argument passing syntax in other places that work. What am I doing wrong?
The helper might be throwing an error, and in Blaze templates this means blank output (i.e. no tooltip). Check the browser console for error messages.
Your helper refers to both smsdata and smsData. Is that correct, or is smsData an invalid reference?
Typos on my part, see comment above. The corrected code for reference:
Template.SocialMedia.helpers({
getSocialMediaIconTooltip: function(service) {
try {
const smsdata = socialMediaSystem.findOne({subname: service});
if (smsdata.active == false)
return smsdata.tooltip;
else {
const smudata = socialMediaUser.findOne({accountId: Meteor.user()._id, service: service});
if (smudata)
return "Disconnect " + smsdata.tooltip;
else
return "Connect " + smsdata.tooltip;
}
} catch(ex) {
console.error(ex);
}
},

Using GSAP (TweenMax) on css varabiles

I'm really into Google's Polymer and I love GSAP - and so far I've been using the two in conjunction without a hitch. Unfortunately I have now hit a problem - how do I use GSAP (TweenMax to be specific) with custom css variables?
For example:
To change someCssProperty of someElement I would
TweenMax.to(someElement, 1, someCssProperty: "value");
but the someCssProperty becomes an issue when I'm trying to animate a css variable, which take on the form --some-custom-css-variable .
I have tried to use
TweenMax.to(someElement, 1, --some-custom-css-Property: "value");
(obviously gives me errors) and I also tried to use TweenMax.to(someElement, 1, "--some-custom-css-Property": "value");
(quotes around the some-custom-Css-property) - however this results in
no change/animation and an invalid tween value error message on the developer console.
So the question is: how would I go about animating custom css variables with TweenMax (GSAP)?
Thanks for any help :)
EDIT:
I have tried using classes through
TweenMax.to("SomeElement", 5, {className:"class2"});
But this changed the element style as if I had declared it in css with a
SomeElement:hover {}
style (as in it does not animate, just changes immediately)
For now, you're going to have to manually update the variable using a generic object.
var docElement = document.documentElement;
var tl = new TimelineMax({ repeat: -1, yoyo: true, onUpdate: updateRoot });
var cs = getComputedStyle(docElement, null);
var blur = {
value: cs.getPropertyValue("--blur")
};
tl.to(blur, 2, { value: "25px" });
function updateRoot() {
docElement.style.setProperty("--blur", blur.value);
}
:root {
--blur: 0px;
}
img {
-webkit-filter: blur(var(--blur));
filter: blur(var(--blur));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.4/TweenMax.min.js"></script>
<img src="http://lorempixel.com/400/400/" />

Yii Framework + Infinite Scroll + Masonry Callback not working

I know that InfiniteScroll and Masonry work well together. But I am using the Infinite Scroll Extension of Yii (called yiinfinite-scroll) and tried to apply Masonry on it. Infinite Scroll for itself works perfectly, Masonry for itself too. But after InfiniteScroll tries to load a new set of images (I've got an image page), the callback part of InfiniteScroll doesn't seem to fire, because the newly appended elements don't have any masonry code in it and appear behind the first visible items. (I know that this bug is reported often, but the solutions I found so far didn't work for me).
My structure for showing the picture looks like this:
<div class="items">
<div class="pic">...</pic>
<div class="pic">...</pic>
...
</div>
The first page load looks like this
<div class="items masonry" style="...">
<div class="pic masonry-brick" ...></div>
<div class="pic masonry-brick" ...></div>
...
</div> // everything's fine, masonry is injected into the code
After infinite scroll dynamically loads new images these look like this:
<div class="items masonry" ...></div>
<div class="pic masonry-brick" ...></div>
...
// appended pics:
<div class="pic"></div>
<div class="pic"></div>
</div> // so no masonry functionality was applied
My Masonry Code:
$(function (){
var $container = $('.items');
$container.imagesLoaded(function(){
$container.masonry({
itemSelector: '.pic',
columnWidth: 405
});
});
});
$container.infinitescroll({
// normally, the options are found here. but as I use infinitescroll as a Yii extension, the plugin is already initiated with options
}
},
// trigger Masonry as a callback
function( newElements ) {
// hide new items while they are loading
var $newElems = $( newElements ).css({ opacity: 0 });
// ensure that images load before adding to masonry layout
$newElems.imagesLoaded(function(){
// show elems now they're ready
$newElems.animate({ opacity: 1 });
$container.masonry( 'appended', $newElems, true );
});
});
});
I also tried to copy and replace the current InfiniteScroll-min.js file in the extension folder by the newest one. Same effect...
Best regards,
Sebastian
Okay I found a solution. I post it here if somebody else has the same issue:
I just modified the YiinfiniteScroller Class from the Yiinfinite Scroll Yii Extension and added the callback part for Infinite Scroll which was missing:
private function createInfiniteScrollScript() {
Yii::app()->clientScript->registerScript(
uniqid(),
"$('{$this->contentSelector}').infinitescroll(".$this->buildInifiniteScrollOptions().", ".$this->callback.");"
);
}
At the beginning of the class I added the line
public $callback;
to use it later in the method.
Then you can call the Widget with an additional option callback, for example like this:
'callback' => 'function( newElements ) {
// hide new items while they are loading
var $newElems = $( newElements ).css({ opacity: 0 });
// ensure that images load before adding to masonry layout
$newElems.imagesLoaded(function(){
// show elems now theyre ready
$newElems.animate({ opacity: 1 });
$(".items").masonry( "appended", $newElems, true );
});
}',
Works like charm.

How to show the compiled css from a .less file in the browser?

What is the best way to show the resulting css from files compiled with less.js in the client.
In other words, how can i fill a div with the resulting css?
I need to display the result on the page, any way to do this?
THanks!
update
As already pointed out in the comments by #ertrzyiks you should replace less.parse with less.render for Less v 2.x:
var lessCode = '';
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
if(xmlhttp.status == 200 && xmlhttp.readyState == 4){
var options = {}
lessCode = xmlhttp.responseText;
less.render(lessCode, options, function (error, output) {
if(!error) {
document.getElementById('lesscode').innerHTML = output.css;
}
else document.getElementById('lesscode').innerHTML = '<span style="color:red">' + error + '</span>';
});
}
};
xmlhttp.open("GET","important.less",true);
xmlhttp.send();
see also: How to detect and print changing variables LESS
But since Less v2:
In the browser, less.pageLoadFinished will be a promise, resolved when
less has finished its initial processing. less.refresh and
less.modifyVars also return promises.
When you compile filename.less the compiled CSS code has been inject in a style tag with id less:filename, so to get the compilled CSS code you can also use:
less.pageLoadFinished.then(
function() {
console.log(document.getElementById('less:filename').innerHTML);
}
);
Notice that the last example also applies the compiled CSS code on the page.
--end update
I expected that running something such as the following was possible:
<link rel="stylesheet/less" type="text/css" href="important.less">
<script src="less-1.7.3.js" type="text/javascript"></script>
<script>
css = less.tree.toCSS();
console.log(css);
</script>
unfortunately this does not work, but you can use the following code to get what you want:
<script src="less-1.7.3.js" type="text/javascript"></script>
<script>
var lessCode = '';
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
if(xmlhttp.status == 200 && xmlhttp.readyState == 4){
lessCode = xmlhttp.responseText;
new(less.Parser)().parse(lessCode, function (e, tree) {
document.getElementById('lesscode').innerHTML = tree.toCSS().replace(/\n/g,"<br>");
});
}
};
xmlhttp.open("GET","important.less",true);
xmlhttp.send();
</script>
With in the body section of your HTML:
<div id="lesscode"></div>
See also: Combining two .less files in one and How to open a local disk file with Javascript?
I just use Chrome's Inspect Element.
Right click on the element CSS you are looking for, Right click and choose Inspect element. On the right you will find the compiled CSS in Styles. Hope it helps
You have two options to do this, Internet Explorer or Firefox.
Let's start with Firefox. If you install the web developer toolbar, you get a menu option that's labelled CSS. Clicking on this gives you a few options and if you choose View CSS, you are taken to a new tab that shows you all of the styles for the page, grouped by their location and you should see a section with the CSS that has been generated by LESS and dynamically applied to the elements.
IE also has a Web Developer option and if you use the toolbar to inspect an element, you can then use the short cut 'Ctrl + T' which will bring up the page source with the computed styles.
The Firefox solution is better, as you can see exactly which styles have been provided by LESS whereas IE just lumps it all together.
There is a third option, and that is to compile the CSS server side!