3 * Copyright(c) 2006-2010 Sencha Inc.
5 * http://www.sencha.com/license
9 Ext.ux.Rating = Ext.extend(Ext.util.Observable, {
10 // Configuration options
18 // Our class constructor
19 constructor : function(element, config) {
20 Ext.apply(this, config);
21 Ext.ux.Rating.superclass.constructor.call(this);
28 this.el = Ext.get(element);
35 // Some arrays we are going to store data in
40 // We create a container to put all our stars into
41 this.container = this.el.createChild({
42 cls: 'ux-rating-container ux-rating-clearfix'
46 this.resetEl = this.container.createChild({
47 cls: 'ux-rating-reset',
50 title: this.showTitles ? (this.resetTitle || 'Reset your vote') : '',
54 this.resetEl.visibilityMode = Ext.Element.DISPLAY;
56 this.resetEl.hover(function() {
57 Ext.fly(this).addClass('ux-rating-reset-hover');
59 Ext.fly(this).removeClass('ux-rating-reset-hover');
62 this.resetEl.on('click', this.reset, this);
65 // We use DomQuery to select the radio buttons
66 this.radioBoxes = this.el.select('input[type=radio]');
67 // Then we can loop over the CompositeElement using each
68 this.radioBoxes.each(this.initStar, this);
70 // We use DomHelper to create our hidden input
71 this.input = this.container.createChild({
75 value: this.values[this.defaultSelected] || this.resetValue
78 // Lets remove all the radio buttons from the DOM
79 this.radioBoxes.remove();
81 this.select(this.defaultSelected === undefined ? false : this.defaultSelected)
86 // Enable will set up our event listeners
91 initStar : function(item, all, i) {
92 var sw = Math.floor(this.starWidth / this.split);
94 // We use the name and disabled attributes of the first radio button
96 this.name = item.dom.name;
97 this.disabled = item.dom.disabled;
100 // Saving the value and title for this star
101 this.values[i] = item.dom.value;
102 this.titles[i] = item.dom.title;
104 if(item.dom.checked) {
105 this.defaultSelected = i;
108 // Now actually create the star!
109 var star = this.container.createChild({
110 cls: 'ux-rating-star'
113 var starLink = star.createChild({
115 html: this.values[i],
116 title: this.showTitles ? this.titles[i] : ''
119 // Prepare division settings
121 var odd = (i % this.split);
123 starLink.setStyle('margin-left', '-' + (odd * sw) + 'px');
126 // Save the reference to this star so we can easily access it later
127 this.stars.push(star.dom);
130 onStarClick : function(ev, t) {
132 this.select(this.stars.indexOf(t));
136 onStarOver : function(ev, t) {
138 this.fillTo(this.stars.indexOf(t), true);
142 onStarOut : function(ev, t) {
144 this.fillTo(this.selected, false);
148 reset : function(ev, t) {
152 select : function(index) {
153 if(index === false || index === -1) {
154 // remove current selection in el
155 this.value = this.resetValue;
157 this.input.dom.value = '';
160 this.resetEl.setOpacity(0.5);
165 if(this.selected !== -1) {
166 this.fireEvent('change', this, this.values[index], this.stars[index]);
170 else if(index !== this.selected) {
171 // Update some properties
172 this.selected = index;
173 this.value = this.values[index];
174 this.title = this.titles[index];
176 // Set the value of our hidden input so the rating can be submitted
177 this.input.dom.value = this.value;
180 this.resetEl.setOpacity(0.99);
183 // the fillTo() method will fill the stars up until the selected one
184 this.fillTo(index, false);
186 // Lets also not forget to fire our custom event!
187 this.fireEvent('change', this, this.values[index], this.stars[index]);
191 fillTo : function(index, hover) {
193 var addClass = hover ? 'ux-rating-star-hover' : 'ux-rating-star-on';
194 var removeClass = hover ? 'ux-rating-star-on' : 'ux-rating-star-hover';
196 // We add a css class to each star up until the selected one
197 Ext.each(this.stars.slice(0, index+1), function() {
198 Ext.fly(this).removeClass(removeClass).addClass(addClass);
201 // And then remove the same class from all the stars after this one
202 Ext.each(this.stars.slice(index+1), function() {
203 Ext.fly(this).removeClass([removeClass, addClass]);
211 fillNone : function() {
212 this.container.select('.ux-rating-star').removeClass(['ux-rating-star-hover', 'ux-rating-star-on']);
215 enable : function() {
220 this.input.dom.disabled = null;
221 this.disabled = false;
223 this.container.removeClass('ux-rating-disabled');
225 // We will be using the technique of event delegation by listening
226 // for bubbled up events on the container
228 click: this.onStarClick,
229 mouseover: this.onStarOver,
230 mouseout: this.onStarOut,
232 delegate: 'div.ux-rating-star'
236 disable : function() {
241 this.input.dom.disabled = true;
242 this.disabled = true;
244 this.container.addClass('ux-rating-disabled');
247 click: this.onStarClick,
248 mouseover: this.onStarOver,
249 mouseout: this.onStarOut,
251 delegate: 'div.ux-rating-star'
255 getValue : function() {
256 return this.values[this.selected] || this.resetValue;
259 destroy : function() {
261 this.container.remove();
262 this.radioBoxes.appendTo(this.el);
263 if(this.selected !== -1) {
264 this.radioBoxes.elements[this.selected].checked = true;