Skip to content
Browse files

Merge branch 'javascript-cleanup' of github.com:Automattic/Ad-Code-Ma…

…nager into javascript-cleanup

Conflicts:
	ad-code-manager.php
  • Loading branch information...
2 parents 3879fb6 + cd59824 commit 589c7769288f65bfe5abd4b1e8cb48bfb2313746 @danielbachhuber danielbachhuber committed Mar 11, 2013
Showing with 398 additions and 165 deletions.
  1. +2 −26 ad-code-manager.php
  2. +395 −138 common/js/acm.js
  3. +1 −1 readme.txt
View
28 ad-code-manager.php
@@ -63,7 +63,6 @@ function __construct() {
// Incorporate the link to our admin menu
add_action( 'admin_menu' , array( $this, 'action_admin_menu' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts_and_styles' ) );
- add_action( 'admin_print_scripts', array( $this, 'post_admin_header' ) );
add_action( 'wp_ajax_acm_admin_action', array( $this, 'handle_admin_action' ) );
add_action( 'current_screen', array( $this, 'contextual_help' ) );
@@ -368,8 +367,6 @@ function handle_admin_action() {
*
*/
function get_ad_codes( $query_args = array() ) {
-
- $ad_codes_formatted = array();
$allowed_query_params = apply_filters( 'acm_allowed_get_posts_args', array( 'offset' ) );
@@ -594,27 +591,6 @@ function edit_conditionals( $ad_code_id, $conditionals = array() ) {
}
/**
- * Print our vars as JS
- */
- function post_admin_header() {
-
- if ( !isset( $_GET['page'] ) || $_GET['page'] != $this->plugin_slug )
- return;
-
- $conditionals_parsed = array();
- foreach ( $this->whitelisted_conditionals as $conditional )
- $conditionals_parsed[] = $conditional . ':' . ucfirst( str_replace( '_', ' ', $conditional ) );
-?>
- <script type="text/javascript">
- var acm_url = '<?php echo esc_js( admin_url( 'admin.php?page=' . $this->plugin_slug ) ) ?>';
- var acm_conditionals = '<?php echo esc_js( implode( ';', $conditionals_parsed ) )?>';
- var acm_ajax_nonce = '<?php echo esc_js( wp_create_nonce( 'acm_nonce' ) ) ?>';
- var acm_conditionals_index = 0;
- </script>
- <?php
- }
-
- /**
* Hook in our submenu page to the navigation
*/
function action_admin_menu() {
@@ -753,8 +729,8 @@ function register_scripts_and_styles() {
if ( 'tools.php' != $pagenow || !isset( $_GET['page'] ) || $_GET['page'] != $this->plugin_slug )
return;
- wp_enqueue_style( 'acm-style', AD_CODE_MANAGER_URL . 'common/css/acm.css' );
- wp_enqueue_script( 'acm', AD_CODE_MANAGER_URL . 'common/js/acm.js', array( 'jquery', 'jquery-ui-core' ) );
+ wp_enqueue_style( 'acm-style', AD_CODE_MANAGER_URL . '/common/css/acm.css' );
+ wp_enqueue_script( 'acm', AD_CODE_MANAGER_URL . '/common/js/acm.js', array( 'jquery' ), false, true );
}
/**
View
533 common/js/acm.js
@@ -1,139 +1,396 @@
-(function($) {
-inlineEditAdCodes = {
-
- init : function() {
- var t = this, row = $('#inline-edit');
-
- t.what = '#ad-code-';
-
- $('.acm-ajax-edit').live('click', function(){
- inlineEditAdCodes.edit(this);
- jQuery('.add-more-conditionals').off( 'click.acm_add_more_conditionals', acm_add_more_conditionals );
- jQuery('.add-more-conditionals').on( 'click.acm_add_more_conditionals', acm_add_more_conditionals );
- jQuery('.acm-remove-conditional').on( 'click.acm_remove_conditional', acm_remove_conditional );
- return false;
- });
-
- // prepare the edit row
- row.keyup(function(e) { if(e.which == 27) return inlineEditAdCodes.revert(); });
-
- $('a.cancel', row).click(function() { return inlineEditAdCodes.revert(); });
- $('a.save', row).click(function() { return inlineEditAdCodes.save(this); });
- $('td', row).keydown(function(e) { if(e.which == 13) return inlineEditAdCodes.save(this); });
-
- $('#posts-filter input[type="submit"]').mousedown(function(e){
- t.revert();
- });
- },
-
- toggle : function(el) {
- var t = this;
- $(t.what+t.getId(el)).css('display') == 'none' ? t.revert() : t.edit(el);
- },
-
- edit : function(id) {
- var t = this, editRow;
- t.revert();
-
- if ( typeof(id) == 'object' )
- id = t.getId(id);
-
- editRow = $('#inline-edit').clone(true), rowData = $('#inline_'+id);
- $('td', editRow).attr('colspan', $('.widefat:first thead th:visible').length);
-
- if ( $(t.what+id).hasClass('alternate') )
- $(editRow).addClass('alternate');
-
- $(t.what+id).hide().after(editRow);
-
- $('input[name="id"]', editRow).val( $('.id', rowData).text() );
- $('.acm-conditional-fields', editRow).html( $('.acm-conditional-fields', rowData).html() );
- $('.acm-column-fields', editRow).html( $('.acm-column-fields', rowData).html() );
- $('.acm-priority-field', editRow).html( $('.acm-priority-field', rowData).html() );
- $('.acm-operator-field', editRow).html( $('.acm-operator-field', rowData).html() );
-
- $(editRow).attr('id', 'edit-'+id).addClass('inline-editor').show();
- $('.ptitle', editRow).eq(0).focus();
-
- return false;
- },
-
- save : function(id) {
-
- if( typeof(id) == 'object' )
- id = this.getId(id);
-
- $('table.widefat .inline-edit-save .waiting').show();
- // Get all of our field parameters
- inline_edit = $('#edit-'+id ).find('fieldset').wrap('<form action="POST" ></form>');
- params = inline_edit.closest('form').serializeArray();
-
- // make ajax request
- $.post(ajaxurl, params,
- function(r) {
- var row, new_id;
- $('table.widefat .inline-edit-save .waiting').hide();
-
- if (r) {
- if ( -1 != r.indexOf('<tr') ) {
- $(inlineEditAdCodes.what+id).remove();
- new_id = $(r).attr('id');
-
- $('#edit-'+id).before(r).remove();
- row = new_id ? $('#'+new_id) : $(inlineEditAdCodes.what+id);
- row.hide().fadeIn();
- } else
- $('#edit-'+id+' .inline-edit-save .error').html(r).show();
- } else
- $('#edit-'+id+' .inline-edit-save .error').html(inlineEditL10n.error).show();
+( function( window, $, undefined ) {
+ var document = window.document;
+
+ var AdCodeManager = function() {
+ /**
+ * A reference to the AdCodeManager object so we avoid confusion with `this` later on
+ *
+ * @type {*}
+ */
+ var SELF = this;
+
+ /**
+ * Container for cached UI elements
+ *
+ * @type {Object}
+ */
+ var UI = {};
+
+ /**
+ * Used for storing the currently edited ACM ID
+ * @type {Boolean}
+ */
+ var EDIT_ID = false;
+
+ /**
+ * Initializes the AdCodeManager when the object is instantiated. This script must always run from the footer
+ * after the DOM elements are rendered
+ *
+ * @private
+ */
+ var _init = function() {
+ _cacheElements();
+ _bindEvents();
+ };
+
+ /**
+ * Caches useful DOM elements so we can easily reference them later without the extra lookup
+ *
+ * @private
+ */
+ var _cacheElements = function() {
+ UI.addMoreButton = document.getElementById( 'conditional-tpl' ).querySelector( '.add-more-conditionals' );
+ UI.theList = document.getElementById( 'the-list' );
+ UI.theNew = document.getElementById( 'add-adcode' );
+ };
+
+ /**
+ * Handles binding our events for the page to work
+ *
+ * @private
+ */
+ var _bindEvents = function() {
+ _addEvent( 'click', UI.addMoreButton, _addConditional );
+ _addEvent( 'click', UI.theList, _delegateListClicks );
+ _addEvent( 'click', UI.theNew, _delegateNewAdClicks );
+ _addEvent( 'keydown', UI.theList, _delegateListKeyEvents );
+ };
+
+ /**
+ * Registers a DOM event for the specified element
+ *
+ * @param event The event we're hooking to
+ * @param element The element we want to monitor for the event
+ * @param callback The callback to be fired when the event is triggered
+ * @private
+ */
+ var _addEvent = function( event, element, callback ) {
+ if( window.addEventListener ) {
+ element.addEventListener( event, callback, false );
+ }
+ else {
+ element.attachEvent( 'on' + event, callback );
+ }
+ };
+
+ /**
+ * Handles adding a new conditional row to the UI for the user
+ *
+ * @param e The event object
+ * @private
+ */
+ var _addConditional = function( e ) {
+ e = e || window.event;
+ var target = e.srcElement || e.target;
+ var parent = target.parentNode.parentNode.querySelector( '.form-new-row' );
+ _addInlineConditionalRow( parent );
+
+ _killEvent( e );
+ };
+
+ /**
+ * Kills the passed event and prevents it from bubbling up the DOM
+ *
+ * @param e The event we're killing
+ * @private
+ */
+ var _killEvent = function( e ) {
+ e.returnValue = false;
+ e.cancelBubble = true;
+ if( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+ if( e.preventDefault ) {
+ e.preventDefault();
+ }
+ };
+
+ /**
+ * Handles checking delegated events for the add ad code area
+ *
+ * @param e The event object
+ * @private
+ */
+ var _delegateNewAdClicks = function( e ) {
+ e = e || window.event;
+ var target = e.srcElement || e.target;
+
+ // check for remove conditional call
+ if( _hasClass( target, 'acm-remove-conditional' ) === true ) {
+ _removeInlineConditionalRow( target );
+ _killEvent( e );
+ }
+ };
+
+ /**
+ * Handles checking delegated key events for the inline editor and table rows
+ * @param e
+ * @private
+ */
+ var _delegateListKeyEvents = function( e ) {
+ e = e || window.event;
+ var key = e.which || e.keyCode;
+
+ // 13 is Enter, which avoids the default form on the page from saving
+ if ( key === 13 ) {
+ _saveInlineEditorChanges();
+ _killEvent( e );
+ }
+ };
+
+ /**
+ * Handles checking delegated events for the inline editor and table rows
+ *
+ * @param e The event object
+ * @private
+ */
+ var _delegateListClicks = function( e ) {
+ e = e || window.event;
+ var target = e.srcElement || e.target;
+
+ // check for ajax edit click
+ if( _hasClass( target, 'acm-ajax-edit' ) === true ) {
+ // close other editors
+ if( EDIT_ID !== false ) {
+ if( confirm( 'Are you sure you want to do this? Any unsaved data will be lost.' ) === false ) {
+ _killEvent( e );
+ return;
+ }
+ _toggleInlineEdit( false );
+ }
+
+ EDIT_ID = parseInt( target.id.replace( 'acm-edit-', '' ), 10 );
+ _toggleInlineEdit( true );
+ _killEvent( e );
+ }
+
+ // check for cancel button
+ else if( _hasClass( target, 'cancel' ) === true && EDIT_ID !== false ) {
+ _toggleInlineEdit( false );
+ EDIT_ID = false;
+ }
+
+ // check for remove conditional call
+ else if( _hasClass( target, 'acm-remove-conditional' ) === true ) {
+ _removeInlineConditionalRow( target );
+ _killEvent( e );
+ }
+
+ // check for save button
+ else if( _hasClass( target, 'save' ) === true ) {
+ _toggleLoader( true );
+ _saveInlineEditorChanges();
+ _killEvent( e );
}
- );
- return false;
- },
-
- revert : function() {
- var id = $('table.widefat tr.inline-editor').attr('id');
-
- if ( id ) {
- $('table.widefat .inline-edit-save .waiting').hide();
- $('#'+id).remove();
- id = id.substr( id.lastIndexOf('-') + 1 );
- $(this.what+id).show();
- }
-
- return false;
- },
-
- getId : function(o) {
- var id = o.tagName == 'TR' ? o.id : $(o).parents('tr').attr('id'), parts = id.split('-');
- return parts[parts.length - 1];
- }
-};
-
-$(document).ready(function(){inlineEditAdCodes.init();});
-})(jQuery);
-
-var acm_add_more_conditionals = function() {
- var temp = jQuery( 'div#conditional-single-field-master').clone( false );
- temp.removeAttr('id');
- jQuery(temp).find('.conditional-arguments').append( '<a href="#" class="acm-remove-conditional">Remove</a>' );
- jQuery(this).closest('.acm-conditional-fields').find('.form-new-row').append(temp);
- jQuery('.acm-remove-conditional').off( 'click.acm_remove_conditional', acm_remove_conditional );
- jQuery('.acm-remove-conditional').on( 'click.acm_remove_conditional', acm_remove_conditional );
- return false;
-}
-
-var acm_remove_conditional = function() {
- jQuery(this).closest('.conditional-single-field').remove();
- return false;
-}
-
-jQuery( document ).ready( function( $ ) {
-
- jQuery('.add-more-conditionals').on( 'click.acm_add_more_conditionals', acm_add_more_conditionals );
- $('#conditionals-help-toggler').click( function( e ) {
- var el = jQuery('#conditionals-help');
-
- el.toggleClass('hidden');
- });
-});
+
+ // check for add more conditionals
+ else if( _hasClass( target, 'add-more-conditionals' ) === true ) {
+ _addInlineConditionalRow( UI.theList.querySelector( '#ad-code-' + EDIT_ID + ' .acm-editor-row .acm-conditional-fields .form-new-row' ) );
+ _killEvent( e );
+ }
+ };
+
+ /**
+ * Saves any inline editor changes that occurred
+ *
+ * @private
+ */
+ var _saveInlineEditorChanges = function() {
+ $.post( window.ajaxurl, _getFormData(), function( result ) {
+ if( result ) {
+ if( result.indexOf( '<tr' ) > -1 ) {
+ $( document.getElementById( 'ad-code-' + EDIT_ID ) ).before( result).remove();
+ EDIT_ID = false;
+ }
+ else {
+ _showError( result );
+ }
+ }
+ else {
+ _showError( inlineEditL10n.error );
+ }
+ } );
+ };
+
+ /**
+ * Shows the error for this ad code if it exists
+ *
+ * @param html
+ * @private
+ */
+ var _showError = function( html ) {
+ var errorContainer = document.getElementById( 'ad-code-' + EDIT_ID ).querySelector( '.acm-editor-row .inline-edit-save .error' );
+ errorContainer.innerHTML = html;
+ errorContainer.style.display = 'block';
+ };
+
+ /**
+ * Custom serialization function based off of $.serializeArray() - slimmed down to exactly what we need
+ *
+ * @return {Array}
+ * @private
+ */
+ var _getFormData = function() {
+ var data = [];
+ var fields = document.getElementById( 'ad-code-' + EDIT_ID ).querySelector( '.acm-editor-row fieldset' );
+ var elements = fields.querySelectorAll( 'input, select, textarea' ), element, name;
+
+ for( var i = 0, len = elements.length; i < len; i++ ) {
+ element = elements[ i ];
+ name = element.name.replace( /^\s+|\s+$/i, '' );
+ if( name === '' ) {
+ continue;
+ }
+
+ data.push( { name : name, value : element.value } );
+ }
+
+ return data;
+ };
+
+ /**
+ * Removes the conditional row from the perspective of the button clicked
+ *
+ * @param target The `remove` button that was clicked.
+ * @private
+ */
+ var _removeInlineConditionalRow = function( target ) {
+ var row = target.parentNode.parentNode;
+ var parent = row.parentNode;
+ parent.removeChild( row );
+ };
+
+ /**
+ * Add a new inline editor conditional row for the current ad-code
+ *
+ * @private
+ */
+ var _addInlineConditionalRow = function( parent ) {
+ // create a new element
+ var newConditional = document.createElement( 'div' );
+ newConditional.className = 'conditional-single-field';
+ newConditional.innerHTML = document.getElementById( 'conditional-single-field-master' ).innerHTML;
+ newConditional.querySelector( '.conditional-arguments' ).innerHTML += '<a href="#" class="acm-remove-conditional">Remove</a>';
+
+ parent.appendChild( newConditional );
+ };
+
+ /**
+ * Toggles the loader for the form. This should only be used when the save button is clicked and we have a current
+ * EDIT_ID available
+ *
+ * @param showing Indicates whether the loader should be showing or not
+ * @private
+ */
+ var _toggleLoader = function( showing ) {
+ var loader = document.querySelector( '#ad-code-' + EDIT_ID + ' .acm-editor-row .inline-edit-save .waiting' );
+ loader.style.display = ( showing === true ) ? 'block' : 'none';
+ };
+
+ /**
+ * Lightweight utility function that handles checking an element to see if it contains a class
+ *
+ * @param element The element we're checking against
+ * @param className The class name we're looking for
+ * @return {Boolean}
+ * @private
+ */
+ var _hasClass = function( element, className ) {
+ return ( ' ' + element.className + ' ' ).indexOf( ' ' + className + ' ' ) > -1;
+ };
+
+ /**
+ * Handles toggling the inline editor. We assume EDIT_ID is being handled correctly for this to work.
+ *
+ * @param visible Indicates whether we are hiding/showing the inline editor.
+ * @private
+ */
+ var _toggleInlineEdit = function( visible ) {
+ var row = document.getElementById( 'ad-code-' + EDIT_ID );
+
+ if( visible === true ) {
+ _toggleTableChildrenDisplay( row, false );
+ _createNewInlineRow( EDIT_ID, row );
+ }
+ else {
+ _toggleTableChildrenDisplay( row, true );
+ _removeEditInlineRow( row );
+ }
+ };
+
+ /**
+ * Toggles all the table children of the parent.
+ *
+ * @param parent The parent table row we're toggling td's for
+ * @param display Indicates whether or not the row children should be shown or not
+ * @private
+ */
+ var _toggleTableChildrenDisplay = function( parent, display ) {
+ display = ( display === true ) ? 'table-cell' : 'none';
+ var children = parent.children;
+ for( var i = 0, len = children.length; i < len; i++ ) {
+ children[ i ].style.display = display;
+ }
+ };
+
+ /**
+ * Handles creating the new inline editor row with all of the necessary UI controls. Notice that we do not rebind
+ * events because they are already handled by the delegation technique in `_delegateListClicks`
+ *
+ * @param id The ID of the ad-code you are editing
+ * @param parentToBe The DOM element that the newRow will be inserted into
+ * @private
+ */
+ var _createNewInlineRow = function( id, parentToBe ) {
+ var newRow = document.createElement( 'td' );
+ newRow.setAttribute( 'colspan', ( parentToBe.children.length - 1 ) );
+ newRow.className = 'acm-editor-row';
+ newRow.innerHTML = document.getElementById( 'inline-edit' ).innerHTML;
+
+ // fill in the rows with existing HTML here
+ var data = _getDataFromRow( id );
+ newRow.querySelector( 'input[name="id"]' ).value = id;
+ newRow.querySelector( '.acm-conditional-fields' ).innerHTML = data.conditionalFields;
+ newRow.querySelector( '.acm-column-fields' ).innerHTML = data.columnFields;
+ newRow.querySelector( '.acm-priority-field' ).innerHTML = data.priority;
+ newRow.querySelector( '.acm-operator-field' ).innerHTML = data.operator;
+
+ parentToBe.appendChild( newRow );
+ };
+
+ /**
+ * Removes the editor inline row if it exists
+ *
+ * @param parent The parent DOM element where we are removing the oldRow from
+ * @private
+ */
+ var _removeEditInlineRow = function( parent ) {
+ var oldRow = parent.querySelector( '.acm-editor-row' );
+ parent.removeChild( oldRow );
+ parent.querySelector( '.column-id' ).style.display = 'none';
+ };
+
+ /**
+ * Builds an object literal containing HTML for the new Row based off of existing DOM elements and their HTML
+ *
+ * @param id The ID of the ad-code we're retrieving information from.
+ * @return {Object}
+ * @private
+ */
+ var _getDataFromRow = function( id ) {
+ var dataParent = document.getElementById( 'inline_' + id );
+ return {
+ conditionalFields : dataParent.querySelector( '.acm-conditional-fields' ).innerHTML,
+ columnFields : dataParent.querySelector( '.acm-column-fields' ).innerHTML,
+ priority : dataParent.querySelector( '.acm-priority-field' ).innerHTML,
+ operator : dataParent.querySelector( '.acm-operator-field' ).innerHTML
+ };
+ };
+
+ // fire our initialization method
+ _init();
+ };
+
+ window.AdCodeManager = new AdCodeManager();
+
+} )( window, jQuery );
View
2 readme.txt
@@ -1,5 +1,5 @@
=== Ad Code Manager ===
-Contributors: rinatkhaziev, jeremyfelt, zztimur, danielbachhuber, automattic, doejo
+Contributors: rinatkhaziev, jeremyfelt, danielbachhuber, carldanley, zztimur, automattic, doejo
Tags: advertising, ad codes, ads, adsense, dfp, doubleclick for publishers
Requires at least: 3.1
Tested up to: 3.5.1

0 comments on commit 589c776

Please sign in to comment.
Something went wrong with that request. Please try again.