PDA

View Full Version : [2.2] Voting component Sample



xingo
24 Oct 2008, 7:20 AM
Hello list,

I am currently learning EXT and i have been stumbeling on some different problems.
So Here is a small sample i made that should run as is and that shows them.
The idea is a small 'live' voting system where you can vote for a candidate and see live updates from an (absent here) back end system.

I would like to refactor this example to best fit EXT way of doing things.

First of all, the code.
the file have paths set to go in examples/somefolder.



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Demo Vote For The Best</title>

<link rel='StyleSheet' href='./../../resources/css/ext-all.css' />
<script type="text/javascript" src="./../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="./../../ext-all-debug.js"></script>

<!-- Common Styles for the examples -->
<link rel='StyleSheet' href='./../../examples/shared/examples.css' />

<style type="text/css">
#recap_ss_bloc {
display:none;
}

.sousbloc {
float: left;
width: 124px !important;width: 130px;
/*height: 80px;*/
border: 1px solid black;
margin-left: 1px;
margin-top: 2px;
margin-bottom: 5px;
text-align: center;
}

.linessbloc {
background-color: #66cc66; /* marron rouge */
color: #ffffff;
height: 15px;
text-align:center;
font-size:14px;
font-weight: bold;
padding-bottom:2px;
}

.growing {
overflow:hidden;
width:15px;
height:15px;
background:transparent url(./../../resources/images/default/panel/tool-sprites.gif) no-repeat;
background-position:0 -209px;
}

.shrinking {
overflow:hidden;
width:15px;
height:15px;
background:transparent url(./../../resources/images/default/panel/tool-sprites.gif) no-repeat;
background-position:0 -194px;
}

.stable {
overflow:hidden;
width:15px;
height:14px;
background:transparent url(./../../resources/images/default/panel/tool-sprites.gif) no-repeat;
background-position:0 -254px;
}

.rightnum { text-align:right; }
.bignumber { font-weight:bolder; }
.smallerbk { color:black; font-size:smaller; }

.growingcolor { color : green; }
.shrinkingcolor { color : red; }
.stablecolor { color : blue; }

.buttonS {
font-weight: bold;
color:red;
margin: 0;
border: 0;
background-color:#ffffff;
border: 1px solid black;
/*text-indent:40px;*/
width:40px;
height:40px;
overflow: hidden;
cursor: pointer;
}

.buttonB {
font-weight: bold;
color:green;
margin: 0;
border: 0;
background-color:#ffffff;
border: 1px solid black;
/*text-indent:40px;*/
width:40px;
height:40px;
overflow: hidden;
cursor: pointer;
}

.trangleblanc {
background : url("./img/ico_steady.gif") no-repeat 0px 4px;
padding-left:7px;
padding-right:8px;
width:15px;
}
</style>

<script type="text/javascript">
/**
* Application Layout
* Modify from Application Layout by Jozef Sakalos, aka Saki to fit voting system
* Xingo
*/

// reference local blank image
Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';

// Just to allow this tutorial to work for 1.1 and 2.
Ext.Ext2 = (Ext.version && (Ext.version.indexOf("2") == 0));

// create namespace
Ext.namespace('voteDemo', 'voteDemo.data.record', 'voteDemo.data.store');

/**
* voteDemo.data.record.participant
* on init we only have the following data
* { starID: "2", starName: "OBAMA", displayed: "1" }
* on updateVotes we get the following data :
* { "starName", "thumbsUp", "thumbsDown" }
*/
voteDemo.data.record.participant = Ext.data.Record.create([
{name:'starID', type:'int' },
{name:'starName', type:'string' },
{name:'displayed', type:'boolean' },
{name:'thumbsUp', type:'int', defaultValue:0 },
{name:'thumbsDown', type:'int', defaultValue:0 },
{name:'ratio', type:'float', defaultValue:0.0 },
{name:'nbVotes', type:'string', defaultValue:'1' },
{name:'style1', type:'string', defaultValue:'stablecolor' },
{name:'style2', type:'string', defaultValue:'stable' }
]);

// Not sure this is the right way but it seems to work.
// any advices on how to do that more 'regulat ext way' ?
Ext.apply(voteDemo.data.record.participant.prototype, {
// Update a record with dynamic info from system
updateVotes:function(voteData)
{
this.beginEdit();
var lasRatio = this.get('ratio');
this.set('thumbsUp', parseInt(voteData.thumbsUp));
this.set('thumbsDown', parseInt(voteData.thumbsDown));
var ratio = 0;
if(this.get('thumbsUp')+this.get('thumbsDown')!=0.0)
{
ratio = 100*this.get('thumbsUp')/(this.get('thumbsUp')+this.get('thumbsDown'));
this.set('ratio', ratio);
if(ratio>lasRatio) {
this.set('style1', 'growingcolor bignumber');
this.set('style2', 'growing');
} else if(ratio < lasRatio) {
this.set('style1', 'shrinkingcolor bignumber');
this.set('style2', 'shrinking');
} else {
this.set('style1', 'stablecolor bignumber');
this.set('style2', 'stable');
}
}
// it brakes here !!!
// this.endEdit();
// or here !!!
// this.commit();
} // eo function updateVotes
}); // eo extend

// I can't figure out how to derive properly from Ext.data.JsonStore
// So this is how i do it...
voteDemo.data.store.instrument = function(store_data)
{
var data_store = new Ext.data.JsonStore({
data: store_data,
root: 'candidates',
fields: voteDemo.data.record.participant,

// extra functions for our store
participants: null,
lastcall: new Date().getTime(),
setupParticipant: function()
{
this.participants = new Array();
this.each( function(record){ this.participants.push(record.get('starName')); return true;}, this )
},
getParticipant: function(starName)
{
var idx = this.participants.indexOf(starName);
// console.log('index for '+starName+'='+idx);
if(idx>=0)
return this.getAt(idx);
return null;
},
updateVotes: function(voteData)
{
var record = this.getParticipant(voteData.starName);
if(record)
{
// console.log(typeof record+' -> '+record.id);
record.updateVotes(voteData);
}
return this.participants.indexOf(voteData.starName);
}
});
data_store.setupParticipant();
return data_store;
}


voteDataView = function()
{
var data_store = null; // Private Variable for the module. Not accessible from outside
var data_view = null;
var data_panel = null;

var tpl = new Ext.XTemplate(
'<tpl for=".">',
'<div id="recap_ss_bloc" {[values.displayed ? "style=\'display:block\'" : ""]}>',
'<div class="sousbloc">',
'<div nowrap="nowrap" class="linessbloc"><span class="x-tool x-tool-gear" style="float:left;" id="{starName}_MENU"></span>&nbsp;{starName}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="{style2}" id="{starID}_CHANGE">&nbsp;&nbsp;&nbsp;&nbsp;</span></div>',
'<b><div id="{starName}_POPULAR">{[this.getPopularity(values)]}</div></b>',
'<button class="buttonB" type="button" id="{starName}_UP">',
'<div><span id="{starName}_UP_VAL" class="{style1}">{thumbsUp}</span></div>',
'<span class="smallerbk">Up</span>',
'</button>',
'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
'<button class="buttonS" type="button" id="{starName}_DOWN">',
'<div><span id="{starName}_DOWN_VAL" class="{style1}">{thumbsDown}</span></div>',
'<span class="smallerbk">Down</span>',
'</button>',
'<br/><br/>',
'<div class="montant">',
'<input type="text" size="2" maxlength="2" id="{starName}_VOTES" class="rightnum" value="{nbVotes}">&nbsp;<label class="smallerbk">Vote</label>',
'</div><br/>',
'</div>',
'</div>',
'</tpl>',
'<div class="x-clear"></div>',
{
getPopularity: function(values)
{
if(values.thumbsUp+values.thumbsDown==0) return '??';
if (values.thumbsUp == values.thumbsDown) return '--';
var ratio = (100*values.thumbsUp)/(values.thumbsUp+values.thumbsDown);
// console.log("%f,%f,%f,%f,%f", ratio,values.thumbsUp,values.thumbsDown,(values.thumbsUp+values.thumbsDown),(values.thumbsUp)/(values.thumbsUp+values.thumbsDown));
return Math.round(ratio);
}
}
);

return {
init : function(store_data, where){
// Here comes the initialisation code
data_store = new voteDemo.data.store.instrument(store_data);
data_view = new Ext.DataView({
store: data_store,
tpl: tpl,
autoHeight: true,
multiSelect: true,
overClass: 'x-view-over',
itemSelector: 'div.recap_ss_bloc',
emptyText: 'No images to display'
});
data_panel = new Ext.Panel({
id: 'images-view',
frame: true,
width: 560,
autoHeight: true,
collapsible: true,
layout: 'fit',
title: 'Vote for the Bests',
items: data_view,
tools: [{
id:'close',
handler:function(event, toolEl, panel) { Ext.Msg.alert('Message', 'The Close tool was clicked.'); }
},
{
id:'gear',
handler:function(event, toolEl, panel) { Ext.Msg.alert('Message', 'The Settings tool was clicked.'); }
}
]
});
data_panel.render(where);
// this.initEvents();
},
initEvents : function(){
console.log('initEvents');
data_store.each(
function(record)
{
var starName = record.get('starName'); console.log(starName);
Ext.get(starName+"_MENU").on('click', function() { Ext.Msg.alert('Message', 'menu on '+starName+'.'); });
Ext.get(starName+"_UP").on('click', function() { Ext.Msg.alert('Message', 'Vote Up for '+starName+'.'); });
Ext.get(starName+"_DOWN").on('click', function() { Ext.Msg.alert('Message', 'Vote Down for '+starName+'.'); });
return true;
}, this
);
},
updateVotes : function(voteData){
var nodeidx = data_store.updateVotes(voteData);
data_view.refresh();
// data_view.refreshNode(nodeidx);
},
getParticipant : function(starName){
return data_store.getParticipant(starName);
}
}
}();

// create application
voteDemo.app = function()
{
// do NOT access DOM from here; elements don't exist yet

// private variables
var data_view = null;

// public space
return {
// public properties, e.g. strings to translate

// public methods
init: function() {
data_view = voteDataView;
data_view.init(candidates, 'view-votes');
fireVotes();
},
queueUpdate: function(voteData, when) {
data_view.updateVotes.defer(when, data_view, [voteData]);
}
};
}(); // end of app
</script>
<script type="text/javascript">
var host = 'localhost';

// Static data to start with
var candidates = { 'results' : 4, 'candidates' : [
{starID: "2", starName: "Obama", factor: "0", displayed: "1"},
{starID: "3", starName: "McCain", factor: "0", displayed: "1"},
{starID: "4", starName: "McKinney", factor: "0", displayed: "0"},
{starID: "1", starName: "Baldwin", factor: "0", displayed: "0"},
{starID: "5", starName: "Moore", factor: "0", displayed: "1"},
{starID: "6", starName: "Calero", factor: "0", displayed: "0"},
{starID: "7", starName: "Barr", factor: "0", displayed: "0"},
{starID: "8", starName: "Nader", factor: "0", displayed: "0"},
{starID: "9", starName: "Keyes", factor: "0", displayed: "1"}
]};
</script>
<!-- A Localization Script File comes here -->

<!-- onReady app init goes here -->
<script type="text/javascript">
Ext.onReady(voteDemo.app.init, voteDemo.app);
</script>
</head>
<body>
<div id="view-votes"></div>

<script type="text/javascript">

function RenderVoteMessage(vote, when)
{
voteDemo.app.queueUpdate(vote, 1000*when);
}

function fireVotes()
{
try{RenderVoteMessage({starName: "Obama", thumbsUp: '100', thumbsDown: '70'}, 1);}catch(e){}
try{RenderVoteMessage({starName: "McCain", thumbsUp: '100', thumbsDown: '70'}, 1);}catch(e){}
try{RenderVoteMessage({starName: "Moore", thumbsUp: '10', thumbsDown: '10'}, 1);}catch(e){}
try{RenderVoteMessage({starName: "Keyes", thumbsUp: '8', thumbsDown: '9' }, 1);}catch(e){}
try{RenderVoteMessage({starName: "Baldwin", thumbsUp: '9', thumbsDown: '8' }, 1);}catch(e){}
try{RenderVoteMessage({starName: "Obama", thumbsUp: '110', thumbsDown: '75'}, 2);}catch(e){}
try{RenderVoteMessage({starName: "Moore", thumbsUp: '12', thumbsDown: '10'}, 3);}catch(e){}
try{RenderVoteMessage({starName: "McCain", thumbsUp: '102', thumbsDown: '75'}, 4);}catch(e){}
try{RenderVoteMessage({starName: "Obama", thumbsUp: '120', thumbsDown: '95'}, 5);}catch(e){}
try{RenderVoteMessage({starName: "Obama", thumbsUp: '120', thumbsDown: '95'}, 5);}catch(e){}
try{RenderVoteMessage({starName: "McCain", thumbsUp: '110', thumbsDown: '115'}, 6);}catch(e){}
}

</script>
</body>
</html>
<!-- eof -->
Ok, now the issues i have.
is the Ext.apply(voteDemo.data.record.participant.prototype, ... the correct way to extend the record, or is there any prefered approach.
Trying to extend Ext.data.JsonStore through Ext.extend(Ext.data.JsonStore, {... was not working so i ended up with the function solution. I would prefer a extended class that i can then use and call loadData.
using endEdit and/or commit in updateVotes always result in a javascript error (d is undefined, http://localhost/extjs/ext-2.2/ext-all-debug.js, Line 5161)
I end up using endEdit.defer(1); commit.defer(1); !!! but i still have to refresh() the dataView to get my modifications rendered.
After the dataView.Refresh() the events placed in initEvents are not active anymore.
I could not manage to have dataView.refreshNode() working.
I designed the widget starting with a vue element from cakePHP, and basically transformed the php view to an XTemplate. I wanted to make a 'component' from this XTemplate but i have to say that i'm not clear on where to start. Component, BoxComponent, Panel ???.Well i guess enought for a first run.
I would like to turn it in a real example of a widget from scratch (actualy from a visual existing raw html widget)

As an asside question, is it prefered here to have inlined code or folder structure in attachement ?

Suggestions and improvements are welcome.

galdaka
24 Oct 2008, 7:54 AM
Any live example or screenshot?

Thanks in advance,

xingo
24 Oct 2008, 8:09 AM
Any live example or screenshot?

Thanks in advance,

Live example with the source, screenshots added.

mjlecomte
24 Oct 2008, 11:17 AM
In my experience, if you post in examples and extra forum, all you will get are people looking for handouts and you really won't get any help (as you've seen so far).

If you want help, usually posting a laundry list of problems won't get you too far either. You're better off asking specific questions about specific problems. You should post small code snippets about each problem. Most of the helpers around here don't want to be bothered to download your files and sift through them, etc. You should be able to post a small example code that illustrates your problem.

JMO.

xingo
24 Oct 2008, 12:52 PM
In my experience, if you post in examples and extra forum, all you will get are people looking for handouts and you really won't get any help (as you've seen so far).

If you want help, usually posting a laundry list of problems won't get you too far either. You're better off asking specific questions about specific problems. You should post small code snippets about each problem. Most of the helpers around here don't want to be bothered to download your files and sift through them, etc. You should be able to post a small example code that illustrates your problem.

JMO.

Thank's for the advice.
I will then post some specific question on Ext Help and report here to complete the sample.