1(function( $, document ) { 2 var sfr = { 3 4 /** 5 * Set up cache with common elements and vars. 6 */ 7 cache: function() { 8 sfr.vars = {}; 9 10 sfr.vars.vote_button_selector = '[data-sfr-vote]'; 11 sfr.vars.button_status_classes = { 12 'voting': 'sfr-vote-button--voting', 13 'voted': 'sfr-vote-button--voted' 14 }; 15 sfr.vars.toggle_button_selector = '[data-sfr-toggle]'; 16 sfr.vars.toggle_user_type_selector = '[data-sfr-toggle-submission-user-type]'; 17 18 sfr.els = {}; 19 20 sfr.els.container = $( '.sfr-container' ); 21 sfr.els.filters = $( '.sfr-filters' ); 22 sfr.els.submission_form = { 23 'form': $( '.sfr-form--submission' ), 24 'title': $( '.sfr-form--submission .sfr-form__title' ), 25 'reveal': $( '.sfr-form--submission .sfr-form__reveal' ), 26 'loader': $( '.sfr-search-field__icon--loader' ), 27 'clear': $( '.sfr-search-field__icon--clear' ), 28 'choices': { 29 'container': $( '.sfr-form--submission .sfr-form__choices' ), 30 'count': $( '.sfr-form--submission .sfr-form__choices-count' ), 31 'vote': $( '.sfr-form--submission .sfr-form__choices-vote' ), 32 'or': $( '.sfr-form--submission .sfr-form__choices-or' ), 33 'post': $( '.sfr-form--submission .sfr-form__choices-post' ) 34 } 35 }; 36 sfr.els.loop = { 37 'container': $( '.sfr-content' ), 38 }; 39 }, 40 41 /** 42 * Run on doc ready. 43 */ 44 on_ready: function() { 45 sfr.cache(); 46 sfr.setup_vote_buttons(); 47 sfr.setup_toggle_buttons(); 48 sfr.setup_toggle_user_type(); 49 sfr.setup_filter_selects(); 50 sfr.setup_submission_form(); 51 sfr.setup_image_uploader(); 52 sfr.setup_image_gallery(); 53 }, 54 55 /** 56 * Setup vote buttons. 57 */ 58 setup_vote_buttons: function() { 59 $( document ).on( 'click', sfr.vars.vote_button_selector, function() { 60 var $button = $( this ); 61 62 if ( sfr.is_voting( $button ) ) { 63 return; 64 } 65 66 if ( sfr.has_user_voted( $button ) ) { 67 sfr.update_vote_count( $button, 'remove' ); 68 return; 69 } 70 71 sfr.update_vote_count( $button, 'add' ); 72 } ); 73 }, 74 75 /** 76 * Update vote count. 77 * 78 * @key $button 79 * @key type add|remove 80 */ 81 update_vote_count: function( $button, type ) { 82 var $button_text = $button.text(), 83 $button_class = $button.attr( 'class' ); 84 85 sfr.add_button_status_class( $button, 'voting' ); 86 $button.text( sfr_vars.il8n.voting + '...' ); 87 88 var post_id = sfr.get_post_id( $button ), 89 $badge = $button.closest( '.sfr-vote-badge' ), 90 $votes_counter = $badge.find( '.sfr-vote-badge__count strong' ), 91 $votes_text = $badge.find( '.sfr-vote-badge__count span' ), 92 data = { 93 'action': 'sfr_update_vote_count', 94 'post_id': post_id, 95 'type': type, 96 'nonce': sfr_vars.nonce 97 }; 98 99 $.post( sfr_vars.ajax_url, data, function( response ) { 100 if ( ! response.success ) { 101 sfr.display_notice( response.message, 'error' ); 102 $button.attr( 'class', $button_class ).text( $button_text ); 103 return; 104 } 105 106 if ( type === 'add' ) { 107 $button.text( sfr_vars.il8n.voted ); 108 sfr.add_button_status_class( $button, 'voted' ); 109 $button.attr( 'aria-pressed', 'true' ); 110 $votes_counter.text( response.votes ); 111 $votes_text.text( response.votes_wording ); 112 return; 113 } 114 115 sfr.remove_button_status_classes( $button ); 116 $button.text( sfr_vars.il8n.vote ); 117 $button.attr( 'aria-pressed', 'false' ); 118 $votes_counter.text( response.votes ); 119 $votes_text.text( response.votes_wording ); 120 } ); 121 }, 122 123 /** 124 * Display notice. 125 * 126 * @key message 127 * @key type 128 */ 129 display_notice: function( message, type ) { 130 alert( message ); 131 }, 132 133 /** 134 * Get post ID from button. 135 * 136 * @key $button 137 * @return {Number} 138 */ 139 get_post_id: function( $button ) { 140 return parseInt( $button.data( 'sfr-vote' ) ); 141 }, 142 143 /** 144 * Has user voted? 145 * 146 * @key $button 147 */ 148 has_user_voted: function( $button ) { 149 return $button.hasClass( sfr.vars.button_status_classes.voted ); 150 }, 151 152 /** 153 * Is voting in progress? 154 * 155 * @key $button 156 */ 157 is_voting: function( $button ) { 158 return $button.hasClass( sfr.vars.button_status_classes.voting ); 159 }, 160 161 /** 162 * Add button status classes. 163 * 164 * @key $button 165 * @key type 166 */ 167 add_button_status_class: function( $button, type ) { 168 sfr.remove_button_status_classes( $button ); 169 170 $button.addClass( sfr.vars.button_status_classes[ type ] ); 171 }, 172 173 /** 174 * Remove button status classes. 175 * 176 * @key $button 177 */ 178 remove_button_status_classes: function( $button ) { 179 $.each( sfr.vars.button_status_classes, function( index, status_class ) { 180 $button.removeClass( status_class ); 181 } ); 182 }, 183 184 /** 185 * Setup toggle buttons. 186 */ 187 setup_toggle_buttons: function() { 188 $( document ).on( 'click', sfr.vars.toggle_button_selector, function() { 189 var $button = $( this ), 190 $toggle = $( '.sfr-js-toggle-' + $button.data( 'sfr-toggle' ) ); 191
192 $toggle.toggle(); 193 } ); 194 }, 195 196 /** 197 * Setup toggle user type. 198 */ 199 setup_toggle_user_type: function() { 200 $( document ).on( 'click', sfr.vars.toggle_user_type_selector, function() { 201 var $button = $( this ), 202 type = $button.data( 'sfr-toggle-submission-user-type' ); 203 204 $( '[name="sfr-login-user-type"]' ).val( type ); 205 } ); 206 }, 207 208 /** 209 * Setup filter select redirects. 210 */ 211 setup_filter_selects: function() { 212 $( document ).on( 'change', '.sfr-filter-select[data-sfr-filter-redirect]', function() { 213 location.href = this.value; 214 } ); 215 }, 216 217 /** 218 * Setup submission form. 219 */ 220 setup_submission_form: function() { 221 if ( sfr.els.submission_form.form.length <= 0 ) { 222 return; 223 } 224 225 sfr.els.submission_form.title.keypress( function( e ) { 226 if ( e.which === 13 ) { 227 e.preventDefault(); 228 } 229 } ); 230 231 var timeout_id = null; 232 233 sfr.els.submission_form.title.keyup( function( e ) { 234 clearTimeout( timeout_id ); 235 236 timeout_id = setTimeout( function() { 237 sfr.search_feature_requests( e.target.value ); 238 }, 500 ); 239 } ); 240 241 sfr.els.submission_form.choices.post.on( 'click', function() { 242 sfr.reveal_submission_form(); 243 return false; 244 } ); 245 246 $( '.sfr-js-clear-search-field' ).on( 'click', function() { 247 sfr.els.submission_form.title.val('').keyup(); 248 $( this ).hide(); 249 } ); 250 }, 251 252 /** 253 * Search feature requests based on string. 254 * 255 * @key search 256 */ 257 search_feature_requests: function( search ) { 258 sfr.update_query_args( 'search', search ); 259 sfr.toggle_loader( 'show' ); 260 261 var data = { 262 'action': 'sfr_search_feature_requests', 263 'nonce': sfr_vars.nonce, 264 'paged': sfr_vars.paged, 265 }; 266 267 $.extend( data, sfr.get_url_parameters( window.location.href ) ); 268 269 // Add here so the characters aren't encoded when using $.extend() 270 data.search = search; 271 272 $.post( sfr_vars.ajax_url, data, function( response ) { 273 if ( ! response.success && ! response.html ) { 274 sfr.display_notice( response.message, 'error' ); 275 sfr.toggle_loader( 'hide' ); 276 return; 277 } 278 279 if ( ! response.success && search.length > 0 ) { 280 sfr.reveal_submission_form(); 281 } else { 282 sfr.hide_submission_form(); 283 } 284 285 sfr.els.loop.container.html( response.html ); 286 sfr.replace_pagination( response.pagination ); 287 sfr.toggle_filters( response ); 288 sfr.toggle_choices( response ); 289 sfr.toggle_loader( 'hide' ); 290 291 // Announce search results to screen readers 292 var announcement = response.count > 0 293 ? sfr_vars.il8n.search_results_found.replace( '%d', response.count ) 294 : sfr_vars.il8n.no_search_results; 295 sfr.announce_to_screen_readers( announcement ); 296 } ); 297 }, 298 299 /** 300 * Update a URL query arg. 301 * 302 * @param key 303 * @param value 304 */ 305 update_query_args: function( key, value ) { 306 key = encodeURIComponent( key ); 307 308 var url = window.location.href, 309 params = sfr.get_url_parameters( url ); 310 311 if ( value.length > 0 ) { 312 params[ key ] = value; 313 } else { 314 delete params[ key ]; 315 } 316 317 url = url.split( '?' )[ 0 ]; 318 319 if ( $.param( params ).length > 0 ) { 320 url += "?" + $.param( params ); 321 } 322 323 window.history.pushState( { key: key, value: value }, document.title, url ); 324 }, 325 326 /** 327 * Get URL parameters. 328 * 329 * @param url 330 * 331 * @return object 332 */ 333 get_url_parameters: function( url ) { 334 var result = {}, 335 searchIndex = url.indexOf( "?" ); 336 337 if ( searchIndex === - 1 ) { 338 return result; 339 } 340 341 var sPageURL = url.substring( searchIndex + 1 ), 342 sURLVariables = sPageURL.split( '&' ); 343 344 for ( var i = 0; i < sURLVariables.length; i ++ ) { 345 var sParameterName = sURLVariables[ i ].split( '=' ); 346 result[ sParameterName[ 0 ] ] = sParameterName[ 1 ]; 347 } 348 349 return result; 350 }, 351 352 /** 353 * Replace pagination. 354 * 355 * @param pagination 356 */ 357 replace_pagination: function( pagination ) { 358 if ( $( '.sfr-pagination' ).length <= 0 ) { 359 return; 360 } 361 362 $( '.sfr-pagination' ).replaceWith( pagination ); 363 }, 364 365 /** 366 * Toggle filters. 367 * 368 * @param search 369 */ 370 toggle_filters: function( response ) { 371 sfr.els.filters.hide(); 372 373 if ( response.search.length <= 0 ) { 374 sfr.els.filters.show(); 375 } 376 }, 377 378 /** 379 * Toggle choices. 380 * 381 * @param response 382 */ 383 toggle_choices: function( response ) { 384 sfr.els.submission_form.choices.vote.show(); 385 sfr.els.submission_form.choices.or.show(); 386 sfr.els.submission_form.choices.post.show(); 387 sfr.els.submission_form.choices.count.text( response.count ); 388 sfr.els.submission_form.choices.container.show(); 389 390 if ( response.count <= 0 || response.search.length <= 0 ) { 391 sfr.els.submission_form.choices.container.hide(); 392 } 393 }, 394 395 /** 396 * Reveal submission form. 397 */ 398 reveal_submission_form: function() { 399 sfr.els.submission_form.choices.or.hide(); 400 sfr.els.submission_form.choices.post.hide(); 401 sfr.els.submission_form.reveal.show(); 402 }, 403 404 /** 405 * Hide submission form. 406 */ 407 hide_submission_form: function() { 408 sfr.els.submission_form.reveal.hide(); 409 }, 410 411 /** 412 * Toggle loader. 413 * 414 * @param visiblity 415 */ 416 toggle_loader: function( visiblity ) { 417 if ( typeof visiblity === 'undefined' ) { 418 return; 419 } 420 421 if ( visiblity === 'show' ) { 422 sfr.els.submission_form.clear.hide(); 423 sfr.els.submission_form.loader.show(); 424 } else { 425 sfr.els.submission_form.loader.hide(); 426 427 if ( sfr.els.submission_form.title.val().length > 0 ) { 428 sfr.els.submission_form.clear.show(); 429 } 430 } 431 }, 432 433 /** 434 * Image upload handler 435 */ 436 setup_image_uploader: function(){ 437 if ( typeof Dropzone !== 'undefined' ) { 438 var uploader = $('#sfr-image-uploader'); 439 440 if( !uploader.length ){ 441 return; 442 } 443 444 var submit_btn = sfr.els.submission_form.form.find('.sfr-form__button'); 445 446 uploader.dropzone({ 447 url: sfr_vars.ajax_url, 448 params: { 449 action: 'sfr_set_feature_request_attachments', 450 nonce: sfr_vars.attachment_nonce 451 }, 452 init: function(){ 453 454 sfr.check_for_already_submitted_attachments( uploader, this ); 455 456 this.on('successmultiple', function(data, response){ 457 if( response.success && response.data.attachment_ids ){ 458 459 uploader.find('[name="attachment_ids[]"]').remove(); 460 461 $.each( response.data.attachment_ids, function( i, id ){ 462 uploader.append( '<input type="hidden" name="attachment_ids[]" value="'+id+'" />' ); 463 }); 464 } 465 }); 466 467 this.on('processingmultiple', function(){ 468 submit_btn.prop('disabled', true); 469 }); 470 471 this.on('successmultiple', function(){ 472 submit_btn.removeAttr('disabled'); 473 submit_btn.trigger('click'); 474 }); 475 476 this.on('removedfile', function(file){ 477 if( ! file.attachment_id ){ 478 return; 479 } 480 481 $('[name="attachment_ids[]"][value="'+file.attachment_id+'"]').remove(); 482 }); 483 }, 484 acceptedFiles: 'image/*', 485 uploadMultiple: true, 486 paramName: 'attachments', 487 autoProcessQueue: false, 488 addRemoveLinks: true, 489 hiddenInputContainer: uploader[0], 490 maxFiles: 5, 491 maxFilesize: sfr_vars['attachments_max_filesize'], 492 parallelUploads: 5 493 }); 494 495 var dropzone = Dropzone.forElement( uploader.get(0) ); 496 497 sfr.els.submission_form.form.on('submit', function(e){ 498 499 if( !dropzone.getQueuedFiles().length ){ 500 return; 501 } 502 503 e.preventDefault(); 504 dropzone.processQueue(); 505 }); 506 } 507 }, 508 509 /** 510 * Initiate already added attachments 511 * 512 * @param {jQuery} el jquery element of attachments container 513 * @param {Dropzone} dropzone Dropzone instance 514 */ 515 check_for_already_submitted_attachments: function( el, dropzone ){ 516 if ( typeof Dropzone !== 'undefined' ) { 517 var attachment_ids = el.find( '[name="attachment_ids[]"]' ); 518 519 if( ! attachment_ids.length ){ 520 return; 521 } 522 523 var values = attachment_ids.toArray().map( function( input ){ return $( input ).val(); }); 524 525 $.get({ 526 url: sfr_vars.ajax_url, 527 data: { 528 action: 'sfr_get_feature_request_attachments', 529 nonce: sfr_vars.attachment_nonce, 530 attachment_ids: values 531 }, 532 success: function(response){ 533 if( response.success && response.data.attachments ){ 534 $.each( response.data.attachments, function( i, attachment ){ 535 536 var mockFile = { name: attachment.name, size: attachment.size, attachment_id: i }; 537 538 dropzone.emit("addedfile", mockFile); 539 dropzone.options.thumbnail.call(dropzone, mockFile, attachment.url); 540 dropzone.emit("complete", mockFile); 541 }); 542 } 543 } 544 }); 545 } 546 }, 547 548 /** 549 * Image gallery on frontend 550 */ 551 setup_image_gallery: function(){ 552 553 var wrapper = $('.sfr-attachments'); 554 555 if( ! wrapper.length ){ 556 return; 557 } 558 559 wrapper.on('click', '.sfr-attachment', function(){ 560 561 var attachments = $(this).parent().find('.sfr-attachment'); 562 var images = []; 563 564 attachments.each(function(){ 565 566 var img = $(this).find('img'); 567 if( img ){ 568 images.push({ 569 src: img.data('src'), 570 w: img.data('width'), 571 h: img.data('height'), 572 }); 573 } 574 }); 575 576 var gallery = new PhotoSwipe( $('.pswp').get(0), PhotoSwipeUI_Default, images, {index: 0}); 577 gallery.init(); 578 }); 579 }, 580 581 /** 582 * Announce message to screen readers 583 * 584 * @param message 585 */ 586 announce_to_screen_readers: function( message ) { 587 var $announcer = $( '.sfr-sr-announcer' ); 588 589 if ( $announcer.length === 0 ) { 590 $announcer = $( '<div class="sfr-sr-announcer" aria-live="assertive" aria-atomic="true"></div>' ); 591 $( 'body' ).append( $announcer ); 592 } 593 594 $announcer.text( message ); 595 setTimeout( function() { 596 $announcer.text( '' ); 597 }, 1000 ); 598 } 599}; 600 601 if( ( typeof Dropzone !== 'undefined' && Dropzone !== null ) && sfr_vars.allow_attachments ) { 602 Dropzone.autoDiscover = false;
603 } 604 $( document ).ready( sfr.on_ready ); 605}( jQuery, document ));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.