I am using cordova push notification plugin un my angular application. I have created this service for the notifications:
define(["app"], function (app) {
'use strict';
var pushNotificationService = function ($q, localStorageService) {
var registrationDefered;
function registrationSuccess(result) {
}
function registrationError(error) {
}
function test(notificationData) {
localStorageService.set('notification_url', notificationData.url);
}
function isOnBrowser() {
var result = document.URL.indexOf( 'http://' ) === -1 && document.URL.indexOf( 'https://' ) === -1;
return !result;
}
//Android Amazon callback
app.onNotificationGCM = function(e) {
console.log(e);
switch(e.event) {
case 'registered':
if (e.regid.length > 0) {
// Your GCM push server needs to know the regID before it can push to this device
// here is where you might want to send it the regID for later use.
var data = {
registrationID: e.regid,
device: device.platform.toLocaleLowerCase()
};
registrationDefered.resolve(data);
}
break;
case 'message':
test(e.payload);
// if this flag is set, this notification happened while we were in the foreground.
// you might want to play a sound to get the user's attention, throw up a dialog, etc.
if (e.foreground) {
console.log(e);
// on Android soundname is outside the payload.
// On Amazon FireOS all custom attributes are contained within payload
var soundfile = e.soundname || e.payload.sound;
// if the notification contains a soundname, play it.
var my_media = new Media("/android_asset/www/"+ soundfile);
my_media.play();
} else {
// otherwise we were launched because the user touched a notification in the notification tray.
if (e.coldstart) {
//$("#app-status-ul").append('<li>--COLDSTART NOTIFICATION--' + '</li>');
} else {
//$("#app-status-ul").append('<li>--BACKGROUND NOTIFICATION--' + '</li>');
}
}
break;
case 'error':
break;
default:
break;
}
};
//public
var serviceApi = {
register: function() {
var pushNotification = window.plugins.pushNotification;
registrationDefered = $q.defer();
debugger;
if(device.platform.toLocaleLowerCase() == 'android' || device.platform == "amazon-fireos") {
pushNotification.register(
registrationSuccess,
registrationError,
{
"senderID": "238062858076",
"ecb":"angular.module('App').onNotificationGCM"
}
);
} else if(isOnBrowser()) {
var data = {
registrationId: "",
device: "browser"
};
registrationDefered.resolve(data);
}
/* else if (device.platform == 'blackberry10'){
pushNotification.register(
registrationSuccess,
registrationError,
{
invokeTargetId : "replace_with_invoke_target_id",
appId: "replace_with_app_id",
ppgUrl:"replace_with_ppg_url", //remove for BES pushes
ecb: "pushNotificationHandler",
simChangeCallback: replace_with_simChange_callback,
pushTransportReadyCallback: replace_with_pushTransportReady_callback,
launchApplicationOnPush: true
});
} else {
pushNotification.register(
tokenHandler,
errorHandler,
{
"badge":"true",
"sound":"true",
"alert":"true",
"ecb":"onNotificationAPN"
});
}*/
return registrationDefered.promise;
}
};
//public
return {
register: serviceApi.register
}
};
return pushNotificationService;
});
Now, I am able to register (I am getting the registration ID) but when the device receives a notification it seems that the application not running the js logic written in the callback function under the message case: test(e.payload).
Note that I'm am receiving the notification butlocalStorageService.set('notification_url', notificationData.url); is never being set to the provided value.
Can you please help me to understand why it is not running? is it even suppose to run (if the application is not running - installed but not running)
The thing is that I made the registration only on login. Now I have added this line to my module run callback:
app.run(function() {
pushNotificationService.register().then(function(result) {
console.log(result); //this just for debugging
});
});
Related
I'm working with service worker to display notification between my users. In my code I include notificationclick event. With this event I'm trying to manage two cases. First case, if in my browser the page of my site is opening, don't open it but focus on it. Second case, if my browser don't show my site, open it and focus on it. But I haven't been succed...
Here is my current code:
self.addEventListener('notificationclick', function (e) {
console.log('notification was clicked')
var notification = e.notification;
var action = e.action;
if (action === 'close') {
notification.close();
} else {
// This looks to see if the current is already open and
// focuses if it is
e.waitUntil(
self.clients.matchAll().then(function(clientList) {
console.log(clientList)
if (clientList.length > 0) {
console.log(clientList[0])
return clientList[0].focus();
}
return self.clients.openWindow('/');
})
);
};
});
self.addEventListener("notificationclick", (event) => {
event.waitUntil(async function () {
const allClients = await clients.matchAll({
includeUncontrolled: true
});
let chatClient;
let appUrl = 'xyz';
for (const client of allClients) {
//here appUrl is the application url, we are checking it application tab is open
if(client['url'].indexOf(appUrl) >= 0)
{
client.focus();
chatClient = client;
break;
}
}
if (!chatClient) {
chatClient = await clients.openWindow(appUrl);
}
}());
});
I've tried everything I can think of.
I'm building a sort of chat bot for IMVU, using injected JavaScript on the IMVU mobile website. I have a loop to crawl the messages received, and search for certain key terms, like a message beginning with a slash (/) to indicate a command to the bot.
When certain commands are used, I have a problem that the bot seems to get stuck in the loop, almost as if the index of the for loop is being modified inside the loop. The code is included below.
If you need more, ask, and if you find something that might be causing the problem, please let me know. I'm at my wit's end.
Just for a note: jQuery is properly injected, all my variables are there, no errors in the debug console, and running under Chrome 41.0.2272.101m on Windows 7 x64.
function verifyCommand() {
if (document.getElementsByClassName("message-list-item").length > last_cmd_count && !processing_commands) {
var new_length = $('.message-list .message-list-item').length;
console.log("Begin processing commands... ** SYSTEM LOCK **");
console.log(new_length);
for (var i = last_cmd_count; i < (new_length); i++) {
processing_commands = true;
try {
var callinguser = $('.message-list .message-list-item .header .username .username-text')[i].innerText.replace("Guest_", "");
var messagetext = $('.message-list .message-list-item .message .message-text')[i].innerText
if (callinguser != "USERNAME REMOVED") {
if (messagetext.substr(0, 1) == "/") {
if (strContains(callinguser, "IMVU User")) {
die();
}
processCommand(messagetext.substr(1), callinguser);
} else {
if (messagetext.toLowerCase().indexOf('roomgreet') > -1 || messagetext.toLowerCase().indexOf('room greet') > -1) {
if (detectFlirt()) {
sendMsgRaw('Please do not hit on me, ' + callinguser + '.');
if (!isAdmin(callinguser)) {
logIdiot(callinguser);
}
} else if (strContains(messagetext, 'what is ')) {
sendMsgRaw('Please use /solve or /advsolve for math.');
} else {
if (callinguser != "USERNAME REMOVED") {
ident();
}
}
}
if (strContains(messagetext, 'free') && strContains(messagetext, 'credits') && strContains(messagetext, 'http://')) {
sendMsgFrom("*** SCAM ALERT ***", callinguser);
}
}
}
} catch (ex) {} finally {}
}
processing_commands = false;
last_cmd_count = new_length;
console.log("Finish processing commands... ** SYSTEM FREE **");
if (monitoring) {
verifyUserMessageCount();
}
}
}
HTML of the IMVU Mobile messages can be found at http://common.snftech.tk/imvu/roomgreet-html-sample.htm
Try changing your function to use each() to loop through each element instead of the loop you have. Once an element has been processed, add a "processed" class to the element so we dont look at them again later. This should be more stable than forcing our logic to keep up with what ones have been processed already.
Here is a jsFiddle,, throw in the html from your page that actually causes the problem and see if it still occurs
function verifyCommand() {
//fixed some logic in here
if ($(".message-list-item").length > last_cmd_count && !processing_commands) {
processing_commands = true; // you should set this immediately
var new_length = $('.message-list-item').length;
console.log("Begin processing commands... ** SYSTEM LOCK **");
console.log('Last command count: '+ last_cmd_count +', New Length: '+new_length);
var newMessages = $('.message-list-item:not(.processed)'); // get all of the message elements that do not have the class "processed"
// loop through each of the message elements
newMessages.each(function(index, element){
console.log('Processing new element at index '+index );
try {
var callinguser = $(this).find('.username-text').text().replace("Guest_", "");
var messagetext = $(this).find('.message-text').text();
$(this).addClass('processed'); // add processed class to the element so we know not to process it again later
if (callinguser != "RoomGreet") {
if (messagetext.match(/^\//)) {
if (callinguser.match(/IMVU User/)) {
die();
}
processCommand(messagetext.substr(1), callinguser);
}
else {
if (detectFlirt(messagetext)) {
if (!isAdmin(callinguser)) {
sendMsgRaw('Please do not hit on me, ' + callinguser + '.');
logIdiot(callinguser);
}
}
else if (messagetext.match('what is ')) {
sendMsgRaw('Please use /solve or /advsolve for math.');
}
else {
if (callinguser != "Nezzle" && !isAdmin(callinguser)) {
ident();
}
}
if (strContains(messagetext,"imvu") && strContains(messagetext,"credits") && strContains(messagetext,"http://")) {
sendMsgFrom("*** SCAM ALERT ***", callinguser);
}
}
}
}
catch (ex) {
console.log('caught error');
}
finally {
}
});
last_cmd_count = new_length;
console.log("Finish processing commands... ** SYSTEM FREE **");
processing_commands = false;
if (monitoring) {
verifyUserMessageCount();
}
}
}
I think your problem is this
if (messagetext.substr(0,1) == "/") {
if the user has a space in front of the "/" then it will not interpret as a command so you need to process
var messagetext = $('.message-list .message-list-item .message .message-text')[i].innerText
remove all white space from message text like this
messagetext.text().replace(" ", "");
you should also have more error catching in
if (messagetext.substr(0,1) == "/") {
When using jQuery's .post() function to submit my form data, I'm getting an Uncaught RangeError: Maximum call stack size exceeded.
I know this generally means recursion but I can't see where the recursion is happening.
I've put the post request into a function ( submitRequest() ) so I can submit data from 2 different points in the code. It originally resided inside the submit event and at that point worked perfectly. The error came as soon as I moved it outside.
Any ideas?
JavaScript code (with commented logs so you can see the flow) :
$(document).ready(function() {
var downloadLink = '',
downloadName = '',
details,
detailsSaved = false;
$('.js--download').click(function(event) {
var self = $(this);
event.preventDefault();
downloadLink = self.data('filePath'); // Store clicked download link
downloadName = self.closest('.brochure').find('.brochure__name').html().replace('<br>', ' ');
if (!detailsSaved) {
$('#brochure-section').addClass('hide');
$('#capture-section').removeClass('hide');
$('html, body').animate({
scrollTop: $("#capture-section").offset().top
}, 500);
} else {
submitRequest();
}
return false;
});
$(".submit-btn").click(function(event) {
var antiSpam = $('input[name=url]').val();
if (antiSpam != "") {
outputResultText('Error - Please leave the spam prevention field blank', 'error');
proceed = false;
event.preventDefault();
return false;
}
var name = $('input[name=name]').val(),
company = $('input[name=company]').val(),
email = $('input[name=email]').val(),
phone = $('input[name=phone]').val(),
proceed = true;
if(name==""){
$('input[name=name]').addClass("error");
proceed = false;
}
if(phone==""){
$('input[name=phone]').addClass("error");
proceed = false;
}
if(email==""){
$('input[name=email]').addClass("error");
proceed = false;
}
if(!proceed) {
outputResultText('Please check all required fields', 'error');
event.preventDefault();
return false;
}
event.preventDefault();
if(proceed) {
console.log('About to request'); // Logged out
submitRequest();
}
return false;
});
//reset previously set border colors and hide all message on .keyup()
$("input, textarea").keyup(function() {
$(this).removeClass("error");
$(".form-result").fadeOut(100);
});
function submitRequest () {
console.log('Start submitRequest'); // Logged out
if (!detailsSaved) {
console.log('Details are NOT saved');
post_data = {
'name': name,
'company': company,
'phone': phone,
'email': email,
'brochure': downloadName,
'brochure_url': downloadLink
};
details = post_data;
} else {
console.log('Details are saved');
post_data = details;
post_data['brochure'] = downloadName;
post_data['brochure_url'] = downloadLink;
}
console.log('Posting data'); // Logged out
// CRASH: Uncaught RangeError: Maximum call stack size exceeded
$.post(bcf_local_args['post_url'], post_data, function(response){
console.log('Response received');
if(response.type != 'error') {
if (detailsSaved) {
outputAlert("Thank you for your request to receive our <strong>'"+downloadName+"'</strong> brochure.<br>We'll send you a copy soon to <strong>'"+email+"'</strong>, so please check your inbox.<br>Want it sent to a different email? Simply refresh the page and try again.");
} else {
//reset values in all input fields
$('#brochure-capture-form input').val('');
$('#brochure-capture-form textarea').val('');
$('#capture-section').addClass('hide');
$('#brochure-section').removeClass('hide');
outputAlert("Thank you for your request to receive our <strong>'"+downloadName+"'</strong> brochure.<br>We'll send you a copy soon to <strong>'"+email+"'</strong>, so please check your inbox.");
}
if (!detailsSaved) {
detailsSaved = true;
}
$('html, body').animate({
scrollTop: $(".brochure__alert").offset().top
}, 500);
} else {
outputResultText(response.text, response.type);
}
}, 'json');
}
function outputResultText (text, status) {
var output = '';
if(status == 'error') {
output = '<div class="error">'+text+'</div>';
} else {
output = '<div class="success">'+text+'</div>';
}
$(".form-result").hide().html(output).fadeIn(250);
}
function outputAlert (text) {
var output = '<div>'+text+'</div>';
$('.brochure__alert').hide().removeClass('hide').html(output).slideDown(250);
setTimeout( function() {
$('.brochure__alert').slideUp(250);
}, 6500);
}
// function accessStorage(action, dataKey, dataValue) {
// if(typeof(Storage) === "undefined") {
// // No support for localStorage/sessionStorage.
// return false;
// }
// if (action == 'store') {
// localStorage.setItem(dataKey, dataValue);
// } else if (action == 'retrieve') {
// return localStorage.getItem(dataKey);
// }
// }
});
I don't know if you already found a solution but I was having the "same" problem.
In my code I had this function where I was calling after an upload of images, and I was passing the images name as paramaters along with others parameters required to my POST data.
After some research I found out that browsers has some limitations on passing parameters so the problem wasn't AT $.post but in my function calling.
I don't know the technical term but I was 'overusing the stack parameters'.
So maybe your problem isn't at your $.post either, but something else exceeding the stack.
Hope this helps.
[]'s
I'm building on top of an existing chrome extension, and I'm trying to maintain a consistent style. I need add a new feature, and I use the following script to save a user's choice from the popup selection, and then set a new popup going forward based on the saved choice.
userchoices.js:
require.scopes["userchoices"] = (function() {
var exports = {};
var userChoices = exports.userChoices = {
userchoices: {},
updateChoice: function(){
self = this;
chrome.storage.local.get('userchoices', function(items){
if(!items.userchoices){
chrome.storage.local.set({userchoices: self.userchoices});
return;
}
self.userchoices = items.userchoices;
});
},
getChoice: function(url){
if(this.userchoices[url]){
return this.userchoices[url][choice];
} else {
return {};
}
},
setChoice: function(url, newChoice){
if(!this.userchoices[url]){
this.userchoices[url] = {};
}
this.userchoices[url][choice] = newChoice;
chrome.storage.local.set({userchoices: this.userchoices});
},
removeChoice: function(url){
if(!this.userchoices[url]){
return;
} else {
delete this.userchoices[url]
}
chrome.storage.local.set({userchoices: this.userchoices});
}
}
return exports;
})();
background.js:
var userChoices= require("userchoices").userChoices;
chrome.windows.onCreated.addListener(function(){
CookieBlockList.updateDomains();
BlockedDomainList.updateDomains();
FakeCookieStore.updateCookies();
userChoices.updateChoice();
});
function refreshIconAndContextMenu(tab)
{
// The tab could have been closed by the time this function is called
if(!tab)
return;
var choice = userChoices.getChoice(tab.url);
if(choice) {
if (choice == "one"){
chrome.browserAction.setPopup({tabId: tab.id, popup: "skin/popupDontCare.html"});
} else if(choice=="two"){
chrome.browserAction.setPopup({tabId: tab.id, popup: "skin/popupSortofCare.html"});
} else if(choice=="three") {
chrome.browserAction.setPopup({tabId: tab.id, popup: "skin/popupCare.html"});
} else if(choice=="four") {
chrome.browserAction.setPopup({tabId: tab.id, popup: "skin/popupReallyCare.html"});
} else {
chrome.browserAction.setPopup({tabId: tab.id, popup: "skin/popup.html"});
}}
}
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(changeInfo.status == "loading")
refreshIconAndContextMenu(tab);
});
// Update icon if a tab is replaced or loaded from cache
chrome.tabs.onReplaced.addListener(function(addedTabId, removedTabId){
chrome.tabs.get(addedTabId, function(tab){
refreshIconAndContextMenu(tab);
});
});
popup.js:
var userChoices = require("userchoices").userChoices;
function init()
{
console.log("Initializing popup.js");
// Attach event listeners
$("#Dont_Care_btn").click(doNothing);
$("#Sort_of_Care_btn").click(doBadger);
$("#Care_btn").click(giveSecrecyBadger);
$("#Really_Care_btn").click(giveAdvice);
$("#Nuance_btn").click(addNuance);
}
function doNothing() {
$("#startingQuestion").hide();
$("#DontCareResponse").show();
$("#siteControls").hide();
userChoices.setChoice(tab.url, "one");
refreshIconAndContextMenu(tab);
}
function doBadger() {
$("#startingQuestion").hide();
$("#SortofCareResponse").show();
$("#siteControls").hide();
$("#blockedResourcesContainer").hide();
$("#Nuance_btn").show();
userChoices.setChoice(tab.url, "two");
refreshIconAndContextMenu(tab);
}
function giveSecrecyBadger() {
$("#startingQuestion").hide();
$("#siteControls").hide();
$("#CareResponse").show();
$("#siteControls").hide();
$("#blockedResourcesContainer").hide();
$("#Nuance_btn").show();
userChoices.setChoice(tab.url, "three");
refreshIconAndContextMenu(tab);
}
function giveAdvice() {
$("#startingQuestion").hide();
$("#siteControls").hide();
$("#ReallyCareResponse").show();
userChoices.setChoice(tab.url, "four");
refreshIconAndContextMenu(tab);
}
The popup is currently not being set, and I'm not even sure that the selection is saved successfully. Anyone see a problem?
Ha! In the middle of trying to create a minimal example, I figured out the problem. Turns out the problem was the now-deprecated chrome.tabs.getSelected method when it should have been chrome.tabs.query()
Thanks Xan!
I managed to record and play my voice like a dictaphone thanks to Cordova. Now i would like to add an "Autotune" or "Vocoder" effect on my voice, how can i do that ?
PS:I work on mobile device.
Here is the the script for record and play my voice :
<script type="text/javascript" charset="utf-8" src="cordova-1.7.0rc1.js"></script>
<script type="text/javascript" src="jquery-1.7.1.js"></script>
<script type="text/javascript">
var deviceready = false;
var mediaVar = null;
var recordFileName = "recording.wav";
var status = null;
var isIOS = false;
function onBodyLoad()
{
document.addEventListener("deviceready", onDeviceReady, false);
deviceready = true;
}
$(document).ready(function(){
$("#stopBtn").hide();
$("#playBtn").hide();
//validation to check if device is ready is skipped
$("#recordBtn").click(function(){
record();
});
$("#playBtn").click(function(){
play();
});
$("#stopBtn").click(function(){
stop();
});
});
function record()
{
createMedia(function(){
status = "recording";
mediaVar.startRecord();
$("#recordBtn").hide();
$("#stopBtn").show();
$("#playBtn").hide();
},onStatusChange);
}
function createMedia(onMediaCreated, mediaStatusCallback){
if (mediaVar != null) {
onMediaCreated();
return;
}
if (typeof mediaStatusCallback == 'undefined')
mediaStatusCallback = null;
if (isIOS) {
//first create the file
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem){
fileSystem.root.getFile(recordFileName, {
create: true,
exclusive: false
}, function(fileEntry){
log("File " + recordFileName + " created at " + fileEntry.fullPath);
mediaVar = new Media(fileEntry.fullPath, function(){
log("Media created successfully");
}, onError, mediaStatusCallback); //of new Media
onMediaCreated();
}, onError); //of getFile
}, onError); //of requestFileSystem
} else //it's Android
{
mediaVar = new Media(recordFileName, function(){
log("Media created successfully");
}, onError, mediaStatusCallback);
onMediaCreated();
}
}
function stop()
{
if (mediaVar == null)
return;
if (status == 'recording')
{
mediaVar.stopRecord();
log("Recording stopped");
}
else if (status == 'playing')
{
mediaVar.stop();
log("Play stopped");
}
else
{
log("Nothing stopped");
}
$("#recordBtn").show();
$("#stopBtn").hide();
$("#playBtn").show();
status = 'stopped';
}
function play()
{
createMedia(function(){
status = "playing";
mediaVar.play();
$("#recordBtn").hide();
$("#stopBtn").show();
$("#playBtn").hide();
});
}
function onStatusChange()
{
if (arguments[0] == 4) //play stopped
{
$("#recordBtn").show();
$("#stopBtn").hide();
$("#playBtn").show();
}
}
function onSuccess()
{
//do nothing
}
function onError(err)
{
if (typeof err.message != 'undefined')
err = err.message;
alert("Error : " + err);
}
function log(message)
{
if (isIOS)
console.log(message);
else
console.info(message);
}
function onDeviceReady()
{
}
</script>
Pitch detection and manipulation (Autotune is a brand-name for a product Anteres Audio Technology that achieves it) is a hard digital signal processing problem (DSP) which is computationally intensive.
DPS Dimension provides a good tutorial here are about pitch manipulation, but it's very far from being a complete solution.
You are unlikely to make much headway with it without a strong academic background in DSP. Existing implementations are proprietary and typically implemented in C++. There are many patents in this problem space too.
One option might be to implement the audio processing server-side using a licensed component.
You might have more luck implementing a Vocoder in Javascript - the complexity is lower and there are plenty of algorithms in the public domain to try.