(function( $ ) { 'use strict'; $(function() { $.fn.afgStarRatings = function( p1, p2 ) { var opts = $.extend( {}, $.fn.afgStarRatings.defaults, p1 ); if( this.length === 0 ){ return this; } return this.each(function() { var $ctrl = $(this), $input; var post, field, nonce, id; init(); function init(){ $ctrl.addClass('afg-star-ratings'); /*in case it was not there yet*/ post = $ctrl.data('post') || opts.post; field = $ctrl.data('field') || opts.field; /* if element has no nonce data, it will be read-only */ nonce = $ctrl.data('nonce') || false; if( typeof $ctrl.data('afg-already-created') !== 'undefined' && $ctrl.data('afg-already-created') != null ){ //console.log( $ctrl.attr('id'), '.afg-star-ratings already created', $ctrl ); if( $ctrl.is('.editable') ){ prepareInput(); refreshView(); } return; } $ctrl.uniqueId(); $ctrl.closest('fieldset').find('input.aspects, input.ranks').on('change.afg', onSettingsChanged); if( nonce || ! hasContent() ){ /* the content is editable OR not there yet */ $ctrl.addClass('editable'); prepareValues(); } else { //console.log($ctrl.attr('id'), '.afg-star-ratings not editable'); } $ctrl.data('afg-already-created', true); //console.log( $ctrl.attr('id'), '.afg-star-ratings created', $ctrl ); } /* init */ function onStarClicked( value, event ){ var $stars = $(this), data = [], $img = $(event.target), $div, aspect = $stars.closest('.item').data("aspect"), decimal, adjusted; /*idx = $ctrl.find('div').index( $stars );*/ /*$img.nextAll('input[name="widgets[{$i}][score]"]').val( value );*/ decimal = (value % 1).toFixed(2) if (decimal < $.fn.raty.defaults.round.down){ adjusted = Math.floor( value ); } else if( decimal > $.fn.raty.defaults.round.up){ adjusted = Math.ceil( value ); } else { adjusted = Math.floor( value ) + 0.5; //half } $div = $img.closest('div').raty('score', adjusted); //console.log('star clicked', value, adjusted); submitValues(); //$('.afg-star-ratings[data-post="'+$ctrl.data('post')+'"] .item:nth-child('+(idx+1)+') div').not( $stars ).raty('score', value ); } /* onStarClicked */ function onSettingsChanged(ev){ var $set = $ctrl.closest('fieldset'), ranks = $set.find('input.ranks').val(), aspects = $set.find('input.aspects').val(), items = $.parseJSON( $input.val()), fresh = [], tmp = []; if( ranks ){ ranks = $.map(ranks.split(','), function(a, idx){ return $.trim(a) || null; }); } if( !ranks.length ){ ranks = opts.ranks; } items.ranks = ranks; $set.find('input.ranks').val( ranks.join(',') ); if( aspects.length ){ aspects = $.map(aspects.split(','), function(a, idx){ return $.trim(a) || null; }); } if( !aspects.length ){ aspects = opts.aspects; } $.each( aspects, function( i, aspect ){ var idx, found = false; if( ! aspect ){ return true; } $.each( items.aspects, function(j, asp){ if( aspect === asp[0] ){ asp[1] = asp[1] ? asp[1] : Math.min(i+0.5, aspects.length); fresh.push( asp ); tmp.push( asp[0] ); found = true; return false; } }); if( ! found ){ tmp.push( aspect ); fresh.push( [aspect, Math.min(i + 0.5, aspects.length)] ); } }); items.aspects = fresh; $set.find('input.aspects').val( tmp.join(',') ); //console.log('onSettingsChanged', items.aspects); $input.val( JSON.stringify( items )); recreateView(); } function refreshView(){/* apply values from input to divs */ var items = $.parseJSON( $input.val() ); //console.log( $input, items ); /* assuming rated aspects are still the same, and only values are changed */ $.each( items.aspects, function(key, aspect){ //console.log(key, aspect, $ctrl.find( '.item[data-aspect="'+aspect[0]+'"] div img' ).length); $ctrl.find( '.item[data-aspect="'+aspect[0]+'"] div' ).raty('score', aspect[1]); }); } /* refreshView */ function prepareInput(){ $input = $ctrl.find('input.items'); if( ! $input.length ){ $input = $( '#'+$ctrl.data('input') ); if( ! $input.length ){ /* create a new element */ //$input = $('').appendTo( $ctrl ); $input = $('').appendTo( $ctrl ); } } } /* prepareInput */ function prepareValues(){ /* Serialized rating data will be stored in one place only: input.value; If input can be found, an internal input gets created, and data for it either resolved from the contained list or gets downloaded. */ var downloading = false; prepareInput(); if( ! $input.val() ){ /* empty value */ if( hasContent() ){ updateValues(); /* resolve data from view */ } else { downloading = true; downloadValues(); /* download data */ } } if( ! downloading ){ recreateView(); /* if downloading, will recreate in the callback instead */ } } /* prepareValues */ function hasContent(){ //console.log('hasContent?', $ctrl.find('ul, table').length ); return $ctrl.find('ul, table').length > 0; } /* hasContent */ function downloadValues(){ var data = {}; data[ 'action' ] = opts.actionRetrieve; data[ 'afg_post_id' ] = post; data[ 'field' ] = field; $.get( opts.wpAjaxUrl, data, function( result ){ if( result.success ){ if( result.data.value ){ $input.val( result.data.value ); if( hasContent() ){ refreshView(); } else { recreateView(); } } } else { /* on error: destroy and recreate */ setDefaultValues(); recreateView(); } }); } /* downloadValues */ function updateValues(){ $input.val( JSON.stringify( collectData() )); } /* updateValues */ function recreateView(){ var $list, items = $.parseJSON( $input.val() ), isTable = $ctrl.is('.contains-table'); destroyContent(); //console.log( 'recreateView', items ); items.aspects = items.aspects || []; if( items.aspects.length ){ if( isTable ){ $list = $('