From 6e1d35bf59bd4f3f551d1bf63918d50d80d1d3ef Mon Sep 17 00:00:00 2001 From: Chuck Scott Date: Mon, 22 Feb 2016 09:29:34 -0500 Subject: [PATCH] More requested changes --- activate.php | 4 +- classes/data/dataImages.php | 22 +- config/plugin.ini | 6 + controllers/admin.php | 115 +--- defines.php | 2 +- js/multiselect/multiselect.css | 101 ++++ js/multiselect/multiselect.js | 557 ++++++++++++++++++ models/admin/management/index.php | 9 +- models/admin/management/terms.php | 2 +- models/admin/members/list.php | 63 +- .../{configure => settings}/amenities.php | 6 +- .../{configure => settings}/categories.php | 4 +- .../admin/{configure => settings}/cities.php | 4 +- .../admin/{configure => settings}/index.php | 4 +- .../admin/{configure => settings}/regions.php | 4 +- setup/adminMenus.php | 122 ++++ setup/validActions.php | 2 +- views/admin/member/memberInfo.html | 8 +- views/admin/members/list.html | 51 +- .../{configure => settings}/amenities.html | 2 +- .../{configure => settings}/categories.html | 2 +- .../admin/{configure => settings}/cities.html | 2 +- .../admin/{configure => settings}/header.html | 2 +- .../admin/{configure => settings}/index.html | 2 +- .../{configure => settings}/regions.html | 2 +- 25 files changed, 918 insertions(+), 180 deletions(-) create mode 100644 js/multiselect/multiselect.css create mode 100644 js/multiselect/multiselect.js rename models/admin/{configure => settings}/amenities.php (97%) rename models/admin/{configure => settings}/categories.php (97%) rename models/admin/{configure => settings}/cities.php (97%) rename models/admin/{configure => settings}/index.php (97%) rename models/admin/{configure => settings}/regions.php (97%) create mode 100644 setup/adminMenus.php rename views/admin/{configure => settings}/amenities.html (99%) rename views/admin/{configure => settings}/categories.html (99%) rename views/admin/{configure => settings}/cities.html (99%) rename views/admin/{configure => settings}/header.html (95%) rename views/admin/{configure => settings}/index.html (99%) rename views/admin/{configure => settings}/regions.html (99%) diff --git a/activate.php b/activate.php index d02f2f0e..88e0eea2 100644 --- a/activate.php +++ b/activate.php @@ -91,7 +91,7 @@ class glmMembersPluginActivate extends glmPluginSupport $this->deleteRoleCapability('glm_members_edit'); $this->deleteRoleCapability('glm_members_info'); $this->deleteRoleCapability('glm_members_list'); - + $this->deleteRoleCapability('glm_members_configure'); /* * Add user capabilties */ @@ -130,7 +130,7 @@ class glmMembersPluginActivate extends glmPluginSupport ); // Access to Configure menu - $this->addRoleCapability('glm_members_configure', + $this->addRoleCapability('glm_members_settings', array( 'administrator' => true, 'author' => false, diff --git a/classes/data/dataImages.php b/classes/data/dataImages.php index 37c42bd7..9d9fe9af 100644 --- a/classes/data/dataImages.php +++ b/classes/data/dataImages.php @@ -133,14 +133,14 @@ class GlmDataImages extends GlmDataAbstract 'force_list' => true, 'use' => 'a' ), - +/* Not using for now // Special Image flag - only one of these 'selected' => array ( 'field' => 'selected', 'type' => 'checkbox', 'use' => 'gled' ), - +*/ // Featured Image flag 'featured' => array ( 'field' => 'featured', @@ -351,10 +351,10 @@ class GlmDataImages extends GlmDataAbstract && is_array($_REQUEST['galleryImage_caption']) && count($_REQUEST['galleryImage_caption']) > 0) { - // Get the ID of the "selected" image - Only one - $selected = 0; - if (isset($_REQUEST['galleryImage_selected'])) { - $selected = ($_REQUEST['galleryImage_selected'] - 0); + // Get the ID of the "featured" image - Only one + $featured = 0; + if (isset($_REQUEST['galleryImage_featured'])) { + $featured = ($_REQUEST['galleryImage_featured'] - 0); } // Update other data for this image @@ -365,20 +365,20 @@ class GlmDataImages extends GlmDataAbstract // Sanitize input $caption = sanitize_text_field( $_REQUEST['galleryImage_caption'][$k] ); $descr = sanitize_text_field( $_REQUEST['galleryImage_descr'][$k] ); - $featured = (isset($_REQUEST['galleryImage_featured']) && isset($_REQUEST['galleryImage_featured'][$k]) && $_REQUEST['galleryImage_featured'][$k] == 'on' ? 'true' : 'false'); +// $featured = (isset($_REQUEST['galleryImage_featured']) && isset($_REQUEST['galleryImage_featured'][$k]) && $_REQUEST['galleryImage_featured'][$k] == 'on' ? 'true' : 'false'); - // Check if this is the selected image - $thisSelected = ($selected == $k ? 'true' : 'false'); + // Check if this is the featured image + $thisFeatured = ($featured == $k ? 'true' : 'false'); // Update data for this image - $sql = "UPDATE ".GLM_MEMBERS_PLUGIN_DB_PREFIX ."images SET caption = '$caption', descr = '$descr', selected = $thisSelected, featured = $featured WHERE id = $id;"; + $sql = "UPDATE ".GLM_MEMBERS_PLUGIN_DB_PREFIX ."images SET caption = '$caption', descr = '$descr', featured = $thisFeatured WHERE id = $id;"; $this->wpdb->query($sql); } // Check for an image deletion if (isset($_REQUEST['galleryImage_delete']) && count($_REQUEST['galleryImage_delete']) > 0) { - // For each delete selected + // For each delete requested reset($_REQUEST['galleryImage_delete']); while (list($k, $v) = each($_REQUEST['galleryImage_delete'])) { $id = ($k -0); diff --git a/config/plugin.ini b/config/plugin.ini index 20b492c4..a8cbed6f 100644 --- a/config/plugin.ini +++ b/config/plugin.ini @@ -54,13 +54,17 @@ status_numb['Archived'] = 90 ; Member Access Levels ; access[30] = 'Display, Updates Moderated' +access[35] = 'Not Displayed, Updates Moderated' access[40] = 'Display, Updates Not Moderated' +access[45] = 'Not Displayed, Updates Not Moderated' access[20] = 'Display, No Access' access[10] = 'Not Displayed, No Access' access[90] = 'Not Displayed, Archived' access_short[30] = 'Moderated' +access_short[35] = 'NotDisplayed-Moderated' access_short[40] = 'Not-Moderated' +access_short[45] = 'NotDisplayed-NotModerated' access_short[20] = 'Display' access_short[10] = 'None' access_short[90] = 'Archived' @@ -68,7 +72,9 @@ access_short[90] = 'Archived' access_numb['NotDisplayed'] = 10 access_numb['NoAccess'] = 20 access_numb['Moderated'] = 30 +access_numb['NotDisplayedModerated'] = 35 access_numb['Full'] = 40 +access_numb['NotDisplayedNotModerated'] = 45 access_numb['Archived'] = 90 ; diff --git a/controllers/admin.php b/controllers/admin.php index 216bcefe..d2ce71cd 100644 --- a/controllers/admin.php +++ b/controllers/admin.php @@ -426,24 +426,37 @@ class glmMembersAdmin extends GlmPluginSupport ); wp_enqueue_style('glm-members-admin-image-upload-css'); + // jQuery Multi-Select + + wp_register_style( + 'glm-members-admin-jquery-select-css', + GLM_MEMBERS_PLUGIN_URL . 'js/multiselect/multiselect.css', + 'glm-members-admin-jquery-select', + GLM_MEMBERS_PLUGIN_VERSION + ); + wp_enqueue_style('glm-members-admin-jquery-select-css'); + wp_register_script( + 'glm-members-admin-jquery-select', + GLM_MEMBERS_PLUGIN_URL . 'js/multiselect/multiselect.js', + array( + 'jquery' + ), + GLM_MEMBERS_PLUGIN_VERSION + ); + wp_enqueue_script('glm-members-admin-jquery-select'); + + } /** * Configure WordPress Menus for this Plugin * * This method is called by an add_action() hook setup in the contructor. We - * do it - * this way so that the menu related functions of WordPress are in scope - * when creating - * the additional menu items. WordPress will execute this call-back method - * when building - * its Dashboard menus. + * do it this way so that the menu related functions of WordPress are in scope + * when creating the additional menu items. WordPress will execute this call-back method + * when building its Dashboard menus. * - * add menu function reference - * add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position) - * add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function) - * - * (no prameters) + * This function searches all add-ons for an "setup/adminMenus.php" file and runs them. * * @return void * @access public @@ -451,86 +464,6 @@ class glmMembersAdmin extends GlmPluginSupport public function configureMenus () { - // If user can manage all members, then show "Members" menu item - if (apply_filters('glm_members_menu_members', true)) { - - $mainMenuSlug = 'glm-members-admin-menu-members'; - - add_menu_page( - 'Members', - 'Members', - 'glm_members_main_menu', - 'glm-members-admin-menu-members', - function() {$this->controller('members');}, - false, - '91.123' - ); - - // Add a submenu for the "Member" section - if (apply_filters('glm_members_menu_member', true)) { - add_submenu_page( - $mainMenuSlug, - 'Member Dashboard', - 'Member', - 'glm_members_member', - 'glm-members-admin-menu-member', - function() {$this->controller('member');} - ); - } - - // Otherwise just display "Member" menu item - } else { - - $mainMenuSlug = 'glm-members-admin-menu-member'; - - add_menu_page( - 'Member', - 'Member', - 'glm_members_main_menu', - 'glm-members-admin-menu-member', - function() {$this->controller('member');}, - false, - '91.123' - ); - - } - - // Add a submenu for the "Configure" section - if (apply_filters('glm_members_menu_configure', true)) { - add_submenu_page( - 'glm-members-admin-menu-members', - 'Configure Members Database', - 'Configure', - 'glm_members_configure', - 'glm-members-admin-menu-configure', - function() {$this->controller('configure');} - ); - } - - // Add a submenu for the "Management" section - if (apply_filters('glm_members_menu_meanagement', true)) { - add_submenu_page( - 'glm-members-admin-menu-members', - 'Member DB Management', - 'Management', - 'glm_members_management', - 'glm-members-admin-menu-management', - function() {$this->controller('management');} - ); - } - - // Add a submenu for the "Shortcode Reference" section - if (apply_filters('glm_members_menu_shortcodes', true)) { - add_submenu_page( - 'glm-members-admin-menu-members', - 'Shortcode Reference', - 'Shortcodes', - 'glm_members_shortcodes', - 'glm-members-admin-menu-shortcodes', - function() {$this->controller('shortcodes');} - ); - } - // For each add-on, read in their menu additions - These are optional files foreach ($this->config['addOns'] as $a) { if (is_file(GLM_MEMBERS_WORDPRESS_PLUGIN_PATH.$a['slug'].'/setup/adminMenus.php')) { diff --git a/defines.php b/defines.php index 17fce4cd..69fcb713 100644 --- a/defines.php +++ b/defines.php @@ -7,7 +7,7 @@ // NOTE: Plugin & Database versions are defined in "/glm-member-db.php". -define('GLM_MEMBERS_PLUGIN_NAME', 'Gaslight Media Member Database'); +define('GLM_MEMBERS_PLUGIN_NAME', 'Gaslight Media Membership Management System'); define('GLM_MEMBERS_PLUGIN_SHORT_NAME', 'GLM Member DB'); define('GLM_MEMBERS_PLUGIN_SLUG', 'glm-member-db'); diff --git a/js/multiselect/multiselect.css b/js/multiselect/multiselect.css new file mode 100644 index 00000000..e8b35824 --- /dev/null +++ b/js/multiselect/multiselect.css @@ -0,0 +1,101 @@ +.ms-options-wrap, +.ms-options-wrap * { + box-sizing: border-box; +} + +.ms-options-wrap > button:focus, +.ms-options-wrap > button { + position: relative; + width: 100%; + text-align: left; + border: 1px solid #aaa; + background-color: #fff; + padding: 5px 20px 5px 5px; + margin-top: 1px; + font-size: 13px; + color: #aaa; + outline: none; + white-space: nowrap; +} + +.ms-options-wrap > button:after { + content: ' '; + height: 0; + position: absolute; + top: 50%; + right: 5px; + width: 0; + border: 6px solid rgba(0, 0, 0, 0); + border-top-color: #999; + margin-top: -3px; +} + +.ms-options-wrap > .ms-options { + position: absolute; + left: 0; + width: 100%; + margin-top: 1px; + margin-bottom: 20px; + background: white; + z-index: 2000; + border: 1px solid #aaa; +} + +.ms-options-wrap > .ms-options > .ms-search input { + width: 100%; + padding: 4px 5px; + border: none; + border-bottom: 1px groove; + outline: none; +} + +.ms-options-wrap > .ms-options .ms-selectall { + display: inline-block; + font-size: .9em; + text-transform: lowercase; + text-decoration: none; +} +.ms-options-wrap > .ms-options .ms-selectall:hover { + text-decoration: underline; +} + +.ms-options-wrap > .ms-options > .ms-selectall.global { + margin: 4px 5px; +} + +.ms-options-wrap > .ms-options > ul { + line-height: .2em; +} + +.ms-options-wrap > .ms-options > ul > li.optgroup { + padding: 5px; +} +.ms-options-wrap > .ms-options > ul > li.optgroup + li.optgroup { + border-top: 1px solid #aaa; +} + +.ms-options-wrap > .ms-options > ul > li.optgroup .label { + display: block; + padding: 5px 0 0 0; + font-weight: bold; +} + +.ms-options-wrap > .ms-options > ul label { + position: relative; + display: inline-block; + width: 100%; + padding: 4px; + margin: 1px 0; +} + +.ms-options-wrap > .ms-options > ul li.selected label, +.ms-options-wrap > .ms-options > ul label:hover { + background-color: #efefef; +} + +.ms-options-wrap > .ms-options > ul input[type="checkbox"] { + margin-right: 5px; + position: absolute; + left: 4px; +/* top: 7px; */ +} \ No newline at end of file diff --git a/js/multiselect/multiselect.js b/js/multiselect/multiselect.js new file mode 100644 index 00000000..c71cdaf9 --- /dev/null +++ b/js/multiselect/multiselect.js @@ -0,0 +1,557 @@ +/** + * Display a nice easy to use multiselect list + * @Version: 2.0 + * @Author: Patrick Springstubbe + * @Contact: @JediNobleclem + * @Website: springstubbe.us + * @Source: https://github.com/nobleclem/jQuery-MultiSelect + * @Notes: If select list is hidden on page load use the jquery.actual plugin + * to resolve issues with preselected items placeholder text + * https://github.com/dreamerslab/jquery.actual + * + * Usage: + * $('select[multiple]').multiselect(); + * $('select[multiple]').multiselect({ placeholder: 'Select options' }); + * $('select[multiple]').multiselect('reload'); + * $('select[multiple]').multiselect( 'loadOption', [{ + * name : 'Option Name 1', + * value : 'option-value-1', + * checked: false + * },{ + * name : 'Option Name 2', + * value : 'option-value-2', + * checked: false + * }]); + * + **/ +(function($){ + var defaults = { + placeholder : 'Select options', // text to use in dummy input + columns : 1, // how many columns should be use to show options + search : false, // include option search box + // search filter options + searchOptions : { + 'default' : 'Search', // search input placeholder text + showOptGroups: false, // show option group titles if no options remaining + onSearch : function( element ){} // fires on keyup before search on options happens + }, + selectAll : false, // add select all option + selectGroup : false, // select entire optgroup + minHeight : 200, // minimum height of option overlay + maxHeight : null, // maximum height of option overlay + showCheckbox : true, // display the checkbox to the user + jqActualOpts : {}, // options for jquery.actual + + // Callbacks + onLoad : function( element ) { // fires at end of list initialization + $(element).hide(); + }, + onOptionClick : function( element, option ){}, // fires when an option is clicked + + // @NOTE: these are for future development + maxWidth : null, // maximum width of option overlay (or selector) + minSelect : false, // minimum number of items that can be selected + maxSelect : false, // maximum number of items that can be selected + }; + + var msCounter = 1; + var placeWidth = 0; + + function MultiSelect( element, options ) + { + this.element = element; + this.options = $.extend( {}, defaults, options ); + this.load(); + } + + MultiSelect.prototype = { + /* LOAD CUSTOM MULTISELECT DOM/ACTIONS */ + load: function() { + var instance = this; + + // make sure this is a select list and not loaded + if( (instance.element.nodeName != 'SELECT') || $(instance.element).hasClass('jqmsLoaded') ) { + return true; + } + + // sanity check so we don't double load on a select element + $(instance.element).addClass('jqmsLoaded'); + + // add option container + $(instance.element).after('
    '); + var placeholder = $(instance.element).next('.ms-options-wrap').find('> button:first-child'); + var optionsWrap = $(instance.element).next('.ms-options-wrap').find('> .ms-options'); + var optionsList = optionsWrap.find('> ul'); + var hasOptGroup = $(instance.element).find('optgroup').length ? true : false; + + var maxWidth = null; + if( typeof instance.options.width == 'number' ) { + optionsWrap.parent().css( 'position', 'relative' ); + maxWidth = instance.options.width; + } + else if( typeof instance.options.width == 'string' ) { + $( instance.options.width ).css( 'position', 'relative' ); + maxWidth = '100%'; + } + else { + optionsWrap.parent().css( 'position', 'relative' ); + } + + var maxHeight = ($(window).height() - optionsWrap.offset().top - 20); + if( instance.options.maxHeight ) { + maxHeight = ($(window).height() - optionsWrap.offset().top - 20); + maxHeight = maxHeight < instance.options.minHeight ? instance.options.minHeight : maxheight; + } + + maxHeight = maxHeight < instance.options.minHeight ? instance.options.minHeight : maxHeight; + + optionsWrap.css({ + maxWidth : maxWidth, + minHeight: instance.options.minHeight, + maxHeight: maxHeight, + overflow : 'auto' + }).hide(); + + // isolate options scroll + // @source: https://github.com/nobleclem/jQuery-IsolatedScroll + optionsWrap.bind( 'touchmove mousewheel DOMMouseScroll', function ( e ) { + if( ($(this).outerHeight() < $(this)[0].scrollHeight) ) { + var e0 = e.originalEvent, + delta = e0.wheelDelta || -e0.detail; + + if( ($(this).outerHeight() + $(this)[0].scrollTop) > $(this)[0].scrollHeight ) { + e.preventDefault(); + this.scrollTop += ( delta < 0 ? 1 : -1 ); + } + } + }); + + // hide options menus if click happens off of the list placeholder button + $(document).off('click.ms-hideopts').on('click.ms-hideopts', function( event ){ + if( !$(event.target).closest('.ms-options-wrap').length ) { + $('.ms-options-wrap > .ms-options:visible').hide(); + } + }); + + // disable button action + placeholder.bind('mousedown',function( event ){ + // ignore if its not a left click + if( event.which != 1 ) { + return true; + } + + // hide other menus before showing this one + $('.ms-options-wrap > .ms-options:visible').each(function(){ + if( $(this).parent().prev()[0] != optionsWrap.parent().prev()[0] ) { + $(this).hide(); + } + }); + + // show/hide options + optionsWrap.toggle(); + + // recalculate height + if( optionsWrap.is(':visible') ) { + optionsWrap.css( 'maxHeight', '' ); + + var maxHeight = ($(window).height() - optionsWrap.offset().top - 20); + if( instance.options.maxHeight ) { + maxHeight = ($(window).height() - optionsWrap.offset().top - 20); + maxHeight = maxHeight < instance.options.minHeight ? instance.options.minHeight : maxheight; + } + maxHeight = maxHeight < instance.options.minHeight ? instance.options.minHeight : maxHeight; + + optionsWrap.css( 'maxHeight', maxHeight ); + } + }).click(function( event ){ event.preventDefault(); }); + + // add placeholder copy + if( instance.options.placeholder ) { + placeholder.text( instance.options.placeholder ); + } + + // add search box + if( instance.options.search ) { + optionsList.before(''); + + var search = optionsWrap.find('.ms-search input'); + search.on('keyup', function(){ + // ignore keystrokes that don't make a difference + if( $(this).data('lastsearch') == $(this).val() ) { + return true; + } + + $(this).data('lastsearch', $(this).val() ); + + // USER CALLBACK + if( typeof instance.options.searchOptions.onSearch == 'function' ) { + instance.options.searchOptions.onSearch( instance.element ); + } + + // search non optgroup li's + optionsList.find('li:not(.optgroup)').each(function(){ + var optText = $(this).text(); + + // show option if string exists + if( optText.toLowerCase().indexOf( search.val().toLowerCase() ) > -1 ) { + $(this).show(); + } + // don't hide selected items + else if( !$(this).hasClass('selected') ) { + $(this).hide(); + } + + // hide / show optgroups depending on if options within it are visible + if( !instance.options.searchOptions.showOptGroups && $(this).closest('li.optgroup') ) { + $(this).closest('li.optgroup').show(); + + if( $(this).closest('li.optgroup').find('li:visible').length ) { + $(this).closest('li.optgroup').show(); + } + else { + $(this).closest('li.optgroup').hide(); + } + } + }); + }); + } + + // add global select all options + if( instance.options.selectAll ) { + optionsList.before('Select all/none'); + } + + // handle select all option + optionsWrap.on('click', '.ms-selectall', function( event ){ + event.preventDefault(); + + if( $(this).hasClass('global') ) { + // check if any selected if so then select them + if( optionsList.find('li:not(.optgroup)').filter(':not(.selected)').length ) { + optionsList.find('li:not(.optgroup)').filter(':not(.selected)').find('input[type="checkbox"]').trigger('click'); + } + // deselect everything + else { + optionsList.find('li:not(.optgroup).selected input[type="checkbox"]').trigger('click'); + } + } + else if( $(this).closest('li').hasClass('optgroup') ) { + var optgroup = $(this).closest('li.optgroup'); + + // check if any selected if so then select them + if( optgroup.find('li:not(.selected)').length ) { + optgroup.find('li:not(.selected) input[type="checkbox"]').trigger('click'); + } + // deselect everything + else { + optgroup.find('li.selected input[type="checkbox"]').trigger('click'); + } + } + }); + + // add options to wrapper + var options = []; + $(instance.element).children().each(function(){ + if( this.nodeName == 'OPTGROUP' ) { + var groupOptions = []; + + $(this).children('option').each(function(){ + groupOptions[ $(this).val() ] = { + name : $(this).text(), + value : $(this).val(), + checked: $(this).prop( 'selected' ) + }; + }); + + options.push({ + label : $(this).attr('label'), + options: groupOptions + }); + } + else if( this.nodeName == 'OPTION' ) { + options.push({ + name : $(this).text(), + value : $(this).val(), + checked: $(this).prop( 'selected' ) + }); + } + else { + // bad option + return true; + } + }); + instance.loadOptions( options ); + + // COLUMNIZE + if( hasOptGroup ) { + // float non grouped options + optionsList.find('> li:not(.optgroup)').css({ + float: 'left', + width: (100 / instance.options.columns) +'%' + }); + + // add CSS3 column styles + optionsList.find('li.optgroup').css({ + clear: 'both' + }).find('> ul').css({ + 'column-count' : instance.options.columns, + 'column-gap' : 0, + '-webkit-column-count': instance.options.columns, + '-webkit-column-gap' : 0, + '-moz-column-count' : instance.options.columns, + '-moz-column-gap' : 0 + }); + + // for crappy IE versions float grouped options + if( this._ieVersion() && (this._ieVersion() < 10) ) { + optionsList.find('li.optgroup > ul > li').css({ + float: 'left', + width: (100 / instance.options.columns) +'%' + }); + } + } + else { + // add CSS3 column styles + optionsList.css({ + 'column-count' : instance.options.columns, + 'column-gap' : 0, + '-webkit-column-count': instance.options.columns, + '-webkit-column-gap' : 0, + '-moz-column-count' : instance.options.columns, + '-moz-column-gap' : 0 + }); + + // for crappy IE versions float grouped options + if( this._ieVersion() && (this._ieVersion() < 10) ) { + optionsList.find('> li').css({ + float: 'left', + width: (100 / instance.options.columns) +'%' + }); + } + } + + // BIND SELECT ACTION + optionsWrap.on( 'click', 'input[type="checkbox"]', function(){ + $(this).closest( 'li' ).toggleClass( 'selected' ); + + var select = optionsWrap.parent().prev(); + + // toggle clicked option + select.find('option[value="'+ $(this).val() +'"]').prop( + 'selected', $(this).is(':checked') + ).closest('select').trigger('change'); + + if( typeof instance.options.onOptionClick == 'function' ) { + instance.options.onOptionClick(); + } + + instance._updatePlaceholderText(); + }); + + // hide native select list + if( typeof instance.options.onLoad === 'function' ) { + instance.options.onLoad( instance.element ); + } + else { + $(instance.element).hide(); + } + }, + + /* LOAD SELECT OPTIONS */ + loadOptions: function( options, overwrite ) { + overwrite = (typeof overwrite == 'boolean') ? overwrite : true; + + var instance = this; + var optionsList = $(instance.element).next('.ms-options-wrap').find('> .ms-options > ul'); + + if( overwrite ) { + optionsList.find('> li').remove(); + } + + for( var key in options ) { + var thisOption = options[ key ]; + var container = $('
  • '); + + // optgroup + if( thisOption.hasOwnProperty('options') ) { + container.addClass('optgroup'); + container.append(''+ thisOption.label +''); + container.find('> .label').css({ + clear: 'both' + }); + + if( instance.options.selectGroup ) { + container.append('Select all') + } + + container.append(''); + + for( var gKey in thisOption.options ) { + var thisGOption = thisOption.options[ gKey ]; + var gContainer = $('
  • ').addClass('ms-reflow'); + + instance._addOption( gContainer, thisGOption ); + + container.find('> ul').append( gContainer ); + } + } + // option + else if( thisOption.hasOwnProperty('value') ) { + container.addClass('ms-reflow') + + instance._addOption( container, thisOption ); + } + + optionsList.append( container ); + } + + optionsList.find('.ms-reflow input[type="checkbox"]').each(function( idx ){ + if( $(this).css('display').match(/block$/) ) { + var checkboxWidth = $(this).outerWidth(); + checkboxWidth = checkboxWidth ? checkboxWidth : 15; + + $(this).closest('label').css( + 'padding-left', + (parseInt( $(this).closest('label').css('padding-left') ) * 2) + checkboxWidth + ); + + $(this).closest('.ms-reflow').removeClass('ms-reflow'); + } + }); + + instance._updatePlaceholderText(); + }, + + /* RESET THE DOM */ + unload: function() { + $(this.element).next('.ms-options-wrap').remove(); + $(this.element).show(function(){ + $(this).css('display','').removeClass('jqmsLoaded'); + }); + }, + + /* RELOAD JQ MULTISELECT LIST */ + reload: function() { + // remove existing options + $(this.element).next('.ms-options-wrap').remove(); + $(this.element).removeClass('jqmsLoaded'); + + // load element + this.load(); + }, + + /** PRIVATE FUNCTIONS **/ + // update selected placeholder text + _updatePlaceholderText: function(){ + var instance = this; + var placeholder = $(instance.element).next('.ms-options-wrap').find('> button:first-child'); + var optionsWrap = $(instance.element).next('.ms-options-wrap').find('> .ms-options'); + var select = optionsWrap.parent().prev(); + + // get selected options + var selOpts = []; + select.find('option:selected').each(function(){ + selOpts.push( $(this).text() ); + }); + + // UPDATE PLACEHOLDER TEXT WITH OPTIONS SELECTED + placeholder.text( selOpts.join( ', ' ) ); + var copy = placeholder.clone().css({ + display : 'inline', + width : 'auto', + visibility: 'hidden' + }).appendTo( optionsWrap.parent() ); + + // if the jquery.actual plugin is loaded use it to get the widths + var copyWidth = (typeof $.fn.actual !== 'undefined') ? copy.actual( 'width', instance.options.jqActualOpts ) : copy.width(); +// var placeWidth = (typeof $.fn.actual !== 'undefined') ? placeholder.actual( 'width', instance.options.jqActualOpts ) : placeholder.width(); + + // Hacked placeWidth to function for me - CPS + if (placeWidth == 0) { + placeWidth = (typeof $.fn.actual !== 'undefined') ? placeholder.actual( 'width', instance.options.jqActualOpts ) : placeholder.width(); + if (instance.options.maxWidth < placeWidth) { + placeWidth = instance.options.maxWidth; + } + } + + // if copy is larger than button width use "# selected" + if( copyWidth > placeWidth ) { + placeholder.text( selOpts.length +' selected' ); + } + // if options selected then use those + else if( selOpts.length ) { + placeholder.text( selOpts.join( ', ' ) ); + } + // replace placeholder text + else { + placeholder.text( instance.options.placeholder ); + } + + // remove dummy element + copy.remove(); + }, + + // Add option to the custom dom list + _addOption: function( container, option ) { + container.text( option.name ); + container.prepend( + $('') + .val( option.value ) + .attr( 'title', option.name ) + .attr( 'id', 'ms-opt-'+ msCounter ) + ); + + if( option.checked ) { + container.addClass('default'); + container.addClass('selected'); + container.find( 'input[type="checkbox"]' ).prop( 'checked', true ); + } + + var label = $('').attr( 'for', 'ms-opt-'+ msCounter ); + container.wrapInner( label ); + + + if( !this.options.showCheckbox ) { + container.find('input[id="ms-opt-'+ msCounter +'"]').hide(); + } + + msCounter = msCounter + 1; + }, + + // check ie version + _ieVersion: function() { + var myNav = navigator.userAgent.toLowerCase(); + return (myNav.indexOf('msie') != -1) ? parseInt(myNav.split('msie')[1]) : false; + } + }; + + // ENABLE JQUERY PLUGIN FUNCTION + $.fn.multiselect = function( options ){ + var args = arguments; + var ret; + + // menuize each list + if( (options === undefined) || (typeof options === 'object') ) { + return this.each(function(){ + if( !$.data( this, 'plugin_multiselect' ) ) { + $.data( this, 'plugin_multiselect', new MultiSelect( this, options ) ); + } + }); + } else if( (typeof options === 'string') && (options[0] !== '_') && (options !== 'init') ) { + this.each(function(){ + var instance = $.data( this, 'plugin_multiselect' ); + + if( instance instanceof MultiSelect && typeof instance[ options ] === 'function' ) { + ret = instance[ options ].apply( instance, Array.prototype.slice.call( args, 1 ) ); + } + + // special destruct handler + if( options === 'unload' ) { + $.data( this, 'plugin_multiselect', null ); + } + }); + + return ret; + } + }; +}(jQuery)); \ No newline at end of file diff --git a/models/admin/management/index.php b/models/admin/management/index.php index 3ce83211..a30ba06a 100644 --- a/models/admin/management/index.php +++ b/models/admin/management/index.php @@ -99,12 +99,13 @@ class GlmMembersAdmin_management_index extends GlmDataSettingsGeneral public function modelAction ($actionData = false) { $settingsUpdated = false; + $settingsUpdateError = false; // General settings are always stored in a record with ID=1. $id = 1; // Determine if current user can edit configurations - if (!current_user_can('glm_members_configure')) { + if (!current_user_can('glm_members_settings')) { return array( 'status' => false, 'menuItemRedirect' => 'error', @@ -131,6 +132,8 @@ class GlmMembersAdmin_management_index extends GlmDataSettingsGeneral $generalSettings = $this->updateEntry(1); if ($generalSettings['status']) { $settingsUpdated = true; + } else { + $settingsUpdateError = true; } break; @@ -165,11 +168,11 @@ class GlmMembersAdmin_management_index extends GlmDataSettingsGeneral // Compile template data $templateData = array( - 'gitBranch' => $gitBranch, 'reason' => '', 'genSettings' => $generalSettings, 'timezones' => DateTimeZone::listIdentifiers(), - 'settingsUpdated' => $settingsUpdated + 'settingsUpdated' => $settingsUpdated, + 'settingsUpdateError' => $settingsUpdateError ); // Return status, suggested view, and data to controller diff --git a/models/admin/management/terms.php b/models/admin/management/terms.php index 2f389613..42e37c00 100644 --- a/models/admin/management/terms.php +++ b/models/admin/management/terms.php @@ -102,7 +102,7 @@ class GlmMembersAdmin_management_terms extends GlmDataSettingsTerms $id = 1; // Determine if current user can edit configurations - if (!current_user_can('glm_members_configure')) { + if (!current_user_can('glm_members_settings')) { return array( 'status' => false, 'menuItemRedirect' => 'error', diff --git a/models/admin/members/list.php b/models/admin/members/list.php index cc81f7cc..b46a274e 100644 --- a/models/admin/members/list.php +++ b/models/admin/members/list.php @@ -103,10 +103,10 @@ class GlmMembersAdmin_members_list extends GlmDataMembers */ public function modelAction ($actionData = false) { + $where = ' true '; $filterPending = false; $filterArchived = false; - $filterCat = false; $haveFilter = false; // Check if this is a request to show archived members @@ -125,9 +125,25 @@ class GlmMembersAdmin_members_list extends GlmDataMembers $Categories = new GlmDataCategories($this->wpdb, $this->config); $categories = $Categories->getListSortedParentChild(false); - // Check if there is a category filter - if (isset($_REQUEST['filterCategory'])) { - $filterCat = ($_REQUEST['filterCategory'] - 0); + // Add "selected" element default false; + reset($categories); + while (list($k, $v) = each($categories)) { + $categories[$k]['selected'] = false; + } + + // Check if there is a category filter (multi-select) + if (isset($_REQUEST['filterCategories']) && count($_REQUEST['filterCategories']) > 0) { + + $cats = ''; + $catsSep = ''; + + // For each selected category + foreach($_REQUEST['filterCategories'] as $c) { + $cats .= $catsSep.$c; + $catsSep = ','; + $categories[$c]['selected'] = true; + } + $where .= " AND T.id in ( SELECT DISTINCT(I.member) FROM ".GLM_MEMBERS_PLUGIN_DB_PREFIX."member_info I, @@ -135,36 +151,30 @@ class GlmMembersAdmin_members_list extends GlmDataMembers ".GLM_MEMBERS_PLUGIN_DB_PREFIX."categories C WHERE I.id = M.member_info AND ( - M.category = $filterCat - OR (C.parent = $filterCat AND M.category = C.id) + M.category in ($cats) + OR (C.parent in ($cats) AND M.category = C.id) ) )"; } - - // Get a current list of members - $list = $this->getSimpleMembersList($where); - - /* - * Check for list filters - * - * Note that since the pointer processing in the data abstract takes place after the - * query of the table data, and that the pending value is actually a sum() of the - * id field values for member_info table generated using the pointer p_sum options, - * we can't use a common where clause to select it. - */ + // Check for "Pending Only if (isset($_REQUEST['filterPending'])) { - foreach($list as $k => $v) { - if ($v['pending'] == 0) { - unset($list[$k]); - } - } + // Refine search only to members with pending Info data + $where .= " AND ( + SELECT COUNT(id) + FROM ".GLM_MEMBERS_PLUGIN_DB_PREFIX."member_info I + WHERE I.status = ".$this->config['status_numb']['Pending']." + AND I.member = T.id + )"; $filterPending = true; $haveFilter = true; } + // Get a current list of members + $list = $this->getSimpleMembersList($where); + if (GLM_MEMBERS_PLUGIN_ADMIN_DEBUG_VERBOSE) { glmMembersAdmin::addNotice($list, 'DataBlock', 'Member Data'); } @@ -179,6 +189,8 @@ class GlmMembersAdmin_members_list extends GlmDataMembers // If we have any entries if (count($list) > 0) { $haveMembers = true; + + $memberCount = count($list); } } @@ -189,12 +201,11 @@ class GlmMembersAdmin_members_list extends GlmDataMembers $templateData = array( 'haveMembers' => $haveMembers, 'members' => $list, + 'memberCount' => $memberCount, 'categories' => $categories, 'haveFilter' => $haveFilter, 'filterArchived' => $filterArchived, - 'filterPending' => $filterPending, - 'filterCat' => $filterCat, -// 'canEdit' => $canEdit + 'filterPending' => $filterPending ); // Return status, suggested view, and data to controller diff --git a/models/admin/configure/amenities.php b/models/admin/settings/amenities.php similarity index 97% rename from models/admin/configure/amenities.php rename to models/admin/settings/amenities.php index 0d0cacf5..9c154491 100644 --- a/models/admin/configure/amenities.php +++ b/models/admin/settings/amenities.php @@ -21,7 +21,7 @@ require_once(GLM_MEMBERS_PLUGIN_CLASS_PATH.'/data/dataAmenities.php'); * option, which is to display the members dashboard. * */ -class GlmMembersAdmin_configure_amenities extends GlmDataAmenities +class GlmMembersAdmin_settings_amenities extends GlmDataAmenities { /** @@ -32,7 +32,7 @@ class GlmMembersAdmin_configure_amenities extends GlmDataAmenities */ public $wpdb; /** - * Plugin Configuration Data + * Plugin Settings Data * * @var $config * @access public @@ -226,7 +226,7 @@ class GlmMembersAdmin_configure_amenities extends GlmDataAmenities 'status' => $success, 'menuItemRedirect' => false, 'modelRedirect' => false, - 'view' => 'admin/configure/amenities.html', + 'view' => 'admin/settings/amenities.html', 'data' => $templateData ); diff --git a/models/admin/configure/categories.php b/models/admin/settings/categories.php similarity index 97% rename from models/admin/configure/categories.php rename to models/admin/settings/categories.php index b1b23efd..0e043314 100644 --- a/models/admin/configure/categories.php +++ b/models/admin/settings/categories.php @@ -21,7 +21,7 @@ require_once(GLM_MEMBERS_PLUGIN_CLASS_PATH.'/data/dataCategories.php'); * option, which is to display the members dashboard. * */ -class GlmMembersAdmin_configure_categories extends GlmDataCategories +class GlmMembersAdmin_settings_categories extends GlmDataCategories { /** @@ -192,7 +192,7 @@ class GlmMembersAdmin_configure_categories extends GlmDataCategories 'status' => $success, 'menuItemRedirect' => false, 'modelRedirect' => false, - 'view' => 'admin/configure/categories.html', + 'view' => 'admin/settings/categories.html', 'data' => $templateData ); diff --git a/models/admin/configure/cities.php b/models/admin/settings/cities.php similarity index 97% rename from models/admin/configure/cities.php rename to models/admin/settings/cities.php index d7217088..e30e53ee 100644 --- a/models/admin/configure/cities.php +++ b/models/admin/settings/cities.php @@ -21,7 +21,7 @@ require_once(GLM_MEMBERS_PLUGIN_CLASS_PATH.'/data/dataCities.php'); * option, which is to display the members dashboard. * */ -class GlmMembersAdmin_configure_cities extends GlmDataCities +class GlmMembersAdmin_settings_cities extends GlmDataCities { /** @@ -181,7 +181,7 @@ class GlmMembersAdmin_configure_cities extends GlmDataCities 'status' => $success, 'menuItemRedirect' => false, 'modelRedirect' => false, - 'view' => 'admin/configure/cities.html', + 'view' => 'admin/settings/cities.html', 'data' => $templateData ); diff --git a/models/admin/configure/index.php b/models/admin/settings/index.php similarity index 97% rename from models/admin/configure/index.php rename to models/admin/settings/index.php index d6ecc937..cc2e273f 100644 --- a/models/admin/configure/index.php +++ b/models/admin/settings/index.php @@ -21,7 +21,7 @@ require_once(GLM_MEMBERS_PLUGIN_CLASS_PATH.'/data/dataMemberTypes.php'); * option, which is to display the members dashboard. * */ -class GlmMembersAdmin_configure_index extends GlmDataMemberTypes +class GlmMembersAdmin_settings_index extends GlmDataMemberTypes { /** @@ -195,7 +195,7 @@ class GlmMembersAdmin_configure_index extends GlmDataMemberTypes 'status' => $success, 'menuItemRedirect' => false, 'modelRedirect' => false, - 'view' => 'admin/configure/index.html', + 'view' => 'admin/settings/index.html', 'data' => $templateData ); diff --git a/models/admin/configure/regions.php b/models/admin/settings/regions.php similarity index 97% rename from models/admin/configure/regions.php rename to models/admin/settings/regions.php index f2f6fbee..72d1e8be 100644 --- a/models/admin/configure/regions.php +++ b/models/admin/settings/regions.php @@ -21,7 +21,7 @@ require_once(GLM_MEMBERS_PLUGIN_CLASS_PATH.'/data/dataRegions.php'); * option, which is to display the members dashboard. * */ -class GlmMembersAdmin_configure_regions extends GlmDataRegions +class GlmMembersAdmin_settings_regions extends GlmDataRegions { /** @@ -181,7 +181,7 @@ class GlmMembersAdmin_configure_regions extends GlmDataRegions 'status' => $success, 'menuItemRedirect' => false, 'modelRedirect' => false, - 'view' => 'admin/configure/regions.html', + 'view' => 'admin/settings/regions.html', 'data' => $templateData ); diff --git a/setup/adminMenus.php b/setup/adminMenus.php new file mode 100644 index 00000000..9cb7c9e9 --- /dev/null +++ b/setup/adminMenus.php @@ -0,0 +1,122 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release admin.php,v 1.0 2014/10/31 19:31:47 cscott Exp $ + * @link http://dev.gaslightmedia.com/ + */ + +/* + * Added menus or sub-menus examples + * + * add_submenu_page( + * 'glm-members-admin-menu-members', // Parent slug + * 'Sample', // Page title + * 'Sample', // Menu Title + * 'glm_members_edit', // Capability required + * 'glm-members-admin-menu-sample', // Menu slug + * function() {$this->controller('sample');} + * ); + * + * If creating a main menu item with add_menu_page(), please document + * that structure here. + * + */ + + +// If user can manage all members, then show "Members" menu item +if (apply_filters('glm_members_menu_members', true)) { + + $mainMenuSlug = 'glm-members-admin-menu-members'; + + add_menu_page( + 'Members', + 'Members', + 'glm_members_main_menu', + 'glm-members-admin-menu-members', + function() {$this->controller('members');}, + false, + '91.123' + ); + + // Add a sub-submenu for the "Member" "List" page + add_submenu_page( + 'glm-members-admin-menu-members', + 'Members List', + '    List', + 'glm_members_main_menu', + 'glm-members-admin-menu-members-list', + function() {$this->controller('members', 'list');} + ); + + // Add a submenu for the "Member" section + if (apply_filters('glm_members_menu_member', true)) { + add_submenu_page( + $mainMenuSlug, + 'Member Dashboard', + 'Member', + 'glm_members_member', + 'glm-members-admin-menu-member', + function() {$this->controller('member');} + ); + } + +// Otherwise just display "Member" menu item +} else { + + $mainMenuSlug = 'glm-members-admin-menu-member'; + + add_menu_page( + 'Member', + 'Member', + 'glm_members_main_menu', + 'glm-members-admin-menu-member', + function() {$this->controller('member');}, + false, + '91.123' + ); + +} + +// Add a submenu for the "Settings" section +if (apply_filters('glm_members_menu_settings', true)) { + add_submenu_page( + 'glm-members-admin-menu-members', + 'Settings', + 'Settings', + 'glm_members_settings', + 'glm-members-admin-menu-settings', + function() {$this->controller('settings');} + ); +} + +// Add a submenu for the "Management" section +if (apply_filters('glm_members_menu_meanagement', true)) { + add_submenu_page( + 'glm-members-admin-menu-members', + 'Member DB Management', + 'Management', + 'glm_members_management', + 'glm-members-admin-menu-management', + function() {$this->controller('management');} + ); +} + +// Add a submenu for the "Shortcode Reference" section +if (apply_filters('glm_members_menu_shortcodes', true)) { + add_submenu_page( + 'glm-members-admin-menu-members', + 'Shortcode Reference', + 'Shortcodes', + 'glm_members_shortcodes', + 'glm-members-admin-menu-shortcodes', + function() {$this->controller('shortcodes');} + ); +} diff --git a/setup/validActions.php b/setup/validActions.php index 9d459272..f3b9208c 100644 --- a/setup/validActions.php +++ b/setup/validActions.php @@ -51,7 +51,7 @@ $glmMembersValidActions = array( 'locations' => 'glm-member-db' ) , - 'configure' => array( + 'settings' => array( 'index' => 'glm-member-db', // Member Types 'categories' => 'glm-member-db', 'cities' => 'glm-member-db', diff --git a/views/admin/member/memberInfo.html b/views/admin/member/memberInfo.html index cd1bea91..6f697035 100644 --- a/views/admin/member/memberInfo.html +++ b/views/admin/member/memberInfo.html @@ -489,8 +489,7 @@ - - +
    Delete:
    Selected Image:
    Featured Image:
    featured Image:
    New Upload
    @@ -516,7 +515,7 @@
    Drag and drop new images here
    HTML5 file drag-and-drop not supported by your browser.
    Use "Browse" button above to upload an image.
    -
    No Selected Image:
     
    +
    No Featured Image: