As soon as I add:
<script src="/bower_components/ember/ember.min.js"></script>
on the same page where there's our snagengage chat code:
<!-- begin SnapEngage code -->
<script type="text/javascript">
(function() {
var se = document.createElement('script'); se.type = 'text/javascript'; se.async = true;
se.src = '//commondatastorage.googleapis.com/code.snapengage.com/js/4f645e9b-afb9-4226-9ebc-f8fc52d28cef.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(se, s);
})();
</script>
<!-- end SnapEngage code -->
it provokes an error:
Uncaught TypeError: Cannot call method 'push' of undefined 4f645e9b-afb9-4226-9ebc-f8fc52d28cef.js:223
YAHOO.register 4f645e9b-afb9-4226-9ebc-f8fc52d28cef.js:223
(anonymous function) 4f645e9b-afb9-4226-9ebc-f8fc52d28cef.js:242
Anyone ever experienced this? Any suggestion about how to fix this?
PS: I tried removing that JS line and it works, that's definitively a conflict between Ember and some YAHOO library I guess.
Thanks!
I opened a ticket on this with SnapEngage and they recently pushed out a fix. If you had a SnapEngage account prior to Mar 6, 2014, then you need to click "Save" within the "Style" section of your account in order for the JS to be updated to the latest version. After this, the error should go away - worked for me!
NOTE: I am using Ember 1.4.0
I had this same issue and I think it was caused by a _super() on the YAHOO.register function cycling through line 233 twice. The first time it does it the variables k.versions and k.builds are defined, but the second time they are not (perhaps because the super reruns the YAHOO.register function without passing in any arguments. Regardless of exactly what caused it, I was able to remedy the issue (albeit in a VERY hacky way) by making the following edits to the snapengage.js source:
1) On line 233 change:
k.versions.push(p);k.builds.push(q);
to:
k.versions ? k.versions.push(p):false;k.builds ? k.builds.push(q):false;
All this does is check to see if the variables are defined and if they are, push to them. If not, do nothing.
I placed the edited snapengage.js source file in app/assets/javascripts/vendor/ and then added the following line to my application.js file:
//= stub ./vendor/snapengage.js
This will stop your ember application from loading the SnapEngage source when the app loads.
Finally, I wrote a chat mixin and loaded the snapengage.js script as follows:
App.Chat = Em.Mixin.create({
agentOnline: false,
didInsertElement: function() {
this._getChatApi();
},
_getChatApi: function() {
var url = 'assets/home/vendor/snapengage.js',
_this = this;
$.getScript(url).done(function() {
// Your custom SnapEngage Javascript API code here. For example...
SnapEngage.getAgentStatusAsync(function(online) {
_this.set('agentOnline', online);
});
});
},
});
App.IndexView = Em.View.extend(Home.Chat, {
// The rest of your view code here
});
The snapengage.js script won't load itself twice but if you're using the mixin on multiple pages you might want to make sure you're not loading the chat assets (images, loading spinner, etc) twice because the plugin seems to make a call to snapengage.com everytime you click on the 'help' button rendered on the webpage.
As I mentioned, it's a very hacky solution and I don't recommend editing the source code for plugins, but this will give you a fix to easily use Snapengage in an Ember.js app.
Related
I've tried to find the solution in previous questions but i couldn't.
I have a web project developed in jquery using requireJS. Everything seems to work fine (in all modern browsers) until i tested in IE9 where there isn't a script working. I tried to find the cause but all i can get is the feedback from dev tool console:
SCRIPT1002: Syntax error libCommon.js, line 10 character 3
SCRIPT445: Object doesn't support this action libEvents.js, line 5
character 2
This is the beginning code of libCommon.js:
//generic JS for all views
define(['jquery'], function ($) {
var LibCommon = function () {};
LibCommon.prototype.hideSubmenu = function() {
$submenu.removeClass('show');
}
LibCommon.prototype.toggleSubmenu = function(tipo) {
const $tipoSubmenu = $('#'+tipo);
this.hideSubmenu();
if (!$tipoSubmenu.hasClass('show')) {
$tipoSubmenu.addClass('show');
} else {
$tipoSubmenu.removeClass('show');
}
};
//and other functions...
And this is the beginning code of libEvents.js:
//generic JS for all views
define(['jquery', 'bootstrap', './libCommon', 'modernizr'], function ($, Bootstrap, LibCommon, Modernizr) {
var common = new LibCommon();
/**
* =================
* TO EXECUTE WHEN INIT
* =================
*/
$( document ).ready(function() {
console.log('initialized all common events');
var common = new LibCommon();
// Fixed header
var stickyNavTop = $('.topmenu').offset().top;
common.fixedNav(stickyNavTop);
$(window).scroll(function() {
common.fixedNav(stickyNavTop);
});
// and other functions or events...
In both errors it's first character of creating a variable/instance of an object after defining all objects/dependencies in requireJS, so it shouldn't be an error. I tried by changing for var common = 0; but error continues appearing in console. It seems that IE9 doesn't like any script. Otherwise, require's instances are working because bootstrap is working properly. Any idea?
Shilly already pointed out in a comment that you should not pass ES6 constructs to IE9. Either write ES5 or use a tool to transpile it.
Now, the error you are getting in libEvents is bizarre because libCommon should not have loaded at all, and consequently the factory of libEvents should not run because one of the dependencies did not load. It is possible to have a module load and later give errors. But I don't recall ever seeing a syntax error in the immediately-interpreted code of a module that did not just cause the load to fail. (The code you are showing is interpreted immediately, even if it is executed later. If you had an eval(string_of_code) in there or a Function(string_of_code) then string_of_code would be interpreted later but this is not something that happens in your code.) I suspect the reason RequireJS goes ahead with executing the factory for libEvents has to do with a problem catching load failures in IE9 and lower. The documentation suggests turning on enforceDefine. I would do this for your code. This won't solve everything but it may help RequireJS detect problems better.
console.log will also probably give you troubles, as explained by this question and answer.
I'm sure this is going to be so trivial, but have had a number of tries and being the last thing I need to configure before I can deploy the private test is driving me mad.
This question extends off this question, my config.xml is established in the same way, this part is a no brainer. I have also got in my <head>:
<script type='text/javascript' src="./js/facebookConnectPlugin.js"></script>
I have tried both ./facebookConnectPlugin.js as well as ./js/facebookConnectPlugin.js, so part (a) of my question is, how can I determine what is the correct relative path without seeing the directory? I can't find its install location to verify.
Next part of the question follows the advice I received from somewhere, that instead of using the usual device ready event, to use the window.onload:
window.onload = onDeviceReady;
...
function onDeviceReady() {
onDeviceReadyFacebook();
...
}
...
function onDeviceReadyFacebook() {
// ?
}
window.fbAsyncInit = function () {
if (!window.cordova) {
// Initialize - only executed when testing in the browser.
facebookConnectPlugin.browserInit(<APP_ID>);
}
}
I have tried the window.fbAsyncInit both inside and out of the call I make for onDeviceReadyFacebook, trying to follow the advice from different forums...
So finally the error occurs within the call I have made to login:
function fb_login(){
var login_data = {};
client.cmd = "login";
login_data.userid = user_id;
login_data.cmd = "login";
facebookConnectPlugin.login([
'user_about_me',
'email',
'user_status',
'user_posts',
'user_photos',
'user_videos',
'user_friends'
],function(response) {
// success
...
Saying that the facebookConnectPlugin is undefined. After sligthly modifying different areas and everything else about the app is working, I would generally say that I'm not specifying the right source url for the primary JS file...
One last question on this topic: if I have correctly put in my Content Security Policy, is there any reason I need to use a plugin when I can just use the Facebook all.js they provide as is used in the browser version? I have got my key hash and other properties defined to add the android platform, I would have thought I can specify those attributes to match the platform...
EDIT: The plugin branch in question is located here.
UPDATE 2:
#JesseMonroy650:
Yes; a few things are definitely becoming clearer, but I did switch to cordova-plugin-facebookconnect-orlando, but adding that made the build crash, the log file result saying the message "...-FacebookLib/ant-build does not exist". I found the exact problem happening here, so I've now tried the same npm plugin and preference settings that was used there. It now builds, but I have the same problem (facebookConnectPlugin is undefined).
However, I checked the repo again this morning, specifically the path:
/platforms/android/assets/www/index.html
To see what I am crucially missing :
<div id="fb-root"></div>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/facebookConnectPlugin.js">/script>
So hopefully if I copy off this example, I should be alright now. Will be trying again tonight.
Any help is always very appreciated!
The code added to index.html has finally resolved the issue. I tidied up the actual call to the login as demonstrated, but ultimately the variable wasn't found because I hadn't done the script include. Confusion over the scripts to include and what path they would be.
BIG relief!!! Props to you #JesseMonroy650 for steering me in the right direction of a deprecated plugin.
Currently using the Parse JavaScript SDK for a web app, but I'm also new to Backbone, and since this particular problem is in functionality that Parse copied over from Backbone, I'm not sure exactly where I'm making my mistake.
I have index.html, with this basic structure & script template tag (to be used by _underscore):
<div id="my-app">
</div>
<script type="text/template" id="album-header-template">
<div id="some-id">
Some Content
</div>
</script>
At the end of <body>, the following script tags, to take care of Parse dependencies, load Parse, & use my own JS file:
<script src="libraries/node_modules/jquery/dist/jquery.min.js"></script>
<script src="libraries/node_modules/underscore/underscore-min.js"></script>
<script src="libraries/node_modules/parse/dist/parse-latest.min.js"></script>
<script src="app/ParseApp.js"></script>
Then in ParseApp.js, where I am trying to get off the ground by creating simple objects and views, I have the following:
$(function () {
var Album = Parse.Object.extend("Album",{
// Default attributes for the album
defaults: {
name: "Album Title"
},
// Ensure that each album created has a title
initialize: function() {
if (!this.get("name")) {
this.set({"name": this.defaults.content});
}
},
});
var HomeView = Parse.View.extend({
el: $("#my-app"),
initialize: function() {
console.log("new instance of HomeView");
this.render();
},
render: function() {
this.$el.html(_.template($("#album-header-template").html()));
}
});
new HomeView;
});
When I run index.html in the browser, I get the following error in console: Uncaught TypeError: Cannot read property 'extend' of undefined (occurring at the var Home View = Parse.View.extend line).
Originally, I had thought this might be because Parse wasn't initiated in time for ParseApp.js to use it, based on my scripts loading. However, I ran the recommended "Test the SDK" script from Parse, and it's indeed initialized (in addition, adding an object with var Album works fine). So I'm really stuck on what's causing either HomeView or Parse.View to be "undefined".
Likely a straightforward answer that I'm overlooking, but any help would be greatly appreciated, and I could provide full files if need be.
Not a very satisfying answer, but thanks to the help from #Yura & #Daniel Blank, discovered that the error was resulting because the most recent versions of the Parse SDK (everything after 1.6.0) no longer include full Backbone functionality. This includes the version I had been using locally from npm.
The best explanation of the Parse SDK direction is in the link given above, and there seem to be three options, for those hoping to continue using Parse and/or Backbone:
Use an old version (1.5.0 being the most recent that includes Backbone functionality) in order to maintain your Backbone functions, such as Parse.Collection or Parse.Router.
Try going Parse SDK-agnostic, while continuing to use Backbone. Can use the basic Parse REST API, or try one of the GitHub projects attempting to do that linking for you.
Give up on Backbone going forward, and use Parse with VanillaJS, or perhaps switch over to React (which is obviously the direction Facebook would want Parse to head)
I'm too inexperienced to recommend one of the three, although #1 seems the easiest, while #3 seems far and away the most maintainable. Still trying to make my own decision, but that's outside the scope of my original question. Thanks for the help, everyone.
2 things jump out at me:
I don't see where you initialize Parse... typically that
produces a different error, but still might be an issue
You are referencing your own local library for Parse... maybe try targeting the officially deployed version.
script src="http://www.parsecdn.com/js/parse-1.2.13.min.js"
I am developing chrome extension. I want to connect some API to current tab after click on button in popup.html. I use this code in popup.js:
$('button').click(function() {
chrome.tabs.executeScript({
file: 'js/ymaps.js'
}, function() {});
});
In ymaps.js I use following code to connect API to current tab:
var script = document.createElement('script');
script.src = "http://api-maps.yandex.ru/2.0-stable/?load=package.standard&lang=ru-RU";
document.getElementsByTagName('head')[0].appendChild(script);
This API is needed to use Yandex Maps. So, after that code I create <div> where map should be placed:
$('body').append('<div id="ymapsbox"></div>');
And this simple code only loads map to created <div>:
ymaps.ready(init);//Waits DOM loaded and run function
var myMap;
function init() {
myMap = new ymaps.Map("ymapsbox", {
center: [55.76, 37.64],
zoom: 7
});
}
I think, everything is clear, and if you are still reading, I'll explain what is the problem.
When I click on button in my popup.html I get in Chrome's console Uncaught ReferenceError: ymaps is not defined. Seems like api library isn't connected. BUT! When I manually type in console ymaps - I get list of available methods, so library is connected. So why when I call ymaps-object from executed .js-file I get such an error?
UPD: I also tried to wrap ymaps.ready(init) in $(document).ready() function:
$(document).ready(function() {
ymaps.ready(init);
})
But error is still appearing.
Man below said that api library maybe isn't loaded yet. But this code produces error too.
setTimeout(function() {
ymaps.ready(init);
}, 1500);
I even tried to do such a way...
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) {
if (changeInfo.status == "complete") {
chrome.tabs.executeScript({
file: 'js/gmm/yandexmaps.js'
});
}
});
ymaps is not defined because you're trying to use it in the content script, while the library is loaded in the context of the page (via the <script> tag).
Usually, you can solve the problem by loading the library as a content script, e.g.
chrome.tabs.executeScript({
file: 'library.js'
}, function() {
chrome.tabs.executeScript({
file: 'yourscript.js'
});
});
However, this will not solve your problem, because your library loads more external scripts in <script> tags. Consequently, part of the library is only visible to scripts within the web page (and not to the content script, because of the separate script execution environments).
Solution 1: Intercept <script> tags and run them as a content script.
Get scriptTagContext.js from https://github.com/Rob--W/chrome-api/tree/master/scriptTagContext, and load it before your other content scripts. This module solves your problem by changing the execution environment of <script> (created within the content script) to the content script.
chrome.tabs.executeScript({
file: 'scriptTagContext.js'
}, function() {
chrome.tabs.executeScript({
file: 'js/ymaps.js'
});
});
See Rob--W/chrome-api/scriptTagContext/README.md for documentation.
See the first revision of this answer for the explanation of the concept behind the solution.
Solution 2: Run in the page's context
If you -somehow- do not want to use the previous solution, then there's another option to get the code to run. I strongly recommend against this method, because it might (and will) cause conflicts in other pages. Nevertheless, for completeness:
Run all code in the context of the page, by inserting the content scripts via <script> tags in the page (or at least, the parts of the extension that use the external library). This will only work if you do not use any of the Chrome extension APIs, because your scripts will effectively run with the limited privileges of the web page.
For example, the code from your question would be restructed as follows:
var script = document.createElement('script');
script.src = "http://api-maps.yandex.ru/2.0-stable/?load=package.standard&lang=ru-RU";
script.onload = function() {
var script = document.createElement('script');
script.textContent = '(' + function() {
// Runs in the context of your page
ymaps.ready(init);//Waits DOM loaded and run function
var myMap;
function init() {
myMap = new ymaps.Map("ymapsbox", {
center: [55.76, 37.64],
zoom: 7
});
}
} + ')()';
document.head.appendChild(script);
};
document.head.appendChild(script);
This is just one of the many ways to switch the execution context of your script to the page. Read Building a Chrome Extension - Inject code in a page using a Content script to learn more about the other possible options.
This is not a timing issue, rather an "execution environment"-related issue.
You inject the script into the web-page's JS context (inserting the script tag into head), but try to call ymaps from the content script's JS context. Yet, content-scripts "live" in an isolated world and have no access to the JS context of the web-page (take a look at the docs).
EDIT (thx to Rob's comment)
Usually, you are able to bundle a copy of the library and inject it as a content script as well. In your perticular case, this won't help either, since the library itself inserts script tags into to load dependencies.
Possible solutions:
Depending on your exact requirements, you could:
Instead of inserting the map into the web-page, you could display (and let the user interact with) it in a popup window or new tab. You will provide an HTML file to be loaded in this new window/tab containing the library (either referencing a bundled copy of the file or using a CDN after relaxing the default Content Security Policy - the former is the recommended way).
Modify the external library (i.e. to eliminate insertion of script tags). I would advise against it, since this method introduces additional maintainance "costs" (e.g. you need to repeat the process every time the library is updated).
Inject all code into the web-page's context.
Possible pitfall: Mess up the web-pages JS, e.g. overwriting already defined variables/functions.
Also, this method will become increasingly complex if you need to interact with chrome.* APIs (which will not be available to the web-page's JS context, so you'll need to device a proprietary message passing mechanism, e.g. using custom events).
Yet, if you only need to execute some simple initialization code, this is a viable alternative:
E.g.:
ymaps.js:
function initMap() {
ymaps.ready(init);//Waits DOM loaded and run function
var myMap;
function init() {
myMap = new ymaps.Map("ymapsbox", {
center: [55.76, 37.64],
zoom: 7
});
}
}
$('body').append('<div id="ymapsbox"></div>');
var script1 = document.createElement('script');
script1.src = 'http://api-maps.yandex.ru/2.0-stable/?load=package.standard&lang=ru-RU';
script1.addEventListener('load', function() {
var script2 = document.createElement('script');
var script2.textContent = '(' + initMap + ')()';
document.head.appendChild(script2);
});
document.head.appendChild(script1);
Rob already pointed to this great resource on the subject:
Building a Chrome Extension - Inject code in a page using a Content script
There is a much easier solutioin from Yandex itself.
// div-container of the map
<div id="YMapsID" style="width: 450px; height: 350px;"></div>
<script type="text/javascript">
var myMap;
function init (ymaps) {
myMap = new ymaps.Map("YMapsID", {
center: [55.87, 37.66],
zoom: 10
});
...
}
</script>
// Just after API is loaded the function init will be invoked
// On that moment the container will be ready for usage
<script src="https://...?load=package.full&lang=ru_RU&onload=init">
Update
To work this properly you must be sure that init has been ready to the moment of Yandex-scirpt is loaded. This is possible in the following ways.
You place init on the html page.
You initiate loading Yandex-script from the same script where init is placed.
You create a dispatcher on the html page which catches the ready events from both components.
And you also need to check that your container is created to the moment of Yandex-script is loaded.
Update 2
Sometimes it happens that init script is loaded later than Yandex-lib. In this case it is worth checking:
if(typeof ymaps !== 'undefined' && typeof ymaps.Map !== 'undefined') {
initMap();
}
Also I came across a problem with positioning of the map canvas, when it is shifted in respect to the container. This may happen, for example, when the container is in a fading modal window. In this case the best is to invoke a window resize event:
$('#modal').on('shown.bs.modal', function (e) {
window.dispatchEvent(new Event('resize'));
});
I have a Dojo 1.7.4 app that is getting "Unable to get value of the property 'dir': object is null or undefined" error when loading pages in IE9.
I'm using an AMD build, and the error does not happen when it has to load all the files individually.
All the code that I have control over is wrapped in dojo/ready and dom/domReady! calls to the point of paranoia.
When the error occurs, and I catch it with the IE9 debugger, and Call stack reveals that the error occurs when calling isBodyLtr, but the top of the call stack is nls/synapse_en-gb.js. The nls/synapse_en-gb.js file seems to be the compile nls file with all the en-gb translations used by the application.
This seems to be getting loaded by virtue of having "en-gb" as my only locale entry in my dojoConfig, and I don't seem have control to ensure it is also wrapped in a dojo/ready or dojo/domReady!.
Here is the sample code in my HTML that bootstraps the Dojo package.
Any pointers for preventing the translation file from running until the dom and remaining Dojo files have fully loaded?
<script type="text/javascript">
//<![CDATA[
var dojoConfig = {
async: true,
parseOnLoad: true,
isDebug: true,
locale: "en-gb",
baseUrl: "/synapse/js/dojo/dojo/",
paths: {"synapse": "../../synapse"}
};
//]]>
</script>
<script type="text/javascript" src="/synapse/js/dojo/dojo/dojo.js"></script>
<script type="text/javascript">
//<![CDATA[
require(['dojo/ready', 'synapse/synapse', 'dojo/domReady!'], function(ready) {
ready(function () {
require(['dojo/ready', 'synapse/overlay','dojo/domReady!'], function (ready, package) {
ready(function() {
package.init();
});
});
});
});
//]]>
Update: 17 April 2013
To try and work out what function calls are in the stack trace, I bootstrapped from dojo.js.uncompress.js.
This shows me that nls/synapse_en-gb.js is the entry point, with calls to the var def = function() (which gets exposed in the global namespace as define, then checkComplete, then execModule and so forth.
Since this seems to run before the DOM is even loaded, I needs to find a way to ensure that nls/synapse_en-gb.js is not run until the DOM is loaded.
Looking at my generated synapse/synapse.js, there is a *now function at the base that appears to preload the i18n files file. i.e.
"*now":function(r){
r(["dojo/i18n!*preload*synapse/nls/synapse*[\"ar\",\"ca\",\"cs\",\"da\",\"de\",\"el\",\"en-gb\",\"en-us\",\"es-es\",\"fi-fi\",\"fr-fr\",\"he-il\",\"hu\",\"it-it\",\"ja-jp\",\"ko-kr\",\"nl-nl\",\"nb\",\"pl\",\"pt-br\",\"pt-pt\",\"ru\",\"sk\",\"sl\",\"sv\",\"th\",\"tr\",\"zh-tw\",\"zh-cn\",\"ROOT\"]"]);
}
I may end up having to relocate all the dojo loading until after so there's a much better chance of the DOM having been loaded, before dojo doing it's thing.
you can control the execution of the ready function by adding a number before the actual function:
ready(999999,function() {
package.init();
});
Small numbers mean early execution, big numbers late execution !
You have nested a ready function inside a ready function. I don't think their are ment to be used that way...
I ended up having to move the inline portion of the script to after the </body> tag.