How to embed Wufoo form in Ember application - ember.js

My client has asked me to integrate a Wufoo form into their Ember application, and provided the following JS (anonymized):
<script type="text/javascript">var abc123;(function(d, t) {
var s = d.createElement(t), options = {
'userName':'example',
'formHash':'abc123',
'autoResize':true,
'height':'491',
'async':true,
'host':'wufoo.com',
'header':'show',
'ssl':true};
s.src = ('https:' == d.location.protocol ? 'https://' : 'http://') + 'www.wufoo.com/scripts/embed/form.js';
s.onload = s.onreadystatechange = function() {
var rs = this.readyState; if (rs) if (rs != 'complete') if (rs != 'loaded') return;
try { abc123 = new WufooForm();abc123.initialize(options);abc123.display(); } catch (e) {}};
var scr = d.getElementsByTagName(t)[0], par = scr.parentNode; par.insertBefore(s, scr);
})(document, 'script');</script>
I've tried including it in index.html and also creating a custom component, but keep getting an error from Wufoo:
TypeError: Cannot set property 'innerHTML' of null
Is there a way to use the provided Wufoo JS in an Ember.js app?

Related

Internationalization of ember application

I'm using ember-i18n lib for Internationalisation and want to save current locale in route like:
domain.com - empty for default en
doman.com/es, doman.com/de- for another
For this I tried to use rootURL
Router.reopen({
rootURL: '/' ('es' or 'de')
});
Problem: When rootURL is not empty, app can't redirect and fail with error: ember.debug.js:4903 Uncaught Error: Assertion Failed: Path / does not start with the provided rootURL /es/
Question: What is the best solution to make redirect, all logic will be hold in emebr so I can't move this logic into nginx and etc.
Another option is Make a wrapper route, looks like this:
this.route(
'lang', { path: '/:lang' }, function (){..}
);
This solution looks like not good:
link-to helper will require lang param
lang can't be empty (for default language)
UPDATE: I understand how to dynamic change rootURL, but can't auto redirect.
Found the solution, describe this logic in instance-initializer
export function initialize(app) {
var router = app.lookup('router:main');
var i18n = app.lookup('service:i18n');
var path = window.location.pathname;
var currentLang = ENV.i18n.defaultLocale;
var newPath = '';
var LangFromPath = path.match('^/([a-z]{2})(?:/|$)');
if (LangFromPath && LangFromPath[1]){
currentLang = (ENV.i18n.allowedLocales.indexOf(LangFromPath[1]) > -1) ? LangFromPath[1] : currentLang;
}
if (currentLang != ENV.i18n.defaultLocale) {
var newPath = '/' + currentLang + '/';
}
router.rootURL = newPath;
i18n.set('locale', currentLang);
if (newPath && path.indexOf(newPath) === -1) {
window.location.pathname = newPath;
}
}

IE9: store.find is failing

I can't seem to fetch new data in Internet Explorer 9. For the purpose of an example I test the store this way:
App.__container__.lookup('store:main').find('style')
The only error I receive is the following:
SCRIPT5022: Error: Assertion Failed: [object Object]
Does Ember-data works out of the box (without polyfills, ...) in Internet Explorer 9?
versions:
Ember: 1.9.1
Ember-data: 1.0.0-beta.12
Problem solved. When doing an AJAX request with jQuery, this normally happens through the XMLHttpRequest object.
On IE8-9, this object is not present, instead it uses XDomainRequest. The simplest fix for this is adding: https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest.
ember-data works out of the box with IE8+. According to this issue:
We've been supporting IE8 with our platform (built on Ember) for a
while now. Things I know:
shim/sham is not needed, it's polyfilled by Ember and Ember-Data.
You will need it if you want additional things like .bind() on a function, then you must prepend it to the vendor file (using Brocfile)
and we only include the shim for that purpose, not the sham
Solution Synthesis
Reason :
On IE8-9, this object is not present, instead it uses XDomainRequest.
Solution :
The issue is solved. When using an AJAX request with jQuery. Normally this is done through the XMLHttpRequest object. A simple fix would be using the Open-Source jQuery-ajaxTransport-XDomainRequest
Code : Adding :
jQuery-ajaxTransport-XDomainRequest.js
/*!
* jQuery-ajaxTransport-XDomainRequest - v1.0.4 - 2015-03-05
* https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest
* Copyright (c) 2015 Jason Moon (#JSONMOON)
* Licensed MIT (/blob/master/LICENSE.txt)
*/
(function(factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals.
factory(jQuery);
}
}(function($) {
// Only continue if we're on IE8/IE9 with jQuery 1.5+ (contains the ajaxTransport function)
if ($.support.cors || !$.ajaxTransport || !window.XDomainRequest) {
return $;
}
var httpRegEx = /^(https?:)?\/\//i;
var getOrPostRegEx = /^get|post$/i;
var sameSchemeRegEx = new RegExp('^(\/\/|' + location.protocol + ')', 'i');
// ajaxTransport exists in jQuery 1.5+
$.ajaxTransport('* text html xml json', function(options, userOptions, jqXHR) {
// Only continue if the request is: asynchronous, uses GET or POST method, has HTTP or HTTPS protocol, and has the same scheme as the calling page
if (!options.crossDomain || !options.async || !getOrPostRegEx.test(options.type) || !httpRegEx.test(options.url) || !sameSchemeRegEx.test(options.url)) {
return;
}
var xdr = null;
return {
send: function(headers, complete) {
var postData = '';
var userType = (userOptions.dataType || '').toLowerCase();
xdr = new XDomainRequest();
if (/^\d+$/.test(userOptions.timeout)) {
xdr.timeout = userOptions.timeout;
}
xdr.ontimeout = function() {
complete(500, 'timeout');
};
xdr.onload = function() {
var allResponseHeaders = 'Content-Length: ' + xdr.responseText.length + '\r\nContent-Type: ' + xdr.contentType;
var status = {
code: 200,
message: 'success'
};
var responses = {
text: xdr.responseText
};
try {
if (userType === 'html' || /text\/html/i.test(xdr.contentType)) {
responses.html = xdr.responseText;
} else if (userType === 'json' || (userType !== 'text' && /\/json/i.test(xdr.contentType))) {
try {
responses.json = $.parseJSON(xdr.responseText);
} catch(e) {
status.code = 500;
status.message = 'parseerror';
//throw 'Invalid JSON: ' + xdr.responseText;
}
} else if (userType === 'xml' || (userType !== 'text' && /\/xml/i.test(xdr.contentType))) {
var doc = new ActiveXObject('Microsoft.XMLDOM');
doc.async = false;
try {
doc.loadXML(xdr.responseText);
} catch(e) {
doc = undefined;
}
if (!doc || !doc.documentElement || doc.getElementsByTagName('parsererror').length) {
status.code = 500;
status.message = 'parseerror';
throw 'Invalid XML: ' + xdr.responseText;
}
responses.xml = doc;
}
} catch(parseMessage) {
throw parseMessage;
} finally {
complete(status.code, status.message, responses, allResponseHeaders);
}
};
// set an empty handler for 'onprogress' so requests don't get aborted
xdr.onprogress = function(){};
xdr.onerror = function() {
complete(500, 'error', {
text: xdr.responseText
});
};
if (userOptions.data) {
postData = ($.type(userOptions.data) === 'string') ? userOptions.data : $.param(userOptions.data);
}
xdr.open(options.type, options.url);
xdr.send(postData);
},
abort: function() {
if (xdr) {
xdr.abort();
}
}
};
});
return $;
}));

Famo.us: Slideshow tutorial with the Picasa API is out of date

I've been working on the famo.us Slideshow tutorial and realised that the API is no longer working.
Any ideas how can I still make this to work without the Picasa API?
You can keep the API by using the following code for SlideData.js
You can make it work by creating the objects returned by the url + parameters below and returning them as the JSON object if you do not want to use the API.
define(function(require, exports, module) {
var SlideData = {
picasaUrl: 'https://picasaweb.google.com/data/feed/api/all',
queryParams: '?kind=photo&q=puppy&max-results=5&imgmax=720&alt=json',
defaultImage: 'https://lh4.googleusercontent.com/-Roszbra0TlI/VB-fE83NAXI/AAAAAAAAACU/ITmhyZMHZrk/s720/cute%252520looking%252520white%252520and%252520black%252520french%252520Bulldog%252520Puppy.jpg'
};
SlideData.getUrl = function() {
return SlideData.picasaUrl + SlideData.queryParams;
};
SlideData.parse = function(data) {
var urls = [];
data = JSON.parse(data);
var entries = data.feed.entry;
for (var i = 0; i < entries.length; i++) {
var media = entries[i].media$group;
urls.push(media.media$content[0].url);
}
return urls;
};
module.exports = SlideData;
});

How do I return data to a template with Knockout and Requirejs modules?

I'm having a difficult time returning data from a module using RequireJS and Knockout to populate my markup for my single page app. Knockout can't seem to find my data binding observables.
I'm trying to keep each view in a separate js file, but I'm failing to identify where I've gone wrong. Here's what I have so far:
/app/app.js
define(function(require) {
require('simrou');
var $ = require('jQuery'),
ko = require('knockout'),
videoView = require('videoView');
var init = function() {
var viewModel = function() {
var self = this;
self.currentPage = ko.observable();
self.videoView = new videoView();
}
var view = new viewModel();
ko.applyBindings( view );
_router = new Simrou({
'/video/:id': [ view.videoView.getVideo ]
});
_router.start();
};
return {
init: init
};
});
/app/videoView.js
define(function(require) {
"use strict";
var $ = require('jQuery'),
ko = require('knockout');
return function() {
var self = this;
self.currentPage = ko.observable( 'showVideo' );
self.currentVideo = ko.observable();
self.videoData = ko.observableArray([]);
self.videoList = ko.observableArray([]);
var getVideo = function( event, params ) {
// ajax pseudo code
$.ajax({});
self.videoData( dataFromAjaxCall );
}
return {
getVideo: getVideo
};
};
});
index.html
When I browse to /#/video/14 I receive the following error:
Uncaught ReferenceError: Unable to parse bindings.
Bindings value: attr: { 'data-video-id': videoData().id }
Message: videoData is not defined
Here's the markup:
<section id="showVideo" data-bind="fadeVisible: currentPage()=='showVideo', with: $root">
<div class="video" data-bind="attr: { 'data-video-id': videoData().id }></div>
</section>
Like I said, I'm trying to keep each view separated, but I would love some enlightenment on what I'm doing wrong, or if this is even possible? Is there a better more efficient way?
videoData is a property of $root.videoView, not of the root model (the one you passed to applyBindings). It's also an observableArray, so videoData() is just a plain array and even if you get the context right, you won't be able to access its id property, since, being an array, it doesn't have.named properties.

Jquery Tool: Keep selected tab on refresh or save data

I am using jquery tool for tab Ui,
Now I want to keep tab selected on page reload. Is there any way to do that? below is my code
$(function() {
// setup ul.tabs to work as tabs for each div directly under div.panes
$("ul.tabs").tabs("div.panes > div");
});
Here is a simple implementation of storing the cookie and retrieving it:
function getCookie(c_name) {
var i, x, y, ARRcookies = document.cookie.split(";");
for (i = 0; i < ARRcookies.length; i++) {
x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
x = x.replace(/^\s+|\s+$/g, "");
if (x == c_name) {
return unescape(y);
}
}
}
function setCookie(c_name, value, exdays) {
var exdate = new Date();
exdate.setDate(exdate.getDate() + exdays);
var c_value = escape(value) + ((exdays == null) ? "" : "; expires=" + exdate.toUTCString());
document.cookie = c_name + "=" + c_value;
}
Then, to save/retrieve cookie data with jQuery UI Tabs:
$(function() {
// retrieve cookie value on page load
var $tabs = $('ul.tabs').tabs();
$tabs.tabs('select', getCookie("selectedtab"));
// set cookie on tab select
$("ul.tabs").bind('tabsselect', function (event, ui) {
setCookie("selectedtab", ui.index + 1, 365);
});
});
Of course, you'll probably want to test if the cookie is set and return 0 or something so that getCookie doesn't return undefined.
On a side note, your selector of ul.tabs may be improved by specifying the tabs by id instead. If you truly have a collection of tabs on the page, you will need a better way of storing the cookie by name - something more specific for which tab collection has been selected/saved.
UPDATE
Ok, I fixed the ui.index usage, it now saves with a +1 increment to the tab index.
Here is a working example of this in action: http://jsbin.com/esukop/7/edit#preview
UPDATE for use with jQuery Tools
According the jQuery Tools API, it should work like this:
$(function() {
//instantiate tabs object
$("ul.tabs").tabs("div.panes > div");
// get handle to the api (must have been constructed before this call)
var api = $("ul.tabs").data("tabs");
// set cookie when tabs are clicked
api.onClick(function(e, index) {
setCookie("selectedtab", index + 1, 365);
});
// retrieve cookie value on page load
var selectedTab = getCookie("selectedtab");
if (selectedTab != "undefined") {
api.click( parseInt(selectedTab) ); // must parse string to int for api to work
}
});
function getCookie(c_name) {
var i, x, y, ARRcookies = document.cookie.split(";");
for (i = 0; i < ARRcookies.length; i++) {
x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
x = x.replace(/^\s+|\s+$/g, "");
if (x == c_name) {
return unescape(y);
}
}
}
function setCookie(c_name, value, exdays) {
var exdate = new Date();
exdate.setDate(exdate.getDate() + exdays);
var c_value = escape(value) + ((exdays === null) ? "" : "; expires=" + exdate.toUTCString());
document.cookie = c_name + "=" + c_value;
}
Here is a working (unstyled) example: http://jsbin.com/ixamig/12/edit#preview
Here is what I see in Firefox when inspecting the cookie from the jsbin.com example:
This is what worked for me... at least I haven't run into any issues yet:
$('#tabs').tabs({
select: function (event, ui)
{
$.cookie('active_tab', ui.index, { path: '/' });
}
});
$('#tabs').tabs("option", "active", $.cookie('active_tab'));
I'm using: jQuery 1.8.2, jQuery UI 1.9.1, jQuery Cookie Plugin.
I set the "path" because in C# I set this value in a mvc controller which defaults to "/". If the path doesn't match, it wont overwrite the existing cookie. Here is my C# code to set the value of the same cookie used above:
Response.Cookies["active_tab"].Value = "myTabIndex";
Edit:
As of jQuery UI 1.10.2 (I just tried this version, not sure if it's broken in previous versions), my method doesnt work. This new code will set the cookie using jQuery UI 1.10.2
$('#tabs').tabs({
activate: function (event, ui) {
$.cookie('active_tab', ui.newTab.index(), { path: '/' });
}
});
The easiest way to survive between page refresh is to store the selected tab id in session or through any server-side script.
Only methods to store data on client side are: Cookies or localStorage.
Refer to thread: Store Javascript variable client side