Chrome Extension - Background Script notified whenever another page updates - google-chrome-extension

I'm making a Chrome Extension that gets the DOM of a closed tab and updates the popup.html. So far so good, I can do that through the background script using XMLHttpRequest.
However, I would like my popup to be updated if the closed page is updated. I was thinking of running a timer in the background script to check every 10 sends or so, but I was wondering if XMLHttpRequest has a way of knowing when its page updates? Or even if the timer would work, I couldn't get it working
I've added the relevant files below. Any help is appreciated
popup.html
<body>
<h1>Agile Board Viewer</h1>
<div class="wrapper">
<button id="mainButton">Click me</button>
<p id="testingDisplay">test</p>
</div>
</body>
popup.js
document.addEventListener('DOMContentLoaded', function () {
document.getElementById("mainButton").addEventListener('click', function () {
chrome.runtime.sendMessage({
method : 'POST',
action : 'xhttp',
url : '//My url//',
data : 'q=something'
}, function (responseText) {
document.getElementById("testingDisplay").innerHTML = responseText;
});
});
});
background.js
I've deleted some lines that are pointless (I think) to avoid clutter, just error handlers and what not, also got rid of my attempt at a timer. Basically, what it does is takes a string from the DOM and sends it to the popup. I would like that popup to update whenever the string does.
var testingString = "Testing (";
chrome.runtime.onMessage.addListener(function (request, sender, callback) {
if (request.action == "xhttp") {
`var xhttp = new XMLHttpRequest();
xhttp.onload = function () {
var testingValue = xhttp.responseText.substring(xhttp.responseText.indexOf(testingString), xhttp.responseText.indexOf(testingString) + 16);
callback(testingValue);
//callback(xhttp.responseText);
};
}
});
Sorry if the formatting is a mess, I'm not too well versed on this

Just to follow up, I've solved my issue by using a timer that checks the closed tab every couple of seconds. If the label that lists the number of items in my Testing column is different, I get my notification. Still learning XHR so I'm hoping I can improve on this again but for now, I'm happy enough. Only works for 20 seconds in my example, as I don't want an infinite timer. Will put in an off switch later
var testingString = "Testing (";
var testBuffer = "";
var i = 0;
chrome.runtime.onMessage.addListener(function (request, sender, callback) {
if (request.action == "xhttp") {
var xhttp = new XMLHttpRequest();
var method = request.method ? request.method.toUpperCase() : 'GET';
var testingValue = xhttp.responseText.substring(xhttp.responseText.indexOf(testingString), xhttp.responseText.indexOf(testingString) + 16);
function startTimer() {
window.setTimeout(function () {
if (i < 20) {
xhttp.open(method, request.url, true);
xhttp.onload = function () {
testBuffer = testingValue;
testingValue = xhttp.responseText.substring(xhttp.responseText.indexOf(testingString), xhttp.responseText.indexOf(testingString) + 16);
if (testBuffer != testingValue) {
notification = new Notification('New Item in Testing Column', {
body : "You have a new item in Testing",
});
console.log(testingValue);
}
};
xhttp.onreadystatechange = function () {
if (xhttp.readyState == 4 && xhttp.status == 200) {
callback(testingValue);
}
};
xhttp.onerror = function () {
alert("error");
callback();
};
if (method == 'POST') {
xhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
xhttp.send(request.data);
console.log("count");
i++;
startTimer();
}
}, 5000);
}
startTimer();
return true;
}
});

Related

How do I set the volume of a Youtube video?

I'm creating an extension that mutes the autoplay video when you navigate to a Youtube channel. It's able to execute content.js when navigating to a Youtube channel and select the video, but how can I set the video's volume? Setting video.volume = 0 does not work like I thought it would.
Background script:
'use strict';
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (changeInfo.status == 'complete') {
const site = tab.url.split('/');
let domain = site[2];
let page = site[3];
if (page === 'channel' || page === 'user') {
chrome.tabs.sendMessage(tab.id, {'message': 'loaded_channel_page'});
}
}
});
Content script:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message === 'loaded_channel_page' || document.readyState != 'loading') {
let newVolume = 0;
document.addEventListener('yt-navigate-finish', () => {
setTimeout(mute, 2000);
});
function mute() {
let video = document.querySelector('.html5-main-video');
video.volume = newVolume;
}
}
})
Youtube doesn't monitor direct changes to the DOM video element's properties, they use their own wrapper on a #movie_player element that exposes the volume control function in page context which we can't access directly from the content script so we need to run it in a <script> element:
// direct call
inPage(setVolume, 0);
// delayed call
setTimeout(inPage, 2000, setVolume, 0);
// range is 0 - 100
function setVolume(vol) {
document.getElementById('movie_player').setVolume(vol);
}
function inPage(fn, ...args) {
const script = document.createElement('script');
script.textContent = `(${fn})(${JSON.stringify(args).slice(1, -1)})`;
document.documentElement.appendChild(script);
script.remove();
}

How to automate site creation on save in a SP list form using JSOM?

For one of the Clients Requirements, I have to automate Sharepoint site creation on a button click. Basically there will be a SharePoint list form in which a user will enter data as title, url, and select a template. Once clicked on save it should create a sharepoint site. I have been able to implement this using a HTML form web part but now i need to Use SharePoint OOTB list form and need to do the same thing. Below is the code I wrote that creates a sharepoint site upon button click, the code works fine and creates a site depending upon the selection. I am using SharePoint online.
Any ideas on how to convert this approach to A Sharepoint list form approach?
<script src="//code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
function PreSaveAction(){
CreateSubWeb();
return true;
}
function CreateSubWeb() {
// defualt list Title field
var webTitle=$("input[title='Client_x0020_Name']").val();
//custom fields URL and Template
var url=$("input[title='Site_x0020_URL']").val();
var template=$("input[title='Custom_x0020_Template']").val();
// current web url
var webUrl = _spPageContextInfo.webAbsoluteUrl;
var clientContext = new SP.ClientContext(webUrl);
this.oWebsite = clientContext.get_web();
var webCreationInfo = new SP.WebCreationInformation();
webCreationInfo.set_title(webTitle);
webCreationInfo.set_language(1033);
webCreationInfo.set_url(url);
webCreationInfo.set_useSamePermissionsAsParentSite(true);
if(template == 'Customer W Project'){
webCreationInfo.set_webTemplate("{2936BD84-30AD-413E-8933-2A6B7856D10F}#Template 2");
}
else
{
webCreationInfo.set_webTemplate("{ED884F01-6B10-4791-A704-FF05A047D0F3}#Template 1");
}
oWebsite.get_webs().add(webCreationInfo);
oWebsite.update();
clientContext.executeQueryAsync(onQuerySucceeded, onQueryFailed);
}
function onQuerySucceeded(sender, args) {
alert('success');
}
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
</script>
The code below for your reference, add the code into script editor web part in new form page.
<script src="//code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
function PreSaveAction(){
var templateName=$("select[title='Custom Template']").val();
getTemplateName(templateName).done(function(template) {
createSubSite(template);
});
return true;
}
var createSubSite = function(templateName) {
// defualt list Title field
var webTitle=$("input[title='Title Required Field']").val();
//custom fields URL and Template
var url=$("input[title='Site URL']").val();
// current web url
var webUrl = _spPageContextInfo.webAbsoluteUrl;
var clientContext = new SP.ClientContext(webUrl);
this.oWebsite = clientContext.get_web();
var webCreationInfo = new SP.WebCreationInformation();
webCreationInfo.set_title(webTitle);
webCreationInfo.set_language(1033);
webCreationInfo.set_url(url);
webCreationInfo.set_useSamePermissionsAsParentSite(true);
webCreationInfo.set_webTemplate(templateName);
oWebsite.get_webs().add(webCreationInfo);
oWebsite.update();
clientContext.executeQueryAsync(function() {
console.log("Done");
}, function(sender,args){
console.log("failed. Message:" + args.get_message());
});
}
var getTemplateName = function(templateName) {
var dfd = new $.Deferred();
var clientContext = SP.ClientContext.get_current();
var templates = clientContext.get_web().getAvailableWebTemplates(1033, false);
clientContext.load(templates);
clientContext.executeQueryAsync(function() {
var templateGuidName;
for (var template in templates.get_data()) {
if (templates.itemAt(template).get_title() === templateName) {
templateGuidName = templates.itemAt(template).get_name();
break;
}
}
dfd.resolve(templateGuidName);
}, function() { dfd.reject(); });
return dfd.promise();
}
</script>

Need if-else advice in actionscript3

function clickButtonHandler(event:MouseEvent):void
{
var message:Object = new Object();
message.text = txtMessage.text;
message.userName = txtUser.text;
//Posts to this swf
showMessage(message);
//Posts to ALL OTHER swf files..
group.post(message);
}
function showMessage(message:Object):void
{
output_txt.appendText(message.userName+": "+message.text + "\n");
}
function jsalertwindow(event:MouseEvent):void
{
var alert:URLRequest = new URLRequest("javascript:alert('Please enter your User name')");
navigateToURL(alert, "_self");
}
As you can see there are two function which are contain mouseevent. I want to send those function with an if-else statement. If user write something in text input component which name is txtUser and,
send_btn.addEventListener(MouseEvent.CLICK, clickButtonHandler);
will work, else(if the user forget writing anything)
send_btn.addEventListener(MouseEvent.CLICK, jsalertwindow);
will work.
And one more question should i use MouseEvent.CLICK or MouseEvent.MOUSE_DOWN? Thanks for your advice.
Assign a single handler to the button click (MouseEvent.CLICK is the right event to use) and check the field is populated in the handler:
function clickButtonHandler(event:MouseEvent):void
{
var message:Object = new Object();
// Check the field is populated
if (txtUser.text != "")
{
message.text = txtMessage.text;
message.userName = txtUser.text;
showMessage(message);
//Posts to ALL OTHER swf files..
group.post(message);
}
else
{
// Nothing in the input field, show the alert
showAlert();
}
}
function showMessage(message:Object):void
{
output_txt.appendText(message.userName+": "+message.text + "\n");
}
function showAlert():void
{
var alert:URLRequest = new URLRequest("javascript:alert('Please enter your User name')");
navigateToURL(alert, "_self");
}

FabricJS double click on objects

I am trying to perform a special action whenever the user double clicks any object located inside the canvas. I have read the docs and not found any mouse:dblclick-like event in the documentation. I tried doing something like:
fabric.util.addListener(fabric.document, 'dblclick', callback);
Which does trigger the dblclick event but does not give specific information about the actual object that is being clicked on the canvas.
Any ideas of the most FabricJS-y way of doing this?
The more elegant way is to override fabric.Canvas._initEventListeners to add the dblclick support
_initEventListeners: function() {
var self = this;
self.callSuper('_initEventListeners');
addListener(self.upperCanvasEl, 'dblclick', self._onDoubleClick);
}
_onDoubleClick: function(e) {
var self = this;
var target = self.findTarget(e);
self.fire('mouse:dblclick', {
target: target,
e: e
});
if (target && !self.isDrawingMode) {
// To unify the behavior, the object's double click event does not fire on drawing mode.
target.fire('object:dblclick', {
e: e
});
}
}
I've also developed a library to implement more events missed in fabricjs : https://github.com/mazong1123/fabric.ext
This is similar to #LeoCreer's answer but actually gets access to the targeted object
fabric.util.addListener(canvas.upperCanvasEl, 'dblclick', function (e) {
var target = canvas.findTarget(e);
});
The Correct way to add custom events to Fabric.js
window.fabric.util.addListener(canvas.upperCanvasEl, 'dblclick', function (event, self) {
yourFunction(event);
});
or use fabric.ext
I'm using this workaround:
var timer = 0;
canvas.item(0).on('mouseup', function() {
var d = new Date();
timer = d.getTime();
});
canvas.item(0).on('mousedown', function() {
var d = new Date();
if ((d.getTime() - timer) < 300) {
console.log('double click')
}
});
Here is a quick and easy way to add a double click event handler to Fabric JS -
Include following code snippet to your html file. Just ensure this is loaded after the main fabric.js library
<script type="text/javascript">
fabric = (function(f) { var nativeOn = f.on; var dblClickSubscribers = []; var nativeCanvas = f.Canvas; f.Canvas = (function(domId, options) { var canvasDomElement = document.getElementById(domId); var c = new nativeCanvas(domId, options); c.dblclick = function(handler) { dblClickSubscribers.push(handler) }; canvasDomElement.nextSibling.ondblclick = function(ev){ for(var i = 0; i < dblClickSubscribers.length; i++) { console.log(ev); dblClickSubscribers[i]({ e :ev }); } }; return c; }); return f; }(fabric));
</script>
Then add this code to listen a double click event:
canvas.dblclick(function(e) {
});
To get information about the actual object that is being clicked on the canvas, use following method -
canvas.getActiveObject();
eg.
canvas.dblclick(function(e) {
activeObject = canvas.getActiveObject();
});
I am late but now fabricjs has mousedblclick event.
Listed at: http://fabricjs.com/docs/fabric.Object.html
See all events:
http://fabricjs.com/events

MOSS 2007: Adding Filter to ListView web part

I have been dropped into a sharepoint 2007 project, and i have relatively little experience with altering existing webparts.
My first task is to add a filter to two out of three columns in a list view. My Lead Dev suggests trying to add a jquery combo-box filter, and another dev suggests extending the web part and overriding some of the functionality.
What i think is a good option is to change the context menu for the list view headers, so that instead of "Show Filter Choices" bringing up a standard dropdownlist that only responds to the first letter, it would have a jquery combobox. And maybe if the business requests it, change the wording of that option.
My question to you is, what would be a good path to take on this? Also, what resources are there besides traipsing around books and blogs are there to guide an sp newbie to do this?
Thanks.
How about something like this:
<script src="http://www.google.com/jsapi"></script>
<script>
google.load("jquery", "1.2.6");
google.setOnLoadCallback(function() {
$(document).ready(function()
{
jQuery.extend(jQuery.expr[':'], {
containsIgnoreCase: "(a.textContent||a.innerText||jQuery(a).text()||'').toLowerCase().indexOf((m[3]||'').toLowerCase())>=0"
});
$("table.ms-listviewtable tr.ms-viewheadertr").each(function()
{
if($("td.ms-vh-group", this).size() > 0)
{
return;
}
var tdset = "";
var colIndex = 0;
$(this).children("th,td").each(function()
{
if($(this).hasClass("ms-vh-icon"))
{
// attachment
tdset += "<td></td>";
}
else
{
// filterable
tdset += "<td><input type='text' class='vossers-filterfield' filtercolindex='" + colIndex + "' /></td>";
}
colIndex++;
});
var tr = "<tr class='vossers-filterrow'>" + tdset + "</tr>";
$(tr).insertAfter(this);
});
$("input.vossers-filterfield")
.css("border", "1px solid #7f9db9")
.css("width", "100%")
.css("margin", "2px")
.css("padding", "2px")
.keyup(function()
{
var inputClosure = this;
if(window.VossersFilterTimeoutHandle)
{
clearTimeout(window.VossersFilterTimeoutHandle);
}
window.VossersFilterTimeoutHandle = setTimeout(function()
{
var filterValues = new Array();
$("input.vossers-filterfield", $(inputClosure).parents("tr:first")).each(function()
{
if($(this).val() != "")
{
filterValues[$(this).attr("filtercolindex")] = $(this).val();
}
});
$(inputClosure).parents("tr.vossers-filterrow").nextAll("tr").each(function()
{
var mismatch = false;
$(this).children("td").each(function(colIndex)
{
if(mismatch) return;
if(filterValues[colIndex])
{
var val = filterValues[colIndex];
// replace double quote character with 2 instances of itself
val = val.replace(/"/g, String.fromCharCode(34) + String.fromCharCode(34));
if($(this).is(":not(:containsIgnoreCase('" + val + "'))"))
{
mismatch = true;
}
}
});
if(mismatch)
{
$(this).hide();
}
else
{
$(this).show();
}
});
}, 250);
});
});
});
It will need to be added to the page via a content editor web part.

Resources