Getting post objects from ACS with photo_id - titanium

I'm developing an App that gets data from ACS, the post objects.
In my app there is button and when the users click that button it get the posts data.
In every post there is also a photo_id, which allows me to get the photo url from the cloud.
But there is a problem, it has a callback function and by the time the callback occurs it is too late.
Anyway, the code below only shows the last post with a photo, the first post doesn't have a photo.
(there are only 2 post objects so far).
I believe the problem is in the callback, but I can't seem to fix it.
Hope you guys can help me out, thanks in advance!
Here is my code:
function getCarsClick() {
Cloud.Posts.query({
page: 1,
per_page: 20
}, function (e) {
if (e.success) {
var tableData = [];
for (var i = 0; i < e.posts.length; i++) {
var post = e.posts[i];
var row = Titanium.UI.createTableViewRow();
var title = Titanium.UI.createLabel({
text:post.title,
font:{fontSize:18,fontWeight:'bold'},
color:'#ef349d',
width:'auto',
textAlign:'left',
top:2,
left:40,
height:30
});
var subtitle = Titanium.UI.createLabel({
text:post.content,
font:{fontSize:12,fontWeight:'normal'},
color:'#000000',
width:'auto',
textAlign:'left',
bottom:10,
left:60,
height:32
});
row.add(title);
row.add(subtitle);
row.hasChild=true;
row.height = 80;
row.selectedBackgroundColor = '#ef349d';
Cloud.Photos.show({
photo_id: post.photo_id
}, function (e) {
if (e.success) {
var photo = e.photos[0];
var img1 = Ti.UI.createImageView({image:photo.urls.square_75,width:30,height:30,left:2, top:2});
row.add(img1);
} else {
alert('Error:\n' +
((e.error && e.message) || JSON.stringify(e)));
}
});
tableData.push(row);
}
//add table data
$.tableview1.setData(tableData);
} else {
alert('Error:\n' +
((e.error && e.message) || JSON.stringify(e)));
}
});
}

If you pass a photo into the post using the default parameter provided, the image should come back by default and not require you to make an additonal API call to get the photo.
I would also suggest if you are just starting out to use Alloy and more importantly use ListViews not TableView
https://github.com/aaronksaunders/AppC-Alloy-Book-Misc

Related

Track YouTube Video Playback with jQuery and Google Analytics Events

I have 4 iframe and I want to recover by clicking on their id .
I walked my iframe using google analytic and I put their id in a table.
Then I create an object of type YT.Player
Probleme : the method onPlayerStateChange does not run .
here is my code :
<script type="text/javascript">
/*
YouTube Analytics
Code adapted from:
http://www.lunametrics.com/blog/2012/10/22/automatically-track-youtube-videos-events-google-analytics/
http://lunametrics.wpengine.netdna-cdn.com/js/lunametrics-youtube.js
Code adapted by Alex Mueller for ISITE Design http://isitedesign.com
*/
// enable cross-domain scripting in IE < 10 for the YouTube Data API
// https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js
if(window.XDomainRequest){jQuery.ajaxTransport(function(e){if(e.crossDomain&&e.async){if(e.timeout){e.xdrTimeout=e.timeout;delete e.timeout}var t;return{send:function(n,r){function i(e,n,i,s){t.onload=t.onerror=t.ontimeout=jQuery.noop;t=undefined;r(e,n,i,s)}t=new XDomainRequest;t.onload=function(){i(200,"OK",{text:t.responseText},"Content-Type: "+t.contentType)};t.onerror=function(){i(404,"Not Found")};t.onprogress=jQuery.noop;t.ontimeout=function(){i(0,"timeout")};t.timeout=e.xdrTimeout||Number.MAX_VALUE;t.open(e.type,e.url);t.send(e.hasContent&&e.data||null)},abort:function(){if(t){t.onerror=jQuery.noop;t.abort()}}}}})}
// load the YouTube iframe API
var tag = document.createElement('script');
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// initialize our arrays to hold video and player information
var playerArray = [],
videoArray = [];
// safely pass the jQuery object as $
(function($) {
// enables tracking of all YouTube videos on the page
function trackYouTube() {
// iterate through every iframe on the page
$('iframe').each(function(i) {
// grab the video source and other properties
var baseUrlLength,
$iframe = $(this),
iframeSrc = $iframe.attr('src'),
isYouTubeVideo = false,
videoID,
url;
// if the video uses the http protocol
if (iframeSrc.substr(0,25) == "http://www.youtube.com/v/") {
baseUrlLength = 25;
isYouTubeVideo = true;
}
// otherwise if the video uses the https protocol
else if (iframeSrc.substr(0,26) == "https://www.youtube.com/v/") {
baseUrlLength = 26;
isYouTubeVideo = true;
}
// if we're dealing with a YouTube video, store its information in our arrays
if (isYouTubeVideo) {
// grab the videoID
videoID = iframeSrc.substr(baseUrlLength);
url = '//gdata.youtube.com/feeds/api/videos/' + videoID + '?v=2&alt=json';
// if the ID ends with extra characters...
if (videoID.indexOf('&') > -1) {
// ...remove the extra characters
videoID = videoID.substr(0, videoID.indexOf('&'));
}
// put an object in our array with the videoID...
videoArray[i] = {};
videoArray[i].id = videoID;
// put the videoID on the iframe as its id
$iframe.attr('id', videoID);
}
});
}
$(function() {
// initiate tracking on document ready
trackYouTube();
onYouTubeIframeAPIReady();
});
})(jQuery);
function onYouTubeIframeAPIReady() {
// insert YouTube Player objects into our playerArray
for (var i = 0; i < videoArray.length; i++) {
playerArray[i] = new YT.Player(videoArray[i].id, {
events: {
'onStateChange': onPlayerStateChange
}
});
}
}
// when the player changes states
function onPlayerStateChange(event) {
// if the video begins playing, send the event
if (event.data == YT.PlayerState.PLAYING) {
alert();
}
// if the video ends, send the event
if (event.data == YT.PlayerState.ENDED) {
alert();
}
}
</script>
You have to set the enablejsapi parameter to 1 in your iframe embed link.
By default, the parameter is set to 0 and unless you set it to 1, the callbacks won't work.
Reference: https://developers.google.com/youtube/js_api_reference

vline add remote stream for callee fail

I am trying to use your api in a custom app with imported users.
Everything works fine (auth_token, login, call initiation) , but when the callee should get a response and add the remotestream nothing happens. no errors get shown in the console.
I would appreciate if someone takes a look at the code and tells me what i m missing.
I tried the vline demo at https://freeofcinema.vline.com and it worked with the same browsers and conditions between the two computers. In my app it is a http , but i tried it also with https, and the same problem came up. This is some simplified code i used to test the api.
var Streams = [];
var Vsession = null;
var Vline = (function(){
var Client;
var authToken;
var service_id = 'freeofcinema';
var profile = null;
var Person;
var Calls = [];
var onMessage = function(event){
//alert('message');
var msg = event.message, sender = msg.getSender();
console.log(sender.getDisplayName() +'sais: '+ msg.getBody());
console.log(event);
}
var onMediaSession = function(event){
console.log(event);
var mediaSession = event.target;
InitSession(mediaSession);
}
function Call(mediaSession) {
mediaSession.
on('change', alert_info);
}
function alert_info(b){
console.log(b);
}
function InitSession(mediaSession){
mediaSession.on('mediaSession:addRemoteStream', function(event) {
alert('addRemoteStream');
});
mediaSession.on('mediaSession:addLocalStream', function(event) {
alert('addLocalStream');
});
mediaSession.on('mediaSession:removeLocalStream mediaSession:removeRemoteStream', function(event) {
console.log('removedStream');
});
Calls.push(new Call(mediaSession));
}
return {
init : function(){
if(profile){
return;
}
profile = {
"displayName" : //some getusrname function...
};
$.post('vtoken.php',{//get auth token
id : Comm.Voip_user().id
},function(data){
authToken = data;
Client = vline.Client.create({
"serviceId": service_id,
"ui" : true
});
Client.on('recv:im', onMessage , this);
Client.on('add:mediaSession', onMediaSession, this);
Client.on('login', function(e) {
Vsession = e.target;
//alert('loged in');
});
Client.login(service_id, profile, authToken);
});
},
getPerson : function(id){//id of user to call
if(Vsession){
Vsession.getPerson(id).
done(function(person){
Person = person;
Vsession.startMedia(id);
});
}
}
}
}());
Thank you for your response.
I tried with one user from the app, and another from the https://freeofcinema.vline.com, and the same problem occured. Also the call (in pending state) gets terminated after a short while..
When passing ui:true when creating the client, you do not have to handle the media sessions yourself. Just comment the line Client.on('add:mediaSession', onMediaSession, this); and it should just work.

Cannot dynamically change a caption 'track' in Video.js

I'm coding a basic video marquee and one of the key requirements is that the videos need to be able to advance while keeping the player in full screen.
Using Video.js (4.1.0) I have been able to get everything work correctly except that I cannot get the captions to change when switching to another video.
Either inserting a "track" tag when the player HTML is first created or adding a track to the 'options' object when the player is initialized are the only ways I can get the player to display the "CC" button and show captions. However, I cannot re-initialize the player while in full screen so changing the track that way will not work.
I have tried addTextTrack and addTextTracks and both show that the tracks have been added - using something like console.log(videoObject.textTracks()) - but the player never shows them or the "CC" button.
Here is my code, any help is greatly appreciated:
;(function(window,undefined) {
// VIDEOS OBJECT
var videos = [
{"volume":"70","title":"TEST 1","url":"test1.mp4","type":"mp4"},
{"volume":"80","title":"TEST 2","url":"test2.mp4","type":"mp4"},
{"volume":"90","title":"TEST 3","url":"test3.mp4","type":"mp4"}
];
// CONSTANTS
var VIDEO_BOX_ID = "jbunow_marquee_video_box", NAV_TEXT_ID = "jbunow_marquee_nav_text", NAV_ARROWS_ID = "jbunow_marquee_nav_arrows", VIDEO_OBJ_ID = "jbunow_marquee_video", NAV_PREV_ID = "jbunow_nav_prev", NAV_NEXT_ID = "jbunow_nav_next";
// GLOBAL VARIABLS
var videoObject;
var currentTrack = 0;
var videoObjectCreated = false;
var controlBarHideTimeout;
jQuery(document).ready(function(){
// CREATE NAV ARROWS AND LISTENERS, THEN START MARQUEE
var navArrowsHtml = "<div id='" + NAV_PREV_ID + "' title='Play Previous Video'></div>";
navArrowsHtml += "<div id='" + NAV_NEXT_ID + "' title='Play Next Video'></div>";
jQuery('#' + NAV_ARROWS_ID).html(navArrowsHtml);
jQuery('#' + NAV_PREV_ID).on('click',function() { ChangeVideo(GetPrevVideo()); });
jQuery('#' + NAV_NEXT_ID).on('click',function() { ChangeVideo(GetNextVideo()); });
ChangeVideo(currentTrack);
});
var ChangeVideo = function(newIndex) {
var videoBox = jQuery('#' + VIDEO_BOX_ID);
if (!videoObjectCreated) {
// LOAD PLAYER HTML
videoBox.html(GetPlayerHtml());
// INITIALIZE VIDEO-JS
videojs(VIDEO_OBJ_ID, {}, function(){
videoObject = this;
// LISTENERS
videoObject.on("ended", function() { ChangeVideo(GetNextVideo()); });
videoObject.on("loadeddata", function () { videoObject.play(); });
videoObjectCreated = true;
PlayVideo(newIndex);
});
} else { PlayVideo(newIndex); }
}
var PlayVideo = function(newIndex) {
// TRY ADDING MULTIPLE TRACKS
videoObject.addTextTracks([{ kind: 'captions', label: 'English2', language: 'en', srclang: 'en', src: 'track2.vtt' }]);
// TRY ADDING HTML
//jQuery('#' + VIDEO_OBJ_ID + ' video').eq(0).append("<track kind='captions' src='track2.vtt' srclang='en' label='English' default />");
// TRY ADDING SINGLE TRACK THEN SHOWING USING RETURNED ID
//var newTrack = videoObject.addTextTrack('captions', 'English2', 'en', { kind: 'captions', label: 'English2', language: 'en', srclang: 'en', src: 'track2.vtt' });
//videoObject.showTextTrack(newTrack.id_, newTrack.kind_);
videoObject.volume(parseFloat(videos[newIndex]["volume"]) / 100); // SET START VOLUME
videoObject.src({ type: "video/" + videos[newIndex]["type"], src: videos[newIndex]["url"] }); // SET NEW SRC
videoObject.load();
videoObject.ready(function () {
videoObject.play();
clearTimeout(controlBarHideTimeout);
controlBarHideTimeout = setTimeout(function() { videoObject.controlBar.fadeOut(); }, 2000);
jQuery('#' + NAV_TEXT_ID).fadeOut(150, function() {
currentTrack = newIndex;
var navHtml = "";
navHtml += "<h1>Now Playing</h1><h2>" + videos[newIndex]["title"] + "</h2>";
if (videos.length > 1) { navHtml += "<h1>Up Next</h1><h2>" + videos[GetNextVideo()]["title"] + "</h2>"; }
jQuery('#' + NAV_TEXT_ID).html(navHtml).fadeIn(250);
});
});
}
var GetPlayerHtml = function() {
var playerHtml = "";
playerHtml += "<video id='" + VIDEO_OBJ_ID + "' class='video-js vjs-default-skin' controls='controls' preload='auto' width='560' height='315'>";
playerHtml += "<source src='' type='video/mp4' />";
//playerHtml += "<track kind='captions' src='track.vtt' srclang='en' label='English' default='default' />";
playerHtml += "</video>";
return playerHtml;
}
var GetNextVideo = function() {
if (currentTrack >= videos.length - 1) { return 0; }
else { return (currentTrack + 1); }
}
var GetPrevVideo = function() {
if (currentTrack <= 0) { return videos.length - 1; }
else { return (currentTrack - 1); }
}
})(window);
The current VideoJS implementation (4.4.2) loads every kind of text tracks (subtitles, captions, chapters) on initialization time of the player itself, so it grabs correctly only those, which are defined between the <video> tags.
EDIT: I meant it does load them when calling addTextTrack, but the player UI will never update after initialization time, and will always show the initialization time text tracks.
One possible workaround is if you destroy the complete videojs player and re-create it on video source change after you have refreshed the content between the <video> tags. So this way you don't update the source via the videojs player, but via dynamically adding the required DOM elements and initializing a new player on them. Probably this solution will cause some UI flashes, and is quite non-optimal for the problem. Here is a link about destroying the videojs player
Second option is to add the dynamic text track handling to the existing code, which is not as hard as it sounds if one knows where to look (I did it for only chapters, but could be similar for other text tracks as well). The code below works with the latest official build 4.4.2. Note that I'm using jQuery for removing the text track elements, so if anyone applies these changes as is, jQuery needs to be loaded before videojs.
Edit the video.dev.js file as follows:
1: Add a clearTextTracks function to the Player
vjs.Player.prototype.clearTextTracks = function() {
var tracks = this.textTracks_ = this.textTracks_ || [];
for (var i = 0; i != tracks.length; ++i)
$(tracks[i].el()).remove();
tracks.splice(0, tracks.length);
this.trigger("textTracksChanged");
};
2: Add the new 'textTracksChanged' event trigger to the end of the existing addTextTrack method
vjs.Player.prototype.addTextTrack = function(kind, label, language, options) {
...
this.trigger("textTracksChanged");
}
3: Handle the new event in the TextTrackButton constructor function
vjs.TextTrackButton = vjs.MenuButton.extend({
/** #constructor */
init: function(player, options) {
vjs.MenuButton.call(this, player, options);
if (this.items.length <= 1) {
this.hide();
}
player.on('textTracksChanged', vjs.bind(this, this.refresh));
}
});
4: Implement the refresh method on the TextTrackButton
// removes and recreates the texttrack menu
vjs.TextTrackButton.prototype.refresh = function () {
this.removeChild(this.menu);
this.menu = this.createMenu();
this.addChild(this.menu);
if (this.items && this.items.length <= this.kind_ == "chapters" ? 0 : 1) {
this.hide();
} else
this.show();
};
Sorry, but for now I cannot link to a real working example, I hope the snippets above will be enough as a starting point to anyone intrested in this.
You can use this code when you update the source to a new video. Just call the clearTextTracks method, and add the new text tracks with the addTextTrack method, and the menus now should update themselves.
Doing the exact same thing (or rather NOT doing the exact same thing)... really need to figure out how to dynamically change / add a caption track.
This works to get it playing via the underlying HTML5, but it does not show the videojs CC button:
document.getElementById("HtmlFiveMediaPlayer_html5_api").innerHTML = '<track label="English Captions" srclang="en" kind="captions" src="http://localhost/media/captiontest/demo_Brian/demo_h264_1.vtt" type="text/vtt" default />';

Win 8 Apps : saving and retrieving data in roamingfolder

I'm trying to store few user data into a roamingFolder method/property of Windows Storage in an app using JavaScript. I'm following a sample code from the Dev Center, but no success. My code snippet is as follows : (OR SkyDrive link for the full project : https://skydrive.live.com/redir?resid=F4CAEFCD620982EB!105&authkey=!AE-ziM-BLJuYj7A )
filesReadCounter: function() {
roamingFolder.getFileAsync(filename)
.then(function (filename) {
return Windows.Storage.FileIO.readTextAsync(filename);
}).done(function (data) {
var dataToRead = JSON.parse(data);
var dataNumber = dataToRead.count;
var message = "Your Saved Conversions";
//for (var i = 0; i < dataNumber; i++) {
message += dataToRead.result;
document.getElementById("savedOutput1").innerText = message;
//}
//counter = parseInt(text);
//document.getElementById("savedOutput2").innerText = dataToRead.counter;
}, function () {
// getFileAsync or readTextAsync failed.
//document.getElementById("savedOutput2").innerText = "Counter: <not found>";
});
},
filesDisplayOutput: function () {
this.filesReadCounter();
}
I'm calling filesDisplayOutput function inside ready method of navigator template's item.js file, to retrieve last session's data. But it always shows blank. I want to save upto 5 data a user may need to save.
I had some trouble running your code as is, but that's tangential to the question. Bottom line, you're not actually reading the file. Note this code, there's no then or done to execute when the promise is fulfilled.
return Windows.Storage.FileIO.readTextAsync(filename);
I hacked this in your example solution and it's working... typical caveats of this is not production code :)
filesReadCounter: function () {
roamingFolder.getFileAsync(filename).then(
function (filename) {
Windows.Storage.FileIO.readTextAsync(filename).done(
function (data) {
var dataToRead = JSON.parse(data);
var dataNumber = dataToRead.count;
var message = "Your Saved Conversions";
//for (var i = 0; i < dataNumber; i++) {
message += dataToRead.result;
document.getElementById("savedOutput1").innerText = message;
//}
//counter = parseInt(text);
//document.getElementById("savedOutput2").innerText = dataToRead.counter;
}, function () {
// readTextAsync failed.
//document.getElementById("savedOutput2").innerText = "Counter: <not found>";
});
},
function () {
// getFileAsync failed
})
},

BlackBerry 10 Cascades: How do I load data into a DropDown?

I have managed to load data from a remote Json web service into a QML ListView, but there doesn't seem to be any such thing for the DropDown control.
Does someone have an example or an alternative method to accomplish a DropDown bound to attachedObjects data sources in Cascades?
I have an alternate method for you, Do note that I have used google's web service here for demonstration purpose, you need to replace it with your url & parse response according to that.
import bb.cascades 1.0
Page {
attachedObjects: [
ComponentDefinition {
id: optionControlDefinition
Option {
}
}
]
function getData() {
var request = new XMLHttpRequest()
request.onreadystatechange = function() {
if (request.readyState == 4) {
var response = request.responseText
response = JSON.parse(response)
var addressComponents = response.results[0].address_components
for (var i = 0; i < addressComponents.length; i ++) {
var option = optionControlDefinition.createObject();
option.text = addressComponents[i].long_name
dropDown.add(option)
}
}
}
// I have used goole's web service url, you can replace with your url
request.open("GET", "http://maps.googleapis.com/maps/api/geocode/json?address=" + "Ahmedabad" + "&sensor=false", true)
request.send()
}
Container {
DropDown {
id: dropDown
}
Button {
onClicked: getData()
}
}
}
Hope this helps.