+ Start a Discussion
Jim BoudreauxJim Boudreaux 

Simile Timeline S-Control

I found the Timeline S-Control on the AppExchange and the documentation says you can use it for Custom Objects.
Has anyone tried this and gained some insight as to how one might accomplish this?
Best Answer chosen by Admin (Salesforce Developers) 
zeezackisbackzeezackisback
ERROR: ........... {faultcode:'sf:INVALID_FIELD', faultstring:'INVALID_FIELD: IsDeleted, Id, Field, CreatedDate, Claim__r.CreatedBy.FirstName, Claim__r.CreatedBy.LastName ^ ERROR at Row:1:Column:63 Didn't understand relationship 'Claim__r' in field path. If you are attempting to use a custom relationship, be sure to append the '__r' after the custom relationship name. Please reference your WSDL or the describe call for the appropriate names.', detail:{fault:{exceptionCode:'INVALID_FIELD', exceptionMessage:' IsDeleted, Id, Field, CreatedDate, Claim__r.CreatedBy.FirstName, Claim__r.CreatedBy.LastName ^ ERROR at Row:1:Column:63 Didn't understand relationship 'Claim__r' in field path. If you are attempting to use a custom relationship, be sure to append the '__r' after the custom relationship name. Please reference your WSDL or the describe call for the appropriate names.', row:'1', column:'63', }, }, }

All Answers

jrotensteinjrotenstein
The Simile Timeline actually originates from an the MIT Simile project. It's a way of showing data in different formats, such as timelines, directories and maps.

The original version requires data in JSON format, while the version on the AppExchange has been modified to access data through S-Controls.

So, if you're having difficulty getting it to do something, take a look at the MIT website, then look closer at the modified code and you might be able to figure it out. However, be warned -- it's some very advanced JavaScript in there!
Jim BoudreauxJim Boudreaux

I am familiar with the MIT version, I was actually working on integrating the Simile Timeline into a VF page when I came across the AppExchange version.

You are right, it is some pretty advanced javascript, hense the request for insight! ;)

wpatterswpatters
Has anyone figured this out?  Or, how do you pull the data from salesforce into the timeline? I've been trying to dynamically create the xml file with javascript, but this is creating lots of problems.  Is it possible to substitute a long text area for the xml?
Jim BoudreauxJim Boudreaux
I gave up and just used the appexchange version. It works well enough.
wpatterswpatters
When you tried to create the xml file as a visualforce page, were you somewhat successful or did it say "xml is null"?  Also, did you succeed in integrating it with a custom object?


Message Edited by wpatters on 10-16-2008 08:41 AM
Jim BoudreauxJim Boudreaux
I abbandoned my original project in favor of using the appexchange version for its intended purpose. So, I didn't use a visualforce xml file, nor did I use it on a custom object. Sorry.
I wanted to use it on a vf page and display multiple records, sort of like a calendar, but I couldn't get that to work. The appexchange version works nicely on single records as an scontrol, for instance on the contacts standard object, displaying activities for that contact.
chrismclarenchrismclaren

I have the version from the Appexchange.  I have modified it so that from an account you get a gantt chart style of all the opportunities for that account.  I want to modify it so that on the dashboard we can see all the opportunities in a gant chart style.  Is this possible?  How is this done?

 

This is the code I have

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Timeline</title> <link href="/dCSS/Theme2/default/common.css" type="text/css" media="handheld,print,projection,screen,tty,tv" rel="stylesheet" > <!-- Include the MIT timeline library and CSS--> {!INCLUDE($SControl.Timeline_CSS)} {!INCLUDE($SControl.Timeline_mit_lib)} <!-- Apex AJAX connection library change--> <script src="/soap/ajax/8.0/connection.js" type="text/javascript"></script> <script type="text/javascript"> var theTimeLine; var eventSource; var baseURL = window.location.protocol + '//' + window.location.hostname; var isOpportunity = new Boolean("{!$Request.eid}" == "{!Opportunity.Id}"); var isContact = new Boolean("{!$Request.eid}" == "{!Contact.Id}"); var isAccount = new Boolean( "{!$Request.eid}" == "{!Account.Id}"); var isCase = new Boolean( "{!$Request.eid}" == "{!Case.Id}" ); // see what tab we are called from function validId(id) { return ("{!$Request.eid}" != null && "{!$Request.eid}" != "" && "{!$Request.eid}" === id); } var hasActivities = new Boolean( isOpportunity == true || isCase == true || isAccount == true ); function _WhatId() { if (isOpportunity == true) return "{!Opportunity.Id}"; if (isCase == true) return "{!Case.Id}"; if (isAccount == true) return "{!Account.Id}"; return null; } var WhatId = _WhatId(); /************************** * load the timeline UI, then query for events to add * all the events are added async to give a quicker load */ function initPage() { //build the timeline widget eventSource = new Timeline.DefaultEventSource(); var theme = Timeline.ClassicTheme.create(); theme.event.label.width = 300; // px this will truncate the labels that appear on the timline //theme.event.bubble.width = 480; //theme.event.bubble.height = 200; theme.ether.backgroundColors.unshift("#f3f3ec"); // set up the bands of info in the display var bandInfos = [ Timeline.createBandInfo({ eventSource: eventSource, date: Date(), width: "80%", intervalUnit: Timeline.DateTime.MONTH, intervalPixels: 100, theme: theme }), Timeline.createBandInfo({ showEventText: false, trackHeight: 0.5, trackGap: 0.2, eventSource: eventSource, date: Date(), width: "20%", intervalUnit: Timeline.DateTime.YEAR, intervalPixels: 200 }) ]; bandInfos[1].syncWith = 0; bandInfos[1].highlight = true; theTimeLine = Timeline.create(document.getElementById("my-timeline"), bandInfos); /************* * begin DATA queries * each query kicks off an async callback to plot/load the results, does not wait for all before drawing. * more can be added to support custom objects, to support custom objects, test for merge fields * decide what related records have dates, and create a layout callback for each. * this can also be used to support one scontrol on many different object page layouts * so, contact, opportunity, account or case can all run from this one scontrol * we do assume it is an inline scontrol */ if ( hasActivities == true && WhatId != null ) { //get all tasks related to this object ( must have a WhatId) sforce.connection.query( "Select Id,Subject,Status,ActivityDate,Description,CreatedDate,Owner.FirstName,Owner.LastName, Who.FirstName, Who.LastName from Task where WhatId=null", layoutTasks); // events sforce.connection.query( "Select Id, Subject, Location, ActivityDateTime,ActivityDate, IsAllDayEvent, DurationInMinutes, Description, Owner.FirstName,Owner.LastName, Who.FirstName, Who.LastName from Event where WhatId=null order by ActivityDate", layoutEvents); } // opportunity stage history if we are on an opp if ( validId( "{!Opportunity.Id}" ) ) { sforce.connection.query("Select CreatedById, CreatedDate, StageName, Amount, CloseDate from OpportunityHistory where OpportunityId ='{!Opportunity.Id}' and StageName <>'Speculative Lead' and StageName <>'Cancelled' and StageName <>'Lost' ", layoutOppHistory); } if ( validId("{!Account.Id}") ) { // we are on an account page, so show opportunities sforce.connection.query( "Select Id, Name, StageName, Amount, CloseDate, IsWon, IsClosed , NextStep, Operation_Start_Date__c, Operation_End__c from Opportunity where AccountId = '{!Account.Id}' and StageName <>'Speculative Lead' and StageName <>'Cancelled' and StageName <>'Lost' ", layoutOpps); // more can be added here // add activities on an account ( AccountId is set) } // for a case if ( validId("{!Case.Id}") ) { // we are on a case page, this gets interesting... // query the case history and display that sforce.connection.query( "Select c.OldValue, c.NewValue, c.IsDeleted, c.Id, c.Field, c.CreatedDate, c.CreatedBy.FirstName, c.CreatedBy.LastName, c.CreatedById, c.CaseId From CaseHistory c"+ " where c.CaseId = '{!Case.Id}' order by CreatedDate ", layoutCaseHist ); // case comments sforce.connection.query( "Select c.ParentId, c.LastModifiedDate, c.LastModifiedById, c.IsPublished, c.IsDeleted, c.Id, c.CreatedDate, c.CreatedBy.FirstName, c.CreatedBy.LastName, c.CreatedById, c.CommentBody From CaseComment c " + " where ParentId = '{!Case.Id}' order by CreatedDate ", layoutCaseComment ); } // end case } /* * layout callbacks, gets a list of query results, formats a timeline entry and bubble contents * when constructing data.events array of objects to add via loadJSON, the following are available * * { start: end: title: link: 'parent:link...' latestStart: null, earliestEnd: null, isDuration: false, description: image: img, icon: img, color: "#999", textColor: null, onclick: "javascript:..." } Note, for IE and IE7 the last data element must not have a comma following it */ function layoutCaseHist(qr) { var formatDesc = function (rec) { if (rec.Field == 'created' ) { return 'the case was created <br>by '+rec.CreatedBy.FirstName + ' '+ rec.CreatedBy.LastName + ' on ' ; } else { return 'the field '+rec.Field+ '<br>was changed to ' + (rec.NewValue?rec.NewValue:'') + '<br>by '+rec.CreatedBy.FirstName + ' '+ rec.CreatedBy.LastName + ' on ' } }; loadJSON ( map ( qr.getArray('records'), function(rec,idx,ary) { return { start: rec.getDateTime('CreatedDate'), title: rec.Field + ' ' + (rec.NewValue?rec.NewValue:''), description: formatDesc(rec), image: "/img/icon/cases16.gif", icon: "/img/icon/cases16.gif", color: "#999" } } ) ); } function layoutCaseComment (qr ) { loadJSON ( map ( qr.getArray('records'), function(rec,idx,ary) { return { start: rec.getDateTime('CreatedDate'), title: 'Comment by ' + rec.CreatedBy.FirstName + ' ' + rec.CreatedBy.LastName, description: (rec.IsPublished?'Public ':'Private ') + '<br>'+ rec.CommentBody.substr(0,64), image:"/img/icon/documents16.gif", icon: "/img/icon/documents16.gif", color: "#999" } } ) ); } // layout helper routines for various objects function layoutOpps(qr) { loadJSON ( map ( qr.getArray('records'), function(rec,idx,ary) { return { start: rec.getDate('Operation_Start_Date__c'), title: rec.Name + ', ' + rec.StageName + ', ' + rec.Amount, link: 'parent:/' + rec.Id, description: rec.Name + ' currently at stage '+rec.StageName+ ', '+ (rec.NextStep?rec.NextStep:'')+' and is expected to close on ', image: "/img/icon/opportunities16.gif", icon: "/img/icon/opportunities16.gif", color: "#777" }; } ) ); } function layoutOppHistory(qr) { loadJSON ( map ( qr.getArray('records'), function(rec,idx,ary) { return { start: rec.getDateTime('CreatedDate'), title: rec.StageName + ', ' + rec.Amount, description: '' , image: "/img/icon/opportunities16.gif", icon: "/img/icon/opportunities16.gif", color: "#999" }; } ) ); } function layoutTasks(qr) { layoutActivity(qr, "/img/icon/tasks16.png"); } function layoutEvents(qr) { layoutActivity(qr, "/img/icon/calendar16.png"); } function layoutTasksWhat(qr) { layoutActivityWhat(qr, "/img/icon/tasks16.png"); } function layoutEventsWhat(qr) { layoutActivityWhat(qr, "/img/icon/calendar16.png"); } // activities may have duplicates on an account for example, keep a list to avoid var seen = []; // this callback loads tasks into the timeline function layoutActivityWhat(qr,img) { loadJSON ( map ( qr.getArray('records'), function(rec,idx,ary) { if ( seen[rec.Id] ) { return null; } else { seen[rec.Id] = rec.Id;} var stdate = rec.getDate('ActivityDate'); if (!stdate) { stdate = rec.getDateTime('CreatedDate'); } return { start: stdate, title: rec.Subject + (rec.What && rec.What.Name ? ', '+rec.What.Name : ''), link: 'parent:/' + rec.Id, description: 'description: ' + (rec.Description ? rec.Description:'') + (rec.Who && rec.Who.FirstName && rec.Who.LastName ? '<br>contact: ' + rec.Who.FirstName + ' '+rec.Who.LastName : '') + "<br>assigned to: " + rec.Owner.FirstName + " " + rec.Owner.LastName, image: img, icon: img, color: "#999" } } ) ); } // this callback loads tasks into the timeline function layoutActivity(qr,img) { loadJSON ( map ( qr.getArray('records'), function(rec,idx,ary) { if ( seen[rec.Id] ) { return null; } else { seen[rec.Id] = rec.Id;} var stdate = rec.getDate('ActivityDate'); if (!stdate) { stdate = rec.getDateTime('CreatedDate'); } return { start: stdate, title: rec.Subject + (rec.Who && rec.Who.FirstName && rec.Who.LastName ? ', '+rec.Who.FirstName + ' '+rec.Who.LastName : ''), link: 'parent:/' + rec.Id, description: 'description: ' + (rec.Description ? rec.Description:'') + (rec.Who && rec.Who.FirstName && rec.Who.LastName ? '<br>contact: ' + rec.Who.FirstName + ' '+rec.Who.LastName : '') + "<br>assigned to: " + rec.Owner.FirstName + " " + rec.Owner.LastName, image: img, icon: img, color: "#999" }; } ) ); } // some helper functions // take an array of events, load them into a data object and pass to loadJSON function loadJSON (events) { if (!events || events.length <1) return; var data = {}; data.events = events; eventSource.loadJSON(data,baseURL); // eventSource is part of the Timeline API } // call a function on each member of the array, return an array // of the results of the callbacks function map(anArray /* Array */, callback /* Function */){ var outArr = []; for(var i=0,l=anArray.length; i<l; i++){ var topush = callback(anArray[i], i, anArray); if (topush != null) { outArr.push( topush ); } } return outArr; } /*********************** * function onResize() * If the page is resized, the timeline is resized to match * this waits for resize to finish 1/2 second */ var resizeTimerID = null; function onResize() { if (resizeTimerID == null) { resizeTimerID = window.setTimeout( function() { resizeTimerID = null; theTimeLine.layout();}, 500 ); } } </script> <!-- main functions --> </head> <body onload="javascript:initPage();" onresize="javascript:onResize();" > <div id="my-timeline" style="height:300px; border: 1px solid #aaa"></div> </body> </html>

 

zeezackisbackzeezackisback

Sorry guys -

 

I got a problem with this timeline. its not displaying ANY data at all on any field.

 

 

I am trying to get it working on a custom field but with no luck

 

 

 

// for a claim if ( validId("{!Claim__c.Id}") ) { // we are on a case page, this gets interesting... // query the claim history and display that sforce.connection.query( "Select OldValue, NewValue, IsDeleted, Id, Field, CreatedDate, Claim__r.CreatedBy.FirstName, Claim__r.CreatedBy.LastName, CreatedById, Id From Claim__History"+ " where Id= '{!Claim__c.Id}' order by CreatedDate ", layoutCaseHist ); } // end case

 

 Code as it is

 

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Timeline</title> <link href="/dCSS/Theme2/default/common.css" type="text/css" media="handheld,print,projection,screen,tty,tv" rel="stylesheet" > <!-- Include the MIT timeline library and CSS--> {!INCLUDE($SControl.Timeline_CSS)} {!INCLUDE($SControl.Timeline_mit_lib)} <!-- Apex AJAX connection library change--> <script src="/soap/ajax/8.0/connection.js" type="text/javascript"></script> <script type="text/javascript"> var theTimeLine; var eventSource; var baseURL = window.location.protocol + '//' + window.location.hostname; var isOpportunity = new Boolean("{!$Request.eid}" == "{!Opportunity.Id}"); var isContact = new Boolean("{!$Request.eid}" == "{!Contact.Id}"); var isAccount = new Boolean( "{!$Request.eid}" == "{!Account.Id}"); var isCase = new Boolean( "{!$Request.eid}" == "{!Case.Id}" ); var isClaim = new Boolean( "{!$Request.eid}" == "{!Claim__c.Id}" ); // see what tab we are called from function validId(id) { return ("{!$Request.eid}" != null && "{!$Request.eid}" != "" && "{!$Request.eid}" === id); } var hasActivities = new Boolean( isOpportunity == true || isCase == true || isAccount == true || isClaim == true ); function _WhatId() { if (isOpportunity == true) return "{!Opportunity.Id}"; if (isCase == true) return "{!Case.Id}"; if (isAccount == true) return "{!Account.Id}"; if (isClaim == true) return "{!Claim__c.Id}"; return null; } var WhatId = _WhatId(); /************************** * load the timeline UI, then query for events to add * all the events are added async to give a quicker load */ function initPage() { //build the timeline widget eventSource = new Timeline.DefaultEventSource(); var theme = Timeline.ClassicTheme.create(); theme.event.label.width = 300; // px this will truncate the labels that appear on the timline //theme.event.bubble.width = 250; //theme.event.bubble.height = 200; theme.ether.backgroundColors.unshift("#f3f3ec"); // set up the bands of info in the display var bandInfos = [ Timeline.createBandInfo({ eventSource: eventSource, date: Date(), width: "80%", intervalUnit: Timeline.DateTime.MONTH, intervalPixels: 100, theme: theme }), Timeline.createBandInfo({ showEventText: false, trackHeight: 0.5, trackGap: 0.2, eventSource: eventSource, date: Date(), width: "20%", intervalUnit: Timeline.DateTime.YEAR, intervalPixels: 200 }) ]; bandInfos[1].syncWith = 0; bandInfos[1].highlight = true; theTimeLine = Timeline.create(document.getElementById("my-timeline"), bandInfos); /************* * begin DATA queries * each query kicks off an async callback to plot/load the results, does not wait for all before drawing. * more can be added to support custom objects, to support custom objects, test for merge fields * decide what related records have dates, and create a layout callback for each. * this can also be used to support one scontrol on many different object page layouts * so, contact, opportunity, account or case can all run from this one scontrol * we do assume it is an inline scontrol */ if ( hasActivities == true && WhatId != null ) { //get all tasks related to this object ( must have a WhatId) sforce.connection.query( "Select Id,Subject,Status,ActivityDate,Description,CreatedDate,Owner.FirstName,Owner.LastName, Who.FirstName, Who.LastName from Task where WhatId='"+ WhatId +"'", layoutTasks); // events sforce.connection.query( "Select Id, Subject, Location, ActivityDateTime,ActivityDate, IsAllDayEvent, DurationInMinutes, Description, Owner.FirstName,Owner.LastName, Who.FirstName, Who.LastName from Event where WhatId='"+ WhatId + "' order by ActivityDate", layoutEvents); } // opportunity stage history if we are on an opp if ( validId( "{!Opportunity.Id}" ) ) { sforce.connection.query("Select CreatedById, CreatedDate, StageName, Amount, CloseDate from OpportunityHistory where OpportunityId ='{!Opportunity.Id}'", layoutOppHistory); } // more can be added, these will find activities on the contact record // simular code can be added for Lead if ( validId("{!Contact.Id}") ) { // tasks sforce.connection.query( "Select Id,Name,LastActivityDate,Description,CreatedDate, FirstName,LastName from Contact where Id='{!Contact.Id}'", layoutTasksWhat); // events sforce.connection.query( "Select Id, Subject, Location, ActivityDateTime,ActivityDate, IsAllDayEvent, DurationInMinutes, Description, Owner.FirstName,Owner.LastName, Who.FirstName, Who.LastName , What.Name from Contact where WhatId='{!Contact.Id}' order by LastActivityDate", layoutEventsWhat); } if ( validId("{!Account.Id}") ) { // we are on an account page, so show opportunities sforce.connection.query( "Select Id, Name, StageName, Amount, CloseDate, IsWon, IsClosed , NextStep from Opportunity where AccountId = '{!Account.Id}'", layoutOpps); // more can be added here // add activities on an account ( AccountId is set) sforce.connection.query( "Select Id,Subject,Status,ActivityDate,Description,CreatedDate, Owner.FirstName,Owner.LastName, Who.FirstName, Who.LastName, What.Name from Task where AccountId ='{!Account.Id}'", layoutTasks); // events sforce.connection.query( "Select Id, Subject, Location, ActivityDateTime,ActivityDate, IsAllDayEvent, DurationInMinutes, Description, Owner.FirstName,Owner.LastName, Who.FirstName, Who.LastName , What.Name from Event where WhatId='{!Account.Id}' order by ActivityDate", layoutEvents); } // for a case if ( validId("{!Case.Id}") ) { // we are on a case page, this gets interesting... // query the case history and display that sforce.connection.query( "Select OldValue, NewValue, IsDeleted, Id, Field, CreatedDate, c.CreatedBy.FirstName, c.CreatedBy.LastName, c.CreatedById, c.CaseId From CaseHistory "+ " where c.CaseId = '{!Case.Id}' order by CreatedDate ", layoutCaseHist ); // case comments sforce.connection.query( "Select c.ParentId, c.LastModifiedDate, c.LastModifiedById, c.IsPublished, c.IsDeleted, c.Id, c.CreatedDate, c.CreatedBy.FirstName, c.CreatedBy.LastName, c.CreatedById, c.CommentBody From CaseComment c " + " where ParentId = '{!Case.Id}' order by CreatedDate ", layoutCaseComment ); } // end case // for a claim if ( validId("{!Claim__c.Id}") ) { // we are on a case page, this gets interesting... // query the claim history and display that sforce.connection.query( "Select OldValue, NewValue, IsDeleted, Id, Field, CreatedDate, Claim__r.CreatedBy.FirstName, Claim__r.CreatedBy.LastName, CreatedById, Id From Claim__History"+ " where Id= '{!Claim__c.Id}' order by CreatedDate ", layoutCaseHist ); } // end case } /* * layout callbacks, gets a list of query results, formats a timeline entry and bubble contents * when constructing data.events array of objects to add via loadJSON, the following are available * * { start: end: title: link: 'parent:link...' latestStart: null, earliestEnd: null, isDuration: false, description: image: img, icon: img, color: "#999", textColor: null, onclick: "javascript:..." } Note, for IE and IE7 the last data element must not have a comma following it */ function layoutCaseHist(qr) { var formatDesc = function (rec) { if (rec.Field == 'created' ) { return 'the case was created <br>by '+rec.CreatedBy.FirstName + ' '+ rec.CreatedBy.LastName + ' on ' ; } else { return 'the field '+rec.Field+ '<br>was changed to ' + (rec.NewValue?rec.NewValue:'') + '<br>by '+rec.CreatedBy.FirstName + ' '+ rec.CreatedBy.LastName + ' on ' } }; loadJSON ( map ( qr.getArray('records'), function(rec,idx,ary) { return { start: rec.getDateTime('CreatedDate'), title: rec.Field + ' ' + (rec.NewValue?rec.NewValue:''), description: formatDesc(rec), image: "/img/icon/cases16.gif", icon: "/img/icon/cases16.gif", color: "#999" } } ) ); } function layoutCaseComment (qr ) { loadJSON ( map ( qr.getArray('records'), function(rec,idx,ary) { return { start: rec.getDateTime('CreatedDate'), title: 'Comment by ' + rec.CreatedBy.FirstName + ' ' + rec.CreatedBy.LastName, description: (rec.IsPublished?'Public ':'Private ') + '<br>'+ rec.CommentBody.substr(0,64), image:"/img/icon/documents16.gif", icon: "/img/icon/documents16.gif", color: "#999" } } ) ); } // layout helper routines for various objects function layoutOpps(qr) { loadJSON ( map ( qr.getArray('records'), function(rec,idx,ary) { return { start: rec.getDate('CloseDate'), title: rec.Name + ', ' + rec.StageName + ', ' + rec.Amount, link: 'parent:/' + rec.Id, description: rec.Name + ' currently at stage '+rec.StageName+ ', '+ (rec.NextStep?rec.NextStep:'')+' and is expected to close on ', image: "/img/icon/opportunities16.gif", icon: "/img/icon/opportunities16.gif", color: "#999" }; } ) ); } function layoutOppHistory(qr) { loadJSON ( map ( qr.getArray('records'), function(rec,idx,ary) { return { start: rec.getDateTime('CreatedDate'), title: rec.StageName + ', ' + rec.Amount, description: '' , image: "/img/icon/opportunities16.gif", icon: "/img/icon/opportunities16.gif", color: "#999" }; } ) ); } function layoutTasks(qr) { layoutActivity(qr, "/img/icon/tasks16.png"); } function layoutEvents(qr) { layoutActivity(qr, "/img/icon/calendar16.png"); } function layoutTasksWhat(qr) { layoutActivityWhat(qr, "/img/icon/tasks16.png"); } function layoutEventsWhat(qr) { layoutActivityWhat(qr, "/img/icon/calendar16.png"); } // activities may have duplicates on an account for example, keep a list to avoid var seen = []; // this callback loads tasks into the timeline function layoutActivityWhat(qr,img) { loadJSON ( map ( qr.getArray('records'), function(rec,idx,ary) { if ( seen[rec.Id] ) { return null; } else { seen[rec.Id] = rec.Id;} var stdate = rec.getDate('ActivityDate'); if (!stdate) { stdate = rec.getDateTime('CreatedDate'); } return { start: stdate, title: rec.Subject + (rec.What && rec.What.Name ? ', '+rec.What.Name : ''), link: 'parent:/' + rec.Id, description: 'description: ' + (rec.Description ? rec.Description:'') + (FirstName && LastName ? '<br>contact: ' + FirstName + ' '+LastName : '') + "<br>assigned to: " + FirstName + " " + LastName, image: img, icon: img, color: "#999" } } ) ); } // this callback loads tasks into the timeline function layoutActivity(qr,img) { loadJSON ( map ( qr.getArray('records'), function(rec,idx,ary) { if ( seen[rec.Id] ) { return null; } else { seen[rec.Id] = rec.Id;} var stdate = rec.getDate('ActivityDate'); if (!stdate) { stdate = rec.getDateTime('CreatedDate'); } return { start: stdate, title: rec.Subject + (rec.Who && rec.Who.FirstName && rec.Who.LastName ? ', '+rec.Who.FirstName + ' '+rec.Who.LastName : ''), link: 'parent:/' + rec.Id, description: 'description: ' + (rec.Description ? rec.Description:'') + (rec.Who && rec.Who.FirstName && rec.Who.LastName ? '<br>contact: ' + rec.Who.FirstName + ' '+rec.Who.LastName : '') + "<br>assigned to: " + rec.Owner.FirstName + " " + rec.Owner.LastName, image: img, icon: img, color: "#999" }; } ) ); } // some helper functions // take an array of events, load them into a data object and pass to loadJSON function loadJSON (events) { if (!events || events.length <1) return; var data = {}; data.events = events; eventSource.loadJSON(data,baseURL); // eventSource is part of the Timeline API } // call a function on each member of the array, return an array // of the results of the callbacks function map(anArray /* Array */, callback /* Function */){ var outArr = []; for(var i=0,l=anArray.length; i<l; i++){ var topush = callback(anArray[i], i, anArray); if (topush != null) { outArr.push( topush ); } } return outArr; } /*********************** * function onResize() * If the page is resized, the timeline is resized to match * this waits for resize to finish 1/2 second */ var resizeTimerID = null; function onResize() { if (resizeTimerID == null) { resizeTimerID = window.setTimeout( function() { resizeTimerID = null; theTimeLine.layout();}, 500 ); } } </script> <!-- main functions --> </head> <body onload="javascript:initPage();" onresize="javascript:onResize();" > <div id="my-timeline" style="height:300px; border: 1px solid #aaa"></div> </body> </html>

 

 

 

 

zeezackisbackzeezackisback
ERROR: ........... {faultcode:'sf:INVALID_FIELD', faultstring:'INVALID_FIELD: IsDeleted, Id, Field, CreatedDate, Claim__r.CreatedBy.FirstName, Claim__r.CreatedBy.LastName ^ ERROR at Row:1:Column:63 Didn't understand relationship 'Claim__r' in field path. If you are attempting to use a custom relationship, be sure to append the '__r' after the custom relationship name. Please reference your WSDL or the describe call for the appropriate names.', detail:{fault:{exceptionCode:'INVALID_FIELD', exceptionMessage:' IsDeleted, Id, Field, CreatedDate, Claim__r.CreatedBy.FirstName, Claim__r.CreatedBy.LastName ^ ERROR at Row:1:Column:63 Didn't understand relationship 'Claim__r' in field path. If you are attempting to use a custom relationship, be sure to append the '__r' after the custom relationship name. Please reference your WSDL or the describe call for the appropriate names.', row:'1', column:'63', }, }, }
This was selected as the best answer