/** * @file Contains all dynamic functionality needed on post and term pages. * * @output wp-admin/js/post.js */ /* global ajaxurl, wpAjax, postboxes, pagenow, tinymce, alert, deleteUserSetting, ClipboardJS */ /* global theList:true, theExtraList:true, getUserSetting, setUserSetting, commentReply, commentsBox */ /* global WPSetThumbnailHTML, wptitlehint */ // Backward compatibility: prevent fatal errors. window.makeSlugeditClickable = window.editPermalink = function(){}; // Make sure the wp object exists. window.wp = window.wp || {}; ( function( $ ) { var titleHasFocus = false, __ = wp.i18n.__; /** * Control loading of comments on the post and term edit pages. * * @type {{st: number, get: commentsBox.get, load: commentsBox.load}} * * @namespace commentsBox */ window.commentsBox = { // Comment offset to use when fetching new comments. st : 0, /** * Fetch comments using Ajax and display them in the box. * * @memberof commentsBox * * @param {number} total Total number of comments for this post. * @param {number} num Optional. Number of comments to fetch, defaults to 20. * @return {boolean} Always returns false. */ get : function(total, num) { var st = this.st, data; if ( ! num ) num = 20; this.st += num; this.total = total; $( '#commentsdiv .spinner' ).addClass( 'is-active' ); data = { 'action' : 'get-comments', 'mode' : 'single', '_ajax_nonce' : $('#add_comment_nonce').val(), 'p' : $('#post_ID').val(), 'start' : st, 'number' : num }; $.post( ajaxurl, data, function(r) { r = wpAjax.parseAjaxResponse(r); $('#commentsdiv .widefat').show(); $( '#commentsdiv .spinner' ).removeClass( 'is-active' ); if ( 'object' == typeof r && r.responses[0] ) { $('#the-comment-list').append( r.responses[0].data ); theList = theExtraList = null; $( 'a[className*=\':\']' ).off(); // If the offset is over the total number of comments we cannot fetch any more, so hide the button. if ( commentsBox.st > commentsBox.total ) $('#show-comments').hide(); else $('#show-comments').show().children('a').text( __( 'Show more comments' ) ); return; } else if ( 1 == r ) { $('#show-comments').text( __( 'No more comments found.' ) ); return; } $('#the-comment-list').append(''+wpAjax.broken+''); } ); return false; }, /** * Load the next batch of comments. * * @memberof commentsBox * * @param {number} total Total number of comments to load. */ load: function(total){ this.st = jQuery('#the-comment-list tr.comment:visible').length; this.get(total); } }; /** * Overwrite the content of the Featured Image postbox * * @param {string} html New HTML to be displayed in the content area of the postbox. * * @global */ window.WPSetThumbnailHTML = function(html){ $('.inside', '#postimagediv').html(html); }; /** * Set the Image ID of the Featured Image * * @param {number} id The post_id of the image to use as Featured Image. * * @global */ window.WPSetThumbnailID = function(id){ var field = $('input[value="_thumbnail_id"]', '#list-table'); if ( field.length > 0 ) { $('#meta\\[' + field.attr('id').match(/[0-9]+/) + '\\]\\[value\\]').text(id); } }; /** * Remove the Featured Image * * @param {string} nonce Nonce to use in the request. * * @global */ window.WPRemoveThumbnail = function(nonce){ $.post( ajaxurl, { action: 'set-post-thumbnail', post_id: $( '#post_ID' ).val(), thumbnail_id: -1, _ajax_nonce: nonce, cookie: encodeURIComponent( document.cookie ) }, /** * Handle server response * * @param {string} str Response, will be '0' when an error occurred otherwise contains link to add Featured Image. */ function(str){ if ( str == '0' ) { alert( __( 'Could not set that as the thumbnail image. Try a different attachment.' ) ); } else { WPSetThumbnailHTML(str); } } ); }; /** * Heartbeat locks. * * Used to lock editing of an object by only one user at a time. * * When the user does not send a heartbeat in a heartbeat-time * the user is no longer editing and another user can start editing. */ $(document).on( 'heartbeat-send.refresh-lock', function( e, data ) { var lock = $('#active_post_lock').val(), post_id = $('#post_ID').val(), send = {}; if ( ! post_id || ! $('#post-lock-dialog').length ) return; send.post_id = post_id; if ( lock ) send.lock = lock; data['wp-refresh-post-lock'] = send; }).on( 'heartbeat-tick.refresh-lock', function( e, data ) { // Post locks: update the lock string or show the dialog if somebody has taken over editing. var received, wrap, avatar; if ( data['wp-refresh-post-lock'] ) { received = data['wp-refresh-post-lock']; if ( received.lock_error ) { // Show "editing taken over" message. wrap = $('#post-lock-dialog'); if ( wrap.length && ! wrap.is(':visible') ) { if ( wp.autosave ) { // Save the latest changes and disable. $(document).one( 'heartbeat-tick', function() { wp.autosave.server.suspend(); wrap.removeClass('saving').addClass('saved'); $(window).off( 'beforeunload.edit-post' ); }); wrap.addClass('saving'); wp.autosave.server.triggerSave(); } if ( received.lock_error.avatar_src ) { avatar = $( '', { 'class': 'avatar avatar-64 photo', width: 64, height: 64, alt: '', src: received.lock_error.avatar_src, srcset: received.lock_error.avatar_src_2x ? received.lock_error.avatar_src_2x + ' 2x' : undefined } ); wrap.find('div.post-locked-avatar').empty().append( avatar ); } wrap.show().find('.currently-editing').text( received.lock_error.text ); wrap.find('.wp-tab-first').trigger( 'focus' ); } } else if ( received.new_lock ) { $('#active_post_lock').val( received.new_lock ); } } }).on( 'before-autosave.update-post-slug', function() { titleHasFocus = document.activeElement && document.activeElement.id === 'title'; }).on( 'after-autosave.update-post-slug', function() { /* * Create slug area only if not already there * and the title field was not focused (user was not typing a title) when autosave ran. */ if ( ! $('#edit-slug-box > *').length && ! titleHasFocus ) { $.post( ajaxurl, { action: 'sample-permalink', post_id: $('#post_ID').val(), new_title: $('#title').val(), samplepermalinknonce: $('#samplepermalinknonce').val() }, function( data ) { if ( data != '-1' ) { $('#edit-slug-box').html(data); } } ); } }); }(jQuery)); /** * Heartbeat refresh nonces. */ (function($) { var check, timeout; /** * Only allow to check for nonce refresh every 30 seconds. */ function schedule() { check = false; window.clearTimeout( timeout ); timeout = window.setTimeout( function(){ check = true; }, 300000 ); } $( function() { schedule(); }).on( 'heartbeat-send.wp-refresh-nonces', function( e, data ) { var post_id, $authCheck = $('#wp-auth-check-wrap'); if ( check || ( $authCheck.length && ! $authCheck.hasClass( 'hidden' ) ) ) { if ( ( post_id = $('#post_ID').val() ) && $('#_wpnonce').val() ) { data['wp-refresh-post-nonces'] = { post_id: post_id }; } } }).on( 'heartbeat-tick.wp-refresh-nonces', function( e, data ) { var nonces = data['wp-refresh-post-nonces']; if ( nonces ) { schedule(); if ( nonces.replace ) { $.each( nonces.replace, function( selector, value ) { $( '#' + selector ).val( value ); }); } if ( nonces.heartbeatNonce ) window.heartbeatSettings.nonce = nonces.heartbeatNonce; } }); }(jQuery)); /** * All post and postbox controls and functionality. */ jQuery( function($) { var stamp, visibility, $submitButtons, updateVisibility, updateText, $textarea = $('#content'), $document = $(document), postId = $('#post_ID').val() || 0, $submitpost = $('#submitpost'), releaseLock = true, $postVisibilitySelect = $('#post-visibility-select'), $timestampdiv = $('#timestampdiv'), $postStatusSelect = $('#post-status-select'), isMac = window.navigator.platform ? window.navigator.platform.indexOf( 'Mac' ) !== -1 : false, copyAttachmentURLClipboard = new ClipboardJS( '.copy-attachment-url.edit-media' ), copyAttachmentURLSuccessTimeout, __ = wp.i18n.__, _x = wp.i18n._x; postboxes.add_postbox_toggles(pagenow); /* * Clear the window name. Otherwise if this is a former preview window where the user navigated to edit another post, * and the first post is still being edited, clicking Preview there will use this window to show the preview. */ window.name = ''; // Post locks: contain focus inside the dialog. If the dialog is shown, focus the first item. $('#post-lock-dialog .notification-dialog').on( 'keydown', function(e) { // Don't do anything when [Tab] is pressed. if ( e.which != 9 ) return; var target = $(e.target); // [Shift] + [Tab] on first tab cycles back to last tab. if ( target.hasClass('wp-tab-first') && e.shiftKey ) { $(this).find('.wp-tab-last').trigger( 'focus' ); e.preventDefault(); // [Tab] on last tab cycles back to first tab. } else if ( target.hasClass('wp-tab-last') && ! e.shiftKey ) { $(this).find('.wp-tab-first').trigger( 'focus' ); e.preventDefault(); } }).filter(':visible').find('.wp-tab-first').trigger( 'focus' ); // Set the heartbeat interval to 10 seconds if post lock dialogs are enabled. if ( wp.heartbeat && $('#post-lock-dialog').length ) { wp.heartbeat.interval( 10 ); } // The form is being submitted by the user. $submitButtons = $submitpost.find( ':submit, a.submitdelete, #post-preview' ).on( 'click.edit-post', function( event ) { var $button = $(this); if ( $button.hasClass('disabled') ) { event.preventDefault(); return; } if ( $button.hasClass('submitdelete') || $button.is( '#post-preview' ) ) { return; } // The form submission can be blocked from JS or by using HTML 5.0 validation on some fields. // Run this only on an actual 'submit'. $('form#post').off( 'submit.edit-post' ).on( 'submit.edit-post', function( event ) { if ( event.isDefaultPrevented() ) { return; } // Stop auto save. if ( wp.autosave ) { wp.autosave.server.suspend(); } if ( typeof commentReply !== 'undefined' ) { /* * Warn the user they have an unsaved comment before submitting * the post data for update. */ if ( ! commentReply.discardCommentChanges() ) { return false; } /* * Close the comment edit/reply form if open to stop the form * action from interfering with the post's form action. */ commentReply.close(); } releaseLock = false; $(window).off( 'beforeunload.edit-post' ); $submitButtons.addClass( 'disabled' ); if ( $button.attr('id') === 'publish' ) { $submitpost.find( '#major-publishing-actions .spinner' ).addClass( 'is-active' ); } else { $submitpost.find( '#minor-publishing .spinner' ).addClass( 'is-active' ); } }); }); // Submit the form saving a draft or an autosave, and show a preview in a new tab. $('#post-preview').on( 'click.post-preview', function( event ) { var $this = $(this), $form = $('form#post'), $previewField = $('input#wp-preview'), target = $this.attr('target') || 'wp-preview', ua = navigator.userAgent.toLowerCase(); event.preventDefault(); if ( $this.hasClass('disabled') ) { return; } if ( wp.autosave ) { wp.autosave.server.tempBlockSave(); } $previewField.val('dopreview'); $form.attr( 'target', target ).trigger( 'submit' ).attr( 'target', '' ); // Workaround for WebKit bug preventing a form submitting twice to the same action. // https://bugs.webkit.org/show_bug.cgi?id=28633 if ( ua.indexOf('safari') !== -1 && ua.indexOf('chrome') === -1 ) { $form.attr( 'action', function( index, value ) { return value + '?t=' + ( new Date() ).getTime(); }); } $previewField.val(''); }); // Auto save new posts after a title is typed. if ( $( '#auto_draft' ).val() ) { $( '#title' ).on( 'blur', function() { var cancel; if ( ! this.value || $('#edit-slug-box > *').length ) { return; } // Cancel the auto save when the blur was triggered by the user submitting the form. $('form#post').one( 'submit', function() { cancel = true; }); window.setTimeout( function() { if ( ! cancel && wp.autosave ) { wp.autosave.server.triggerSave(); } }, 200 ); }); } $document.on( 'autosave-disable-buttons.edit-post', function() { $submitButtons.addClass( 'disabled' ); }).on( 'autosave-enable-buttons.edit-post', function() { if ( ! wp.heartbeat || ! wp.heartbeat.hasConnectionError() ) { $submitButtons.removeClass( 'disabled' ); } }).on( 'before-autosave.edit-post', function() { $( '.autosave-message' ).text( __( 'Saving Draft…' ) ); }).on( 'after-autosave.edit-post', function( event, data ) { $( '.autosave-message' ).text( data.message ); if ( $( document.body ).hasClass( 'post-new-php' ) ) { $( '.submitbox .submitdelete' ).show(); } }); /* * When the user is trying to load another page, or reloads current page * show a confirmation dialog when there are unsaved changes. */ $( window ).on( 'beforeunload.edit-post', function( event ) { var editor = window.tinymce && window.tinymce.get( 'content' ); var changed = false; if ( wp.autosave ) { changed = wp.autosave.server.postChanged(); } else if ( editor ) { changed = ( ! editor.isHidden() && editor.isDirty() ); } if ( changed ) { event.preventDefault(); // The return string is needed for browser compat. // See https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event. return __( 'The changes you made will be lost if you navigate away from this page.' ); } }).on( 'pagehide.edit-post', function( event ) { if ( ! releaseLock ) { return; } /* * Unload is triggered (by hand) on removing the Thickbox iframe. * Make sure we process only the main document unload. */ if ( event.target && event.target.nodeName != '#document' ) { return; } var postID = $('#post_ID').val(); var postLock = $('#active_post_lock').val(); if ( ! postID || ! postLock ) { return; } var data = { action: 'wp-remove-post-lock', _wpnonce: $('#_wpnonce').val(), post_ID: postID, active_post_lock: postLock }; if ( window.FormData && window.navigator.sendBeacon ) { var formData = new window.FormData(); $.each( data, function( key, value ) { formData.append( key, value ); }); if ( window.navigator.sendBeacon( ajaxurl, formData ) ) { return; } } // Fall back to a synchronous POST request. // See https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon $.post({ async: false, data: data, url: ajaxurl }); }); // Multiple taxonomies. if ( $('#tagsdiv-post_tag').length ) { window.tagBox && window.tagBox.init(); } else { $('.meta-box-sortables').children('div.postbox').each(function(){ if ( this.id.indexOf('tagsdiv-') === 0 ) { window.tagBox && window.tagBox.init(); return false; } }); } // Handle categories. $('.categorydiv').each( function(){ var this_id = $(this).attr('id'), catAddBefore, catAddAfter, taxonomyParts, taxonomy, settingName; taxonomyParts = this_id.split('-'); taxonomyParts.shift(); taxonomy = taxonomyParts.join('-'); settingName = taxonomy + '_tab'; if ( taxonomy == 'category' ) { settingName = 'cats'; } // @todo Move to jQuery 1.3+, support for multiple hierarchical taxonomies, see wp-lists.js. $('a', '#' + taxonomy + '-tabs').on( 'click', function( e ) { e.preventDefault(); var t = $(this).attr('href'); $(this).parent().addClass('tabs').siblings('li').removeClass('tabs'); $('#' + taxonomy + '-tabs').siblings('.tabs-panel').hide(); $(t).show(); if ( '#' + taxonomy + '-all' == t ) { deleteUserSetting( settingName ); } else { setUserSetting( settingName, 'pop' ); } }); if ( getUserSetting( settingName ) ) $('a[href="#' + taxonomy + '-pop"]', '#' + taxonomy + '-tabs').trigger( 'click' ); // Add category button controls. $('#new' + taxonomy).one( 'focus', function() { $( this ).val( '' ).removeClass( 'form-input-tip' ); }); // On [Enter] submit the taxonomy. $('#new' + taxonomy).on( 'keypress', function(event){ if( 13 === event.keyCode ) { event.preventDefault(); $('#' + taxonomy + '-add-submit').trigger( 'click' ); } }); // After submitting a new taxonomy, re-focus the input field. $('#' + taxonomy + '-add-submit').on( 'click', function() { $('#new' + taxonomy).trigger( 'focus' ); }); /** * Before adding a new taxonomy, disable submit button. * * @param {Object} s Taxonomy object which will be added. * * @return {Object} */ catAddBefore = function( s ) { if ( !$('#new'+taxonomy).val() ) { return false; } s.data += '&' + $( ':checked', '#'+taxonomy+'checklist' ).serialize(); $( '#' + taxonomy + '-add-submit' ).prop( 'disabled', true ); return s; }; /** * Re-enable submit button after a taxonomy has been added. * * Re-enable submit button. * If the taxonomy has a parent place the taxonomy underneath the parent. * * @param {Object} r Response. * @param {Object} s Taxonomy data. * * @return {void} */ catAddAfter = function( r, s ) { var sup, drop = $('#new'+taxonomy+'_parent'); $( '#' + taxonomy + '-add-submit' ).prop( 'disabled', false ); if ( 'undefined' != s.parsed.responses[0] && (sup = s.parsed.responses[0].supplemental.newcat_parent) ) { drop.before(sup); drop.remove(); } }; $('#' + taxonomy + 'checklist').wpList({ alt: '', response: taxonomy + '-ajax-response', addBefore: catAddBefore, addAfter: catAddAfter }); // Add new taxonomy button toggles input form visibility. $('#' + taxonomy + '-add-toggle').on( 'click', function( e ) { e.preventDefault(); $('#' + taxonomy + '-adder').toggleClass( 'wp-hidden-children' ); $('a[href="#' + taxonomy + '-all"]', '#' + taxonomy + '-tabs').trigger( 'click' ); $('#new'+taxonomy).trigger( 'focus' ); }); // Sync checked items between "All {taxonomy}" and "Most used" lists. $('#' + taxonomy + 'checklist, #' + taxonomy + 'checklist-pop').on( 'click', 'li.popular-category > label input[type="checkbox"]', function() { var t = $(this), c = t.is(':checked'), id = t.val(); if ( id && t.parents('#taxonomy-'+taxonomy).length ) { // Fixed for ticket #62504. See https://core.trac.wordpress.org/ticket/62504. $('input#in-' + taxonomy + '-' + id + ', input[id^="in-' + taxonomy + '-' + id + '-"]').prop('checked', c); $('input#in-popular-' + taxonomy + '-' + id).prop('checked', c); } } ); }); // End cats. // Custom Fields postbox. if ( $('#postcustom').length ) { $( '#the-list' ).wpList( { /** * Add current post_ID to request to fetch custom fields * * @ignore * * @param {Object} s Request object. * * @return {Object} Data modified with post_ID attached. */ addBefore: function( s ) { s.data += '&post_id=' + $('#post_ID').val(); return s; }, /** * Show the listing of custom fields after fetching. * * @ignore */ addAfter: function() { $('table#list-table').show(); } }); } /* * Publish Post box (#submitdiv) */ if ( $('#submitdiv').length ) { stamp = $('#timestamp').html(); visibility = $('#post-visibility-display').html(); /** * When the visibility of a post changes sub-options should be shown or hidden. * * @ignore * * @return {void} */ updateVisibility = function() { // Show sticky for public posts. if ( $postVisibilitySelect.find('input:radio:checked').val() != 'public' ) { $('#sticky').prop('checked', false); $('#sticky-span').hide(); } else { $('#sticky-span').show(); } // Show password input field for password protected post. if ( $postVisibilitySelect.find('input:radio:checked').val() != 'password' ) { $('#password-span').hide(); } else { $('#password-span').show(); } }; /** * Make sure all labels represent the current settings. * * @ignore * * @return {boolean} False when an invalid timestamp has been selected, otherwise True. */ updateText = function() { if ( ! $timestampdiv.length ) return true; var attemptedDate, originalDate, currentDate, publishOn, postStatus = $('#post_status'), optPublish = $('option[value="publish"]', postStatus), aa = $('#aa').val(), mm = $('#mm').val(), jj = $('#jj').val(), hh = $('#hh').val(), mn = $('#mn').val(); attemptedDate = new Date( aa, mm - 1, jj, hh, mn ); originalDate = new Date( $('#hidden_aa').val(), $('#hidden_mm').val() -1, $('#hidden_jj').val(), $('#hidden_hh').val(), $('#hidden_mn').val() ); currentDate = new Date( $('#cur_aa').val(), $('#cur_mm').val() -1, $('#cur_jj').val(), $('#cur_hh').val(), $('#cur_mn').val() ); // Catch unexpected date problems. if ( attemptedDate.getFullYear() != aa || (1 + attemptedDate.getMonth()) != mm || attemptedDate.getDate() != jj || attemptedDate.getMinutes() != mn ) { $timestampdiv.find('.timestamp-wrap').addClass('form-invalid'); return false; } else { $timestampdiv.find('.timestamp-wrap').removeClass('form-invalid'); } // Determine what the publish should be depending on the date and post status. if ( attemptedDate > currentDate ) { publishOn = __( 'Schedule for:' ); $('#publish').val( _x( 'Schedule', 'post action/button label' ) ); } else if ( attemptedDate <= currentDate && $('#original_post_status').val() != 'publish' ) { publishOn = __( 'Publish on:' ); $('#publish').val( __( 'Publish' ) ); } else { publishOn = __( 'Published on:' ); $('#publish').val( __( 'Update' ) ); } // If the date is the same, set it to trigger update events. if ( originalDate.toUTCString() == attemptedDate.toUTCString() ) { // Re-set to the current value. $('#timestamp').html(stamp); } else { $('#timestamp').html( '\n' + publishOn + ' ' + // translators: 1: Month, 2: Day, 3: Year, 4: Hour, 5: Minute. __( '%1$s %2$s, %3$s at %4$s:%5$s' ) .replace( '%1$s', $( 'option[value="' + mm + '"]', '#mm' ).attr( 'data-text' ) ) .replace( '%2$s', parseInt( jj, 10 ) ) .replace( '%3$s', aa ) .replace( '%4$s', ( '00' + hh ).slice( -2 ) ) .replace( '%5$s', ( '00' + mn ).slice( -2 ) ) + ' ' ); } // Add "privately published" to post status when applies. if ( $postVisibilitySelect.find('input:radio:checked').val() == 'private' ) { $('#publish').val( __( 'Update' ) ); if ( 0 === optPublish.length ) { postStatus.append(''); } else { optPublish.html( __( 'Privately Published' ) ); } $('option[value="publish"]', postStatus).prop('selected', true); $('#misc-publishing-actions .edit-post-status').hide(); } else { if ( $('#original_post_status').val() == 'future' || $('#original_post_status').val() == 'draft' ) { if ( optPublish.length ) { optPublish.remove(); postStatus.val($('#hidden_post_status').val()); } } else { optPublish.html( __( 'Published' ) ); } if ( postStatus.is(':hidden') ) $('#misc-publishing-actions .edit-post-status').show(); } // Update "Status:" to currently selected status. $('#post-status-display').text( // Remove any potential tags from post status text. wp.sanitize.stripTagsAndEncodeText( $('option:selected', postStatus).text() ) ); // Show or hide the "Save Draft" button. if ( $('option:selected', postStatus).val() == 'private' || $('option:selected', postStatus).val() == 'publish' ) { $('#save-post').hide(); } else { $('#save-post').show(); if ( $('option:selected', postStatus).val() == 'pending' ) { $('#save-post').show().val( __( 'Save as Pending' ) ); } else { $('#save-post').show().val( __( 'Save Draft' ) ); } } return true; }; // Show the visibility options and hide the toggle button when opened. $( '#visibility .edit-visibility').on( 'click', function( e ) { e.preventDefault(); if ( $postVisibilitySelect.is(':hidden') ) { updateVisibility(); $postVisibilitySelect.slideDown( 'fast', function() { $postVisibilitySelect.find( 'input[type="radio"]' ).first().trigger( 'focus' ); } ); $(this).hide(); } }); // Cancel visibility selection area and hide it from view. $postVisibilitySelect.find('.cancel-post-visibility').on( 'click', function( event ) { $postVisibilitySelect.slideUp('fast'); $('#visibility-radio-' + $('#hidden-post-visibility').val()).prop('checked', true); $('#post_password').val($('#hidden-post-password').val()); $('#sticky').prop('checked', $('#hidden-post-sticky').prop('checked')); $('#post-visibility-display').html(visibility); $('#visibility .edit-visibility').show().trigger( 'focus' ); updateText(); event.preventDefault(); }); // Set the selected visibility as current. $postVisibilitySelect.find('.save-post-visibility').on( 'click', function( event ) { // Crazyhorse branch - multiple OK cancels. var visibilityLabel = '', selectedVisibility = $postVisibilitySelect.find('input:radio:checked').val(); $postVisibilitySelect.slideUp('fast'); $('#visibility .edit-visibility').show().trigger( 'focus' ); updateText(); if ( 'public' !== selectedVisibility ) { $('#sticky').prop('checked', false); } switch ( selectedVisibility ) { case 'public': visibilityLabel = $( '#sticky' ).prop( 'checked' ) ? __( 'Public, Sticky' ) : __( 'Public' ); break; case 'private': visibilityLabel = __( 'Private' ); break; case 'password': visibilityLabel = __( 'Password Protected' ); break; } $('#post-visibility-display').text( visibilityLabel ); event.preventDefault(); }); // When the selection changes, update labels. $postVisibilitySelect.find('input:radio').on( 'change', function() { updateVisibility(); }); // Edit publish time click. $timestampdiv.siblings('a.edit-timestamp').on( 'click', function( event ) { if ( $timestampdiv.is( ':hidden' ) ) { $timestampdiv.slideDown( 'fast', function() { $( 'input, select', $timestampdiv.find( '.timestamp-wrap' ) ).first().trigger( 'focus' ); } ); $(this).hide(); } event.preventDefault(); }); // Cancel editing the publish time and hide the settings. $timestampdiv.find('.cancel-timestamp').on( 'click', function( event ) { $timestampdiv.slideUp('fast').siblings('a.edit-timestamp').show().trigger( 'focus' ); $('#mm').val($('#hidden_mm').val()); $('#jj').val($('#hidden_jj').val()); $('#aa').val($('#hidden_aa').val()); $('#hh').val($('#hidden_hh').val()); $('#mn').val($('#hidden_mn').val()); updateText(); event.preventDefault(); }); // Save the changed timestamp. $timestampdiv.find('.save-timestamp').on( 'click', function( event ) { // Crazyhorse branch - multiple OK cancels. if ( updateText() ) { $timestampdiv.slideUp('fast'); $timestampdiv.siblings('a.edit-timestamp').show().trigger( 'focus' ); } event.preventDefault(); }); // Cancel submit when an invalid timestamp has been selected. $('#post').on( 'submit', function( event ) { if ( ! updateText() ) { event.preventDefault(); $timestampdiv.show(); if ( wp.autosave ) { wp.autosave.enableButtons(); } $( '#publishing-action .spinner' ).removeClass( 'is-active' ); } }); // Post Status edit click. $postStatusSelect.siblings('a.edit-post-status').on( 'click', function( event ) { if ( $postStatusSelect.is( ':hidden' ) ) { $postStatusSelect.slideDown( 'fast', function() { $postStatusSelect.find('select').trigger( 'focus' ); } ); $(this).hide(); } event.preventDefault(); }); // Save the Post Status changes and hide the options. $postStatusSelect.find('.save-post-status').on( 'click', function( event ) { $postStatusSelect.slideUp( 'fast' ).siblings( 'a.edit-post-status' ).show().trigger( 'focus' ); updateText(); event.preventDefault(); }); // Cancel Post Status editing and hide the options. $postStatusSelect.find('.cancel-post-status').on( 'click', function( event ) { $postStatusSelect.slideUp( 'fast' ).siblings( 'a.edit-post-status' ).show().trigger( 'focus' ); $('#post_status').val( $('#hidden_post_status').val() ); updateText(); event.preventDefault(); }); } /** * Handle the editing of the post_name. Create the required HTML elements and * update the changes via Ajax. * * @global * * @return {void} */ function editPermalink() { var i, slug_value, slug_label, $el, revert_e, c = 0, real_slug = $('#post_name'), revert_slug = real_slug.val(), permalink = $( '#sample-permalink' ), permalinkOrig = permalink.html(), permalinkInner = $( '#sample-permalink a' ).html(), buttons = $('#edit-slug-buttons'), buttonsOrig = buttons.html(), full = $('#editable-post-name-full'); // Deal with Twemoji in the post-name. full.find( 'img' ).replaceWith( function() { return this.alt; } ); full = full.html(); permalink.html( permalinkInner ); // Save current content to revert to when cancelling. $el = $( '#editable-post-name' ); revert_e = $el.html(); buttons.html( ' ' + '' ); // Save permalink changes. buttons.children( '.save' ).on( 'click', function() { var new_slug = $el.children( 'input' ).val(); if ( new_slug == $('#editable-post-name-full').text() ) { buttons.children('.cancel').trigger( 'click' ); return; } $.post( ajaxurl, { action: 'sample-permalink', post_id: postId, new_slug: new_slug, new_title: $('#title').val(), samplepermalinknonce: $('#samplepermalinknonce').val() }, function(data) { var box = $('#edit-slug-box'); box.html(data); if (box.hasClass('hidden')) { box.fadeIn('fast', function () { box.removeClass('hidden'); }); } buttons.html(buttonsOrig); permalink.html(permalinkOrig); real_slug.val(new_slug); $( '.edit-slug' ).trigger( 'focus' ); wp.a11y.speak( __( 'Permalink saved' ) ); } ); }); // Cancel editing of permalink. buttons.children( '.cancel' ).on( 'click', function() { $('#view-post-btn').show(); $el.html(revert_e); buttons.html(buttonsOrig); permalink.html(permalinkOrig); real_slug.val(revert_slug); $( '.edit-slug' ).trigger( 'focus' ); }); // If more than 1/4th of 'full' is '%', make it empty. for ( i = 0; i < full.length; ++i ) { if ( '%' == full.charAt(i) ) c++; } slug_value = ( c > full.length / 4 ) ? '' : full; slug_label = __( 'URL Slug' ); $el.html( '' + '' ).children( 'input' ).on( 'keydown', function( e ) { var key = e.which; // On [Enter], just save the new slug, don't save the post. if ( 13 === key ) { e.preventDefault(); buttons.children( '.save' ).trigger( 'click' ); } // On [Esc] cancel the editing. if ( 27 === key ) { buttons.children( '.cancel' ).trigger( 'click' ); } } ).on( 'keyup', function() { real_slug.val( this.value ); }).trigger( 'focus' ); } $( '#titlediv' ).on( 'click', '.edit-slug', function() { editPermalink(); }); /** * Adds screen reader text to the title label when needed. * * Use the 'screen-reader-text' class to emulate a placeholder attribute * and hide the label when entering a value. * * @param {string} id Optional. HTML ID to add the screen reader helper text to. * * @global * * @return {void} */ window.wptitlehint = function( id ) { id = id || 'title'; var title = $( '#' + id ), titleprompt = $( '#' + id + '-prompt-text' ); if ( '' === title.val() ) { titleprompt.removeClass( 'screen-reader-text' ); } title.on( 'input', function() { if ( '' === this.value ) { titleprompt.removeClass( 'screen-reader-text' ); return; } titleprompt.addClass( 'screen-reader-text' ); } ); }; wptitlehint(); // Resize the WYSIWYG and plain text editors. ( function() { var editor, offset, mce, $handle = $('#post-status-info'), $postdivrich = $('#postdivrich'); // If there are no textareas or we are on a touch device, we can't do anything. if ( ! $textarea.length || 'ontouchstart' in window ) { // Hide the resize handle. $('#content-resize-handle').hide(); return; } /** * Handle drag event. * * @param {Object} event Event containing details about the drag. */ function dragging( event ) { if ( $postdivrich.hasClass( 'wp-editor-expand' ) ) { return; } if ( mce ) { editor.theme.resizeTo( null, offset + event.pageY ); } else { $textarea.height( Math.max( 50, offset + event.pageY ) ); } event.preventDefault(); } /** * When the dragging stopped make sure we return focus and do a confidence check on the height. */ function endDrag() { var height, toolbarHeight; if ( $postdivrich.hasClass( 'wp-editor-expand' ) ) { return; } if ( mce ) { editor.focus(); toolbarHeight = parseInt( $( '#wp-content-editor-container .mce-toolbar-grp' ).height(), 10 ); if ( toolbarHeight < 10 || toolbarHeight > 200 ) { toolbarHeight = 30; } height = parseInt( $('#content_ifr').css('height'), 10 ) + toolbarHeight - 28; } else { $textarea.trigger( 'focus' ); height = parseInt( $textarea.css('height'), 10 ); } $document.off( '.wp-editor-resize' ); // Confidence check: normalize height to stay within acceptable ranges. if ( height && height > 50 && height < 5000 ) { setUserSetting( 'ed_size', height ); } } $handle.on( 'mousedown.wp-editor-resize', function( event ) { if ( typeof tinymce !== 'undefined' ) { editor = tinymce.get('content'); } if ( editor && ! editor.isHidden() ) { mce = true; offset = $('#content_ifr').height() - event.pageY; } else { mce = false; offset = $textarea.height() - event.pageY; $textarea.trigger( 'blur' ); } $document.on( 'mousemove.wp-editor-resize', dragging ) .on( 'mouseup.wp-editor-resize mouseleave.wp-editor-resize', endDrag ); event.preventDefault(); }).on( 'mouseup.wp-editor-resize', endDrag ); })(); // TinyMCE specific handling of Post Format changes to reflect in the editor. if ( typeof tinymce !== 'undefined' ) { // When changing post formats, change the editor body class. $( '#post-formats-select input.post-format' ).on( 'change.set-editor-class', function() { var editor, body, format = this.id; if ( format && $( this ).prop( 'checked' ) && ( editor = tinymce.get( 'content' ) ) ) { body = editor.getBody(); body.className = body.className.replace( /\bpost-format-[^ ]+/, '' ); editor.dom.addClass( body, format == 'post-format-0' ? 'post-format-standard' : format ); $( document ).trigger( 'editor-classchange' ); } }); // When changing page template, change the editor body class. $( '#page_template' ).on( 'change.set-editor-class', function() { var editor, body, pageTemplate = $( this ).val() || ''; pageTemplate = pageTemplate.substr( pageTemplate.lastIndexOf( '/' ) + 1, pageTemplate.length ) .replace( /\.php$/, '' ) .replace( /\./g, '-' ); if ( pageTemplate && ( editor = tinymce.get( 'content' ) ) ) { body = editor.getBody(); body.className = body.className.replace( /\bpage-template-[^ ]+/, '' ); editor.dom.addClass( body, 'page-template-' + pageTemplate ); $( document ).trigger( 'editor-classchange' ); } }); } // Save on pressing [Ctrl]/[Command] + [S] in the Text editor. $textarea.on( 'keydown.wp-autosave', function( event ) { // Key [S] has code 83. if ( event.which === 83 ) { if ( event.shiftKey || event.altKey || ( isMac && ( ! event.metaKey || event.ctrlKey ) ) || ( ! isMac && ! event.ctrlKey ) ) { return; } wp.autosave && wp.autosave.server.triggerSave(); event.preventDefault(); } }); // If the last status was auto-draft and the save is triggered, edit the current URL. if ( $( '#original_post_status' ).val() === 'auto-draft' && window.history.replaceState ) { var location; $( '#publish' ).on( 'click', function() { location = window.location.href; location += ( location.indexOf( '?' ) !== -1 ) ? '&' : '?'; location += 'wp-post-new-reload=true'; window.history.replaceState( null, null, location ); }); } /** * Copies the attachment URL in the Edit Media page to the clipboard. * * @since 5.5.0 * * @param {MouseEvent} event A click event. * * @return {void} */ copyAttachmentURLClipboard.on( 'success', function( event ) { var triggerElement = $( event.trigger ), successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) ); // Clear the selection and move focus back to the trigger. event.clearSelection(); // Show success visual feedback. clearTimeout( copyAttachmentURLSuccessTimeout ); successElement.removeClass( 'hidden' ); // Hide success visual feedback after 3 seconds since last success. copyAttachmentURLSuccessTimeout = setTimeout( function() { successElement.addClass( 'hidden' ); }, 3000 ); // Handle success audible feedback. wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) ); } ); } ); /** * TinyMCE word count display */ ( function( $, counter ) { $( function() { var $content = $( '#content' ), $count = $( '#wp-word-count' ).find( '.word-count' ), prevCount = 0, contentEditor; /** * Get the word count from TinyMCE and display it */ function update() { var text, count; if ( ! contentEditor || contentEditor.isHidden() ) { text = $content.val(); } else { text = contentEditor.getContent( { format: 'raw' } ); } count = counter.count( text ); if ( count !== prevCount ) { $count.text( count ); } prevCount = count; } /** * Bind the word count update triggers. * * When a node change in the main TinyMCE editor has been triggered. * When a key has been released in the plain text content editor. */ $( document ).on( 'tinymce-editor-init', function( event, editor ) { if ( editor.id !== 'content' ) { return; } contentEditor = editor; editor.on( 'nodechange keyup', _.debounce( update, 1000 ) ); } ); $content.on( 'input keyup', _.debounce( update, 1000 ) ); update(); } ); } )( jQuery, new wp.utils.WordCounter() );

Keuntungan Bermain Mesin Virtual Tanpa Biaya

Mainkan Sekarang 100 Slot Gratis Terbaru Tanpa Deposit
slot gratis

Tahukah Anda bahwa slot gratis memberikan akses tanpa batas ke seluruh fitur permainan tanpa perlu deposit? Ini bekerja dengan memanfaatkan kredit virtual yang memungkinkan Anda memutar gulungan dan merasakan sensasi kemenangan tanpa risiko kehilangan uang sungguhan. Manfaat utamanya adalah Anda bisa menguji strategi dan memahami mekanisme bonus secara langsung, sehingga siap meraih keuntungan maksimal saat beralih ke mode taruhan nyata.

Keuntungan Bermain Mesin Virtual Tanpa Biaya

Bermain mesin virtual tanpa biaya di slot gratis memberi Anda kesempatan menguasai fitur-fitur unik tanpa tekanan kehilangan uang. Anda bisa mencoba berbagai strategi taruhan dengan bebas, karena risiko finansial sama sekali nol. Ini memungkinkan Anda memahami volatilitas permainan dan siklus bonus sebelum bermain sungguhan. Keuntungan lain adalah Anda bisa menikmati hiburan tanpa batas kapan saja tanpa perlu deposit. Pada akhirnya, pengalaman ini membangun kepercayaan diri Anda saat menghadapi mesin slot berbayar di kemudian hari.

Peluang Mencoba Beragam Tema Permainan

Keuntungan bermain mesin virtual tanpa biaya membuka peluang mencoba beragam tema permainan tanpa risiko finansial. Setiap slot gratis menawarkan narasi unik, dari petualangan Mesir kuno hingga dunia fiksi ilmiah futuristik. Pemain dapat menganalisis mekanisme volatilitas dan frekuensi bonus dari setiap tema tanpa harus mengeluarkan deposit. Perbandingan langsung antara tema klasik buah dengan tema video modern memungkinkan identifikasi preferensi visual dan audio yang paling sesuai. Dengan demikian, eksplorasi ini membangun pemahaman tentang bagaimana elemen tematik memengaruhi pengalaman bermain sebelum beralih ke taruhan nyata.

Melatih Strategi Tanpa Risiko Keuangan

Melatih strategi tanpa risiko keuangan adalah keuntungan utama dari mesin virtual gratis. Kamu bisa mencoba berbagai taktik taruhan, seperti mengatur besaran taruhan atau memilih fitur bonus tertentu, tanpa kehilangan uang sungguhan. Ini memungkinkan kamu menguji efektivitas setiap pendekatan secara langsung di putaran demo. Hasilnya, saat beralih ke permainan dengan uang asli, kamu sudah punya gambaran jelas tentang mana strategi yang paling cocok untuk gaya bermainmu.

Akses Langsung ke Fitur Bonus Spesial

Dalam bermain slot gratis, salah satu keuntungan terbesarmu adalah akses langsung ke fitur bonus spesial tanpa perlu deposit. Kamu bisa langsung memicu putaran gratis, pengganda liar, atau mini-game tanpa hambatan. Fitur ini biasanya terkunci di versi berbayar, tapi di sini semua terbuka begitu saja. Cukup klik dan nikmati bonusnya sepuas hati, tanpa risiko kehilangan saldo.

Akses langsung ke fitur bonus spesial di slot gratis memberimu kesempatan mencoba semua elemen seru tanpa syarat atau biaya tambahan.

Cara Memilih Platform Terbaik untuk Putaran Cuma-Cuma

Waktu itu saya hampir memilih platform asal hanya karena tergiur tulisan «100 putaran gratis». Ternyata, cara memilih platform terbaik untuk putaran cuma-cuma bukan sekadar melihat angka besar, melainkan syarat taruhan yang melekat. Saya baru sadar setelah mencoba beberapa platform, bahwa perbandingan syarat taruhan dan batas maksimal kemenangan adalah kunci utama. Platform bagus selalu transparan soal RTP slot yang digunakan untuk putaran gratis itu. Jangan langsung klaim; cek dulu apakah game slot gratis yang ditawarkan populer dan memiliki volatilitas sesuai gaya main Anda.

Pengalaman mengajarkan, platform terbaik sering menyembunyikan hadiah terbesarnya bukan di jumlah putaran, tapi di kemudahan Anda mengubah putaran cuma-cuma jadi saldo nyata.

Akhirnya saya hanya berpegang pada satu aturan: pilih platform yang betul-betul memberdayakan pemain, bukan sebaliknya.

Lisensi Resmi dan Keamanan Data Pemain

Memilih platform untuk slot gratis aman harus memprioritaskan lisensi resmi seperti PAGCOR atau MGA, yang menjamin enkripsi data pemain. Sebelum klaim putaran cuma-cuma, pastikan situs menggunakan protokol SSL untuk melindungi informasi pribadi dan transaksi. Lisensi resmi juga memastikan RNG (Random Number Generator) diaudit, sehingga hasil putaran benar-benar acak dan tidak dimanipulasi. Hindari platform tanpa izin jelas, karena data Anda rentan bocor. Cek ikon lisensi di footer situs sebagai indikasi keamanan.

Koleksi Provider Game Terkemuka

Saat memilih platform untuk putaran cuma-cuma, perhatikan koleksi provider game terkemuka yang tersedia. Provider seperti Pragmatic Play atau Habanero sering menawarkan slot gratis dengan fitur unik, seperti bonus putaran ulang atau simbol liar yang meluas. Semakin banyak provider ternama yang bekerja sama dengan platform, semakin variatif pengalaman bermain Anda. Q: Apa yang membedakan koleksi provider terkemuka dari yang lain? A: Provider ternama biasanya menyediakan slot gratis dengan winrate lebih tinggi (RTP) dan mekanisme bonus yang lebih sering aktif, sehingga peluang Anda meraih kemenangan dari putaran cuma-cuma pun lebih besar. Pastikan platform yang Anda pilih mengutamakan kerja sama dengan nama-nama besar ini.

slot gratis

Tawaran Bonus Sambutan yang Menguntungkan

Dalam memilih platform untuk putaran cuma-cuma, perhatikan syarat taruhan dari bonus sambutan yang menguntungkan. Bandingkan jumlah putaran gratis yang ditawarkan dengan persentase kontribusi slot terhadap persyaratan turnover. Pastikan batas waktu klaim bonus realistis dan tidak memberatkan permainan Anda. Periksa apakah bonus hanya berlaku untuk slot tertentu yang Anda minati. Beberapa platform menyertakan cashback jika tidak memenuhi syarat taruhan.

Aspek Bonus Sambutan Info Penting
Jumlah Putaran 25–100 putaran gratis untuk slot pilihan
Syarat Taruhan Minimal 35x kemenangan dari bonus
Masa Berlaku 7–14 hari sejak klaim

slot gratis

Jenis-Jenis Putaran Hiburan yang Populer

Di dunia slot gratis, jenis putaran hiburan yang paling populer adalah free spin tanpa deposit, di mana pemain bisa merasakan sensasi memutar gulungan tanpa mengeluarkan modal. Ada juga putaran dengan fitur «buy feature» yang memungkinkan Anda langsung masuk ke babak bonus. Saya ingat suatu kali, saat memainkan slot bertema petualangan, putaran ‘avalanche’ memberikan kemenangan beruntun tanpa henti dalam hitungan detik. Putaran tumbling atau cascading ini menjadi favorit karena setiap menang memicu simbol baru turun, memperpanjang aksi tanpa harus mengklik ulang. Semua ini murni hiburan, tanpa tekanan saldo riil.

Slot Klasik dengan Gulungan Sederhana

Untuk pemain yang suka nuansa nostalgia, Slot Klasik dengan Gulungan Sederhana adalah pilihan tepat di slot gratis. Dengan hanya tiga gulungan dan satu garis pembayaran, kamu bisa langsung fokus pada simbol buah seperti ceri dan lonceng tanpa kebingungan fitur bonus. Pola permainannya cepat dan mudah ditebak, cocok buat latihan strategi taruhan kecil. Setiap putaran terasa murni dan adil karena tidak ada animasi rumit yang mengganggu.

Video Slot Bertema Petualangan

Dalam ranah slot gratis bertema petualangan, pemain diajak menjelajahi harta karun, piramida kuno, atau hutan misterius tanpa risiko finansial. Fitur putaran bonus interaktif sering muncul saat simbol petualang mendarat, memungkinkan Anda memilih jalan atau membuka peti untuk menggandakan kemenangan virtual. Grafik sinematik dan efek suara dramatis membuat setiap putaran terasa seperti episode film. Q: Apakah kemenangan di slot gratis petualangan sama dengan versi berbayar? A: Ya, semua mekanisme dan RTP identik, hanya saldo Anda tidak berkurang saat kalah.

Jackpot Progresif dengan Hadiah Menggiurkan

Di antara jenis-jenis putaran hiburan populer, Jackpot Progresif dengan Hadiah Menggiurkan menjadi magnet utama karena akumulasi hadiahnya yang terus membengkak setiap kali pemain memutar gulungan secara gratis. Tanpa perlu deposit, Anda bisa mengejar kemenangan besar yang nilainya melonjak dari partisipasi banyak pengguna. Kuncinya adalah aktif bermain secara konsisten karena setiap putaran gratis berkontribusi pada jackpot. Berikut langkah untuk memaksimalkannya:

  1. Pilih permainan slot gratis yang terhubung langsung ke jaringan jackpot progresif.
  2. Pastikan Anda memenuhi syarat taruhan minimum untuk ikut serta dalam kumpulan hadiah.
  3. Manfaatkan fitur putaran bonus yang biasanya memicu kesempatan ekstra meraih jackpot.

Tips Maksimalkan Pengalaman Bermain Tanpa Deposit

Untuk memaksimalkan pengalaman bermain slot gratis, fokus utama adalah memilih varian permainan dengan tingkat pengembalian ke pemain (RTP) tinggi. Manfaatkan fitur demo untuk memahami pola volatilitas dan frekuensi bonus tanpa tekanan modal. Aturlah batas waktu bermain agar tidak kehilangan fokus, karena ketiadaan deposit justru membuat pemain cenderung bermain lebih lama. Pelajari tabel pembayaran setiap slot untuk mengetahui kombinasi simbol paling menguntungkan. Hindari berpindah-pindah game secara acak; sebaliknya, dalami satu atau dua judul untuk mengasah strategi. Dengan cara ini, Anda bisa merasakan sensasi kemenangan maksimal tanpa risiko finansial.

Manfaatkan Mode Demo Sebagai Latihan

Manfaatkan mode demo sebagai latihan untuk mengasah strategi tanpa risiko kehilangan uang. Dalam slot gratis, fitur ini memungkinkan Anda memahami pola pembayaran dan volatilitas setiap permainan. Lakukan taruhan virtual dengan metode berbeda untuk mengukur efektivitasnya. Jangan hanya bermain asal; rekam skenario kemenangan dan kekalahan untuk evaluasi.

Pantau Jadwal Promosi Putaran Spesial

Memantau jadwal promosi putaran spesial adalah langkah krusial untuk memaksimalkan sesi bermain slot gratis tanpa deposit. Biasanya, penyedia game menetapkan waktu tertentu, seperti akhir pekan atau jam-jam sepi, di mana putaran gratis ekstra atau multiplier lebih tinggi aktif. Catat jadwal ini di kalender pribadi, karena seringkali promosi bersifat flash sale dengan kuota terbatas. Dengan datang tepat waktu, Anda bisa mengklaim kredit tambahan tanpa perlu mengeluarkan modal, sekaligus memperpanjang durasi bermain Anda secara signifikan di mesin slot favorit.

Pantau jadwal promosi putaran spesial agar Anda bisa mengklaim bonus waktu-terbatas dan memperpanjang sesi slot gratis tanpa deposit secara optimal.

Kelola Waktu Bermain agar Tetap Santai

Bermain slot gratis memang menyenangkan, tapi kunci agar tetap santai adalah mengelola waktu bermain dengan bijak. Tetapkan batas waktu, misalnya 30 menit per sesi, lalu berhenti sejenak untuk meregangkan badan atau minum air. Jangan sampai larut karena tidak ada tekanan deposit, justru ini saatnya kamu latihan disiplin. Q: Bagaimana cara mengatur waktu agar tidak kalap? A: Gunakan timer di ponsel dan patuhi alarmnya; jika berbunyi, tinggalkan layar sejenak. Ingat, tujuan utama slot gratis adalah hiburan, bukan balapan tanpa akhir.

Membedah Fitur Unggulan pada Permainan Non-Taruhan

Dalam konteks slot gratis, membedah fitur unggulan pada permainan non-taruhan memungkinkan pemain menguasai mekanisme inti tanpa risiko finansial. Fitur-fitur seperti simbol Wild yang meluas dan putaran gratis (free spins) menjadi fokus utama karena secara langsung meningkatkan potensi kemenangan virtual. Dengan menganalisis tabel pembayaran (paytable) dan pola volatilitas, Anda dapat mengidentifikasi kombinasi pemicu bonus yang paling menguntungkan. Praktik ini justru lebih efektif daripada bermain asal-asalan karena memberi Anda peta jalan strategis sebelum bertaruh sungguhan. Misalnya, pada slot gratis bertema petualangan, fitur «Cascading Reels» dapat dipelajari polanya untuk memicu multiplier berantai, sementara simbol Scatter yang tersembunyi bisa dioptimalkan dengan simulasi spin berulang. Dengan pendekatan ini, slot gratis bukan sekadar hiburan, melainkan laboratorium untuk mengasah naluri permainan.

Simbol Scatter dan Wild yang Memicu Kemenangan

Dalam permainan slot gratis, kombinasi antara simbol Scatter dan Wild adalah pemicu utama kemenangan besar. Scatter yang muncul di mana pun pada gulungan biasanya mengaktifkan putaran gratis atau pengganda kemenangan total, sementara Wild berfungsi menggantikan simbol lain untuk melengkapi garis pembayaran. Interaksi keduanya menciptakan potensi maksimal saat Wild muncul dalam gulungan yang dipicu oleh Scatter, memungkinkan rantai kemenangan berlipat ganda tanpa biaya taruhan. Fokuslah pada posisi Scatter sebagai kunci pembuka fitur dan Wild sebagai akselerator pembayaran.

Ronde Bonus Interaktif dengan Hadiah Virtual

Ronde Bonus Interaktif dengan Hadiah Virtual adalah puncak pengalaman pada slot gratis non-taruhan. Alih-alih mengandalkan putaran acak, fitur ini meminta Anda menyelesaikan aktivitas seperti memilih kotak misteri, memecahkan teka-teki mini, atau memutar roda virtual untuk mengungkap hadiah virtual. Setiap aksi Anda dalam ronde ini memberikan umpan balik instan berupa koin, putaran tambahan, atau power-up. Berikut urutan interaksinya:

  1. Picu ronde bonus melalui kombinasi simbol spesifik pada gulungan.
  2. Selesaikan tantangan interaktif (klik, seret, atau ketuk) dalam batas waktu tertentu.
  3. Kumpulkan dan kumulasi hadiah virtual yang langsung ditambahkan ke saldo permainan.

slot gratis

Grafis Animasi Berkualitas Tinggi

Grafis animasi berkualitas tinggi pada slot gratis non-taruhan menghadirkan transisi visual mulus dengan efek partikel dan render 3D real-time. Setiap putaran bebas biaya menampilkan detail tekstur simbol premium yang tajam, serta animasi kemenangan dengan pencahayaan dinamis tanpa jeda. Q&A: Apa yang membedakan slot gratis dengan animasi tinggi dari versi berbayar? Tidak ada perbedaan; kualitas visual tetap terjaga karena hanya aspek taruhan yang dihapus, sehingga pemain tetap menikmati efek sinematik penuh.

Perbedaan Antara Versi Gratis dan Uang Asli

Perbedaan utama antara versi slot gratis dan uang asli terletak pada risiko dan imbalan. Di versi gratis, Anda bermain dengan kredit virtual sehingga tidak ada tekanan kehilangan uang, namun Anda juga tidak bisa menarik kemenangan. Sementara itu, versi uang asli menggunakan saldo nyata, sehingga setiap putaran memicu sensasi menang atau rugi secara langsung. Fitur permainan seperti RTP dan volatilitas tetap identik di kedua versi, tetapi versi uang asli sering menawarkan jackpot progresif dan bonus deposit yang tidak ada di versi gratis. Perbedaan paling krusial adalah Anda tidak bisa merasakan dampak psikologis dari risiko finansial saat bermain gratis, sehingga pengalaman menang terasa hampa. Pilihlah versi gratis untuk mempelajari mekanisme dan pola slot sebelum mempertaruhkan dana nyata.

Batasan Akses ke Kemenangan Riil

Batasan Akses ke Kemenangan Riil merupakan hambatan utama pada slot gratis. Meskipun Anda bisa memenangkan kredit virtual atau putaran bonus, kemenangan tersebut tidak dapat dicairkan menjadi uang tunai. Sistem kemenangan riil terkunci di balik persyaratan deposit. Bahkan jika saldo virtual mencapai angka fantastis, Anda tidak akan pernah bisa menariknya. Akses Anda hanya terbatas pada kepuasan bermain tanpa nilai ekonomis, berbeda total dengan versi uang asli yang membayar langsung ke rekening Anda.

Slot gratis membatasi akses ke kemenangan riil karena seluruh keuntungan bersifat virtual dan tidak dapat ditarik atau digunakan di luar platform.

Kesamaan Mekanisme dan RTP Dasar

Meskipun versi gratis tidak mempertaruhkan uang, kesamaan mekanisme dan RTP dasar tetap menjadi inti pengalaman. Setiap putaran pada slot gratis menjalankan algoritma yang identik dengan versi uang asli, memastikan frekuensi kemunculan simbol dan pola pembayaran tidak berubah. Untuk memahami hubungan ini secara praktis:

  1. Simbol Wild dan Scatter aktif dengan fungsi yang sama persis.
  2. RTP dasar (Return to Player) yang tertanam dalam kode tetap berlaku, tetapi tanpa dampak finansial riil.
  3. Volatilitas permainan—frekuensi kemenangan kecil versus besar—tidak dimodifikasi.

Ini membuktikan bahwa versi gratis adalah replika akurat untuk menguji strategi tanpa risiko.

Kesempatan untuk Memahami Pola Pembayaran

Bermain slot gratis memberikan kesempatan untuk memahami pola pembayaran tanpa risiko finansial. Anda dapat mengidentifikasi frekuensi simbol Wild dan Scatter memicu kemenangan, serta mengamati volatilitas permainan melalui simulasi gulungan. Perhatikan bagaimana kombinasi tertentu menghasilkan pembayaran lebih sering meski dengan nominal kecil. Untuk mempelajarinya secara sistematis:

  1. Catat hasil dari 100 putaran berturut-turut untuk melihat distribusi kemenangan.
  2. Bandingkan rasio antara putaran tanpa hadiah dan putaran dengan pengganda.
  3. Uji apakah fitur bonus mengaktifkan pola pembayaran yang berbeda.

Strategi Efektif untuk Pemula di Mesin Hiburan

Seorang pemula yang duduk di depan mesin hiburan sering kali langsung terburu-buru memencet tombol, tapi dengan slot gratis ia punya ruang untuk bernapas. Gunakan kesempatan ini untuk mempelajari pola pembayaran tanpa risiko kehilangan modal. Mulailah dengan taruhan terkecil agar Anda bisa mengamati berapa sering simbol liar muncul dan bagaimana fitur bonus dipicu. Saat gulungan berhenti, catat momen ketika kemenangan kecil beruntun terjadi—itu adalah petunjuk ritme mesin. Dengan begitu, Anda membangun strategi efektif untuk pemula di mesin hiburan, yaitu berlatih membaca siklus permainan lewat putaran gratis. Jangan tergoda mengganti mesin terlalu cepat; tetaplah di satu slot untuk memahami karakternya.

Mulai dengan Taruhan Minimal di Mode Uji Coba

Untuk pemula, strategi paling efektif adalah Mulai dengan Taruhan Minimal di Mode Uji Coba. Langkah ini memungkinkan Anda mempelajari mekanisme putaran, frekuensi kemenangan, dan fitur bonus tanpa risiko kehilangan saldo sungguhan. Dengan taruhan terkecil, Anda dapat memperpanjang sesi bermain guna mengamati pola volatilitas mesin. Fokus utama adalah mengidentifikasi kombinasi simbol pemicu free spin atau mini-game.

Pelajari Tabel Pembayaran Sebelum Bermain

Dalam konteks slot gratis, mempelajari tabel pembayaran sebelum bermain adalah langkah analitis yang tidak boleh dilewatkan. Tabel ini secara logis mengungkap nilai simbol, kombinasi kemenangan, serta fitur pengganda yang berlaku. Tanpa pemahaman ini, pemula kesulitan mengidentifikasi peluang optimal. Analisis tabel dilakukan secara berurutan:

  1. Buka tabel pembayaran untuk melihat hierarki nilai setiap simbol.
  2. Cari simbol Wild dan Scatter karena memicu fitur bonus atau putaran gratis.
  3. Perhatikan batas taruhan minimum dan maksimum yang memengaruhi potensi pembayaran.

Dengan pendekatan ini, risiko membuat keputuhan asal saat bermain slot gratis dapat diminimalkan secara efektif.

Hindari Kejar Rugi dengan Disiplin Diri

Disiplin diri adalah satu-satunya tameng untuk menghindari kejar rugi saat bermain slot gratis. Ketika saldo virtual habis, otak sering memicu dorongan untuk terus bermain demi mengembalikan kerugian—padahal di mode gratis, tidak ada yang benar-benar rugi. Anda harus menetapkan batas waktu dan jumlah putaran sebelum mulai. Jika rasa frustrasi muncul karena terus kalah, segera berhenti. Logika dasarnya sederhana: tanpa disiplin menghentikan sesi saat kondisi emosi mulai negatif, Anda justru terperangkap siklus sia-sia yang menghabiskan waktu. Hindari kejar rugi dengan disiplin diri berarti Anda mengontrol kapan berhenti, bukan mesin yang mengontrol Anda.

Q: Bagaimana cara langsung menerapkan disiplin diri agar tidak kejar rugi di slot gratis? A: Tentukan batas kerugian virtual—misalnya, jika saldo turun 30% dari awal sesi, segera tutup tab permainan tanpa pengecualian.

Rekomendasi Tema Favorit di Kalangan Pemain

Dalam rekomendasi tema favorit di kalangan pemain slot gratis, tema petualangan dan mitologi kuno mendominasi pilihan. Pemain sangat menyukai tema favorit di kalangan pemain yang menawarkan visual epik seperti dewa-dewi atau harta karun, karena memberikan sensasi imersif tanpa risiko finansial. Tema buah klasik juga tetap populer karena kesederhanaannya, sementara slot bertema fantasi dengan fitur putaran gratis interaktif sering menjadi incaran. Dengan slot gratis, pemain bisa mengeksplorasi berbagai variasi tanpa tekanan, memungkinkan mereka menentukan tema mana yang paling menghibur dan menguntungkan secara virtual.

Petualangan Mitologi Yunani Kuno

Dalam slot gratis bertema Petualangan Mitologi Yunani Kuno, pemain diajak berhadapan langsung dengan dewa-dewa seperti Zeus atau Hades. Fitur putaran gratis sering dipicu oleh simbol petir Zeus atau gerbang dunia bawah. Tidak ada uang sungguhan yang dipertaruhkan, jadi Anda bisa bebas menikmati animasi Medusa atau petualangan Perseus tanpa tekanan. Q: Apa simbol paling menarik di tema ini? A: Biasanya Patung Athena atau kutukan Medusa yang mengubah simbol jadi wild jika kena sinar matanya.

Jelajah Hutan Tropis dengan Binatang Liar

Di antara para pemain slot gratis bertema hutan tropis, tema «Jelajah Hutan Tropis dengan Binatang Liar» menjadi favorit karena efek visualnya yang liar dan peluang kemenangan yang tidak terduga. Setiap putaran menghadirkan harimau, monyet, atau burung eksotis sebagai simbol liar yang menggandakan kemenangan Anda. Kejutan muncul saat predator diam-diam mengaktifkan fitur bebas putaran di tengah rimbunnya dedaunan digital. Q: Apa keunikan fitur binatang liar di tema ini? A: Simbol binatang liar biasanya menggantikan simbol lain untuk membentuk kombinasi menang, sekaligus memicu animasi hutan yang mempercepat ritme permainan secara langsung.

Dunia Fantasi Berbasis Cerita Rakyat Nusantara

Di antara tema favorit di slot gratis, Dunia Fantasi Berbasis Cerita Rakyat Nusantara memikat pemain dengan petualangan mistis dari legenda lokal. Slot ini menghadirkan karakter seperti putri duyung dan genderuwo dalam putaran bonus bertingkat, membuat setiap spin terasa seperti menjelajahi hutan keramat. Simbol scatter sering memicu game interaktif untuk mengumpulkan mustika ajaib, bukan sekadar putaran biasa. Pemain bisa merasakan sensasi menggali harta karun dari kisah rakyat tanpa harus membaca narasi panjang, langsung seru dan relevan.

Dunia Fantasi Berbasis Cerita Rakyat Nusantara menghidupkan mitos lokal dalam putaran slot dengan fitur bonus unik dan petualangan tanpa henti.

slot gratis

Keamanan Bermain di Situs Penyedia Putaran Virtual

Keamanan bermain di situs penyedia putaran virtual sangat krusial saat memanfaatkan slot gratis. Pastikan situs menggunakan enkripsi SSL untuk melindungi data pribadi Anda saat login. Fitur slot gratis yang aman biasanya tidak meminta informasi sensitif seperti detail kartu kredit. Namun, kemenangan dari putaran gratis sering kali memiliki aturan taruhan ketat yang jarang dibaca pemain. Selalu konfirmasi bahwa koneksi situs dimulai dengan «https» sebelum memulai putaran virtual. Hindari mengklik tautan unduhan mencurigakan yang mengklaim akses ke slot gratis tanpa deposit. Fokus pada praktik pencegahan ini agar pengalaman bermain Anda tetap terlindungi dari risiko phising atau malware.

Verifikasi Identitas Platform Terpercaya

Verifikasi identitas di platform terpercaya menjadi benteng pertama saat Anda bermain slot gratis. Proses ini, meski terasa merepotkan, sebenarnya melindungi data pribadi Anda dari penyalahgunaan. Platform tepercaya mewajibkan verifikasi untuk memastikan setiap akun asli, mencegah robot atau penipu mengakses fitur. Verifikasi identitas platform terpercaya juga memudahkan Anda jika suatu saat ingin menarik bonus atau hadiah dari permainan gratis. Apakah verifikasi identitas wajib untuk semua slot gratis? Ya, karena ini memastikan Anda benar-benar pemain manusia yang menikmati putaran tanpa risiko kehilangan data.

Penggunaan Enkripsi Data untuk Transaksi

Dalam bermain slot gratis, enkripsi data untuk transaksi tetap menjadi fondasi keamanan meskipun tidak melibatkan uang sungguhan. Saat Anda mendaftar atau melakukan deposit awal, sistem harus melindungi informasi pribadi dan metode pembayaran melalui protokol SSL (Secure Socket Layer) yang mengubah data menjadi kode rumit. Hal ini mencegah peretas mengintip data selama proses pengiriman antara perangkat Anda dan server penyedia. official mashoki website Pastikan ikon gembok pada bilah alamat browser aktif sebelum memasukkan detail apa pun. Enkripsi TLS terbaru juga memastikan bahwa setiap sesi transaksi bersifat unik dan tidak mudah ditembus, sehingga Anda dapat fokus bermain tanpa khawatir data disalahgunakan.

Dukungan Pelanggan yang Responsif

Dukungan pelanggan yang responsif merupakan inti dari pengalaman bermain slot gratis yang aman. Jika Anda menemukan tautan rusak atau fitur demo tidak berfungsi, tim dukungan yang cepat akan memverifikasi keabsahan teknis platform tersebut tanpa menunda aktivitas Anda. Respons cepat terhadap pertanyaan sederhana, seperti jadwal refresh putaran gratis harian, menunjukkan bahwa situs mengutamakan transparansi. Pastikan kanal live chat beroperasi 24 jam untuk menangani laporan bug secara langsung, karena penundaan resolusi bisa mengindikasikan lemahnya proteksi data pemain.

Kesalahan Umum yang Harus Dihindari Saat Menikmati Demo

Kesalahan umum saat menikmati demo slot gratis adalah menganggap kemenangan di mode latihan sebagai jaminan hasil serupa di permainan uang asli. Banyak pemain juga abai membaca tabel pembayaran dan fitur bonus, padahal demo justru waktu ideal untuk mempelajarinya. Jangan terbuai dengan saldo virtual yang melimpah, karena itu hanya koin palsu tanpa nilai riil. Sikap terburu-buru memicu taruhan maksimal tanpa memahami volatilitas game adalah jebakan yang paling sering terjadi. Fokuslah menganalisis pola putaran dan frekuensi fitur, bukan mengejar kemenangan semu.

Tergoda untuk Langsung Bermain dengan Uang Asli

Salah satu jebakan paling umum adalah tergoda untuk langsung bermain dengan uang asli setelah beberapa putaran demo yang beruntung. Padahal, kemenangan di mode gratis hanyalah simulasi tanpa risiko. Tanpa memahami volatilitas dan ritme permainan, deposit awal bisa habis dalam hitungan menit. Gunakan momen demo untuk menguji strategi tanpa tekanan finansial, bukan sebagai ajang balas dendam. Q: Kapan waktu yang tepat untuk beralih ke uang asli jika saya tidak sabar? Jawab: Setelah Anda benar-benar yakin dengan pola dan modal yang Anda siapkan, bukan karena euforia sesaat.

Mengabaikan Syarat dan Ketentuan Promosi

Salah satu kesalahan paling umum saat menikmati slot gratis adalah mengabaikan syarat dan ketentuan promosi. Padahal, dokumen ini berisi batasan penting seperti persyaratan taruhan (wagering requirements), batas maksimal kemenangan dari bonus, serta daftar permainan yang memenuhi syarat. Tanpa membacanya, pemain bisa kehilangan hak klaim kemenangan karena dianggap melanggar aturan teknis. Sebagai contoh, banyak promo mengharuskan deposit minimum tertentu atau membatasi waktu penggunaan. Melewatkan detail ini membuat pengalaman bermain sia-sia. Selalu luangkan waktu beberapa menit untuk meninjau syarat sebelum memulai.

Bermain Tanpa Memahami Volatilitas Game

Bermain demo slot tanpa memahami volatilitas game adalah kesalahan umum yang membuat evaluasi Anda tidak akurat. Volatilitas tinggi menghasilkan kemenangan besar namun jarang, sementara volatilitas rendah memberi kemenangan kecil dan sering. Memahami volatilitas game membantu Anda menyusun strategi taruhan yang sesuai, bukan sekadar mengandalkan keberuntungan. Tanpa kesadaran ini, Anda mungkin mengira demo buruk hanya karena pola kemenangan tidak sesuai harapan.

Q: Apa akibat langsung dari mengabaikan volatilitas saat bermain demo slot?
A: Anda akan salah mengukur potensi risiko dan hadiah, sehingga pengalaman bermain tidak merepresentasikan performa game yang sebenarnya.

Apa Itu Slot Gratis dan Bagaimana Cara Kerjanya

Definisi dasar permainan tanpa biaya

Mekanisme putaran dan sistem pembayaran virtual

Keuntungan Bermain Tanpa Modal Awal

Pelajari fitur permainan tanpa risiko kehilangan uang

Kesempatan menguasai strategi taruhan simbol

Jenis-Jenis Fitur yang Bisa Kamu Temukan

Simbol liar, pencar, dan putaran gratis bonus

Jackpot progresif dalam versi demo

Tips Memilih Provider Terbaik untuk Mode Demo

Kriteria tampilan grafis dan animasi menarik

Keandalan platform dengan akses tanpa unduhan

Pertanyaan Umum Pengguna Baru Seputar Mode Coba-Coba

Apakah kemenangan di permainan latihan bisa dicairkan

Berapa lama batas waktu menggunakan akun percobaan