Make WordPress Core

Ticket #5618: 5618.diff

File 5618.diff, 37.3 KB (added by mdawaffe, 17 years ago)
  • wp-includes/js/jquery/ui.tabs.js

     
     1/*
     2 * Tabs 3 - New Wave Tabs
     3 *
     4 * Copyright (c) 2007 Klaus Hartl (stilbuero.de)
     5 * Dual licensed under the MIT (MIT-LICENSE.txt)
     6 * and GPL (GPL-LICENSE.txt) licenses.
     7 */
     8
     9(function($) {
     10
     11    // if the UI scope is not availalable, add it
     12    $.ui = $.ui || {};
     13
     14    // tabs initialization
     15    $.fn.tabs = function(initial, options) {
     16        if (initial && initial.constructor == Object) { // shift arguments
     17            options = initial;
     18            initial = null;
     19        }
     20        options = options || {};
     21
     22        initial = initial && initial.constructor == Number && --initial || 0;
     23
     24        return this.each(function() {
     25            new $.ui.tabs(this, $.extend(options, { initial: initial }));
     26        });
     27    };
     28
     29    // other chainable tabs methods
     30    $.each(['Add', 'Remove', 'Enable', 'Disable', 'Click', 'Load', 'Href'], function(i, method) {
     31        $.fn['tabs' + method] = function() {
     32            var args = arguments;
     33            return this.each(function() {
     34                var instance = $.ui.tabs.getInstance(this);
     35                instance[method.toLowerCase()].apply(instance, args);
     36            });
     37        };
     38    });
     39    $.fn.tabsSelected = function() {
     40        var selected = -1;
     41        if (this[0]) {
     42            var instance = $.ui.tabs.getInstance(this[0]),
     43                $lis = $('li', this);
     44            selected = $lis.index( $lis.filter('.' + instance.options.selectedClass)[0] );
     45        }
     46        return selected >= 0 ? ++selected : -1;
     47    };
     48
     49    // tabs class
     50    $.ui.tabs = function(el, options) {
     51
     52        this.source = el;
     53
     54        this.options = $.extend({
     55
     56            // basic setup
     57            initial: 0,
     58            event: 'click',
     59            disabled: [],
     60            cookie: null, // pass options object as expected by cookie plugin: { expires: 7, path: '/', domain: 'jquery.com', secure: true }
     61            // TODO bookmarkable: $.ajaxHistory ? true : false,
     62            unselected: false,
     63            unselect: options.unselected ? true : false,
     64
     65            // Ajax
     66            spinner: 'Loading…',
     67            cache: false,
     68            idPrefix: 'ui-tabs-',
     69            ajaxOptions: {},
     70
     71            // animations
     72            /*fxFade: null,
     73            fxSlide: null,
     74            fxShow: null,
     75            fxHide: null,*/
     76            fxSpeed: 'normal',
     77            /*fxShowSpeed: null,
     78            fxHideSpeed: null,*/
     79
     80            // callbacks
     81            add: function() {},
     82            remove: function() {},
     83            enable: function() {},
     84            disable: function() {},
     85            click: function() {},
     86            hide: function() {},
     87            show: function() {},
     88            load: function() {},
     89           
     90            // templates
     91            tabTemplate: '<li><a href="#{href}"><span>#{text}</span></a></li>',
     92            panelTemplate: '<div></div>',
     93
     94            // CSS classes
     95            navClass: 'ui-tabs-nav',
     96            selectedClass: 'ui-tabs-selected',
     97            unselectClass: 'ui-tabs-unselect',
     98            disabledClass: 'ui-tabs-disabled',
     99            panelClass: 'ui-tabs-panel',
     100            hideClass: 'ui-tabs-hide',
     101            loadingClass: 'ui-tabs-loading'
     102
     103        }, options);
     104
     105        this.options.event += '.ui-tabs'; // namespace event
     106        this.options.cookie = $.cookie && $.cookie.constructor == Function && this.options.cookie;
     107
     108        // save instance for later
     109        $.data(el, $.ui.tabs.INSTANCE_KEY, this);
     110       
     111        // create tabs
     112        this.tabify(true);
     113    };
     114
     115    // static
     116    $.ui.tabs.INSTANCE_KEY = 'ui_tabs_instance';
     117    $.ui.tabs.getInstance = function(el) {
     118        return $.data(el, $.ui.tabs.INSTANCE_KEY);
     119    };
     120
     121    // instance methods
     122    $.extend($.ui.tabs.prototype, {
     123        tabId: function(a) {
     124            return a.title ? a.title.replace(/\s/g, '_')
     125                : this.options.idPrefix + $.data(a);
     126        },
     127        tabify: function(init) {
     128
     129            this.$lis = $('li:has(a[href])', this.source);
     130            this.$tabs = this.$lis.map(function() { return $('a', this)[0] });
     131            this.$panels = $([]);
     132           
     133            var self = this, o = this.options;
     134           
     135            this.$tabs.each(function(i, a) {
     136                // inline tab
     137                if (a.hash && a.hash.replace('#', '')) { // Safari 2 reports '#' for an empty hash
     138                    self.$panels = self.$panels.add(a.hash);
     139                }
     140                // remote tab
     141                else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#"
     142                    $.data(a, 'href', a.href);
     143                    var id = self.tabId(a);
     144                    a.href = '#' + id;
     145                    self.$panels = self.$panels.add(
     146                        $('#' + id)[0] || $(o.panelTemplate).attr('id', id).addClass(o.panelClass)
     147                            .insertAfter( self.$panels[i - 1] || self.source )
     148                    );
     149                }
     150                // invalid tab href
     151                else {
     152                    o.disabled.push(i + 1);
     153                }
     154            });
     155
     156            if (init) {
     157
     158                // attach necessary classes for styling if not present
     159                $(this.source).hasClass(o.navClass) || $(this.source).addClass(o.navClass);
     160                this.$panels.each(function() {
     161                    var $this = $(this);
     162                    $this.hasClass(o.panelClass) || $this.addClass(o.panelClass);
     163                });
     164               
     165                // disabled tabs
     166                for (var i = 0, position; position = o.disabled[i]; i++) {
     167                    this.disable(position);
     168                }
     169               
     170                // Try to retrieve initial tab:
     171                // 1. from fragment identifier in url if present
     172                // 2. from cookie
     173                // 3. from selected class attribute on <li>
     174                // 4. otherwise use given initial argument
     175                // 5. check if tab is disabled
     176                this.$tabs.each(function(i, a) {
     177                    if (location.hash) {
     178                        if (a.hash == location.hash) {
     179                            o.initial = i;
     180                            // prevent page scroll to fragment
     181                            //if (($.browser.msie || $.browser.opera) && !o.remote) {
     182                            if ($.browser.msie || $.browser.opera) {
     183                                var $toShow = $(location.hash), toShowId = $toShow.attr('id');
     184                                $toShow.attr('id', '');
     185                                setTimeout(function() {
     186                                    $toShow.attr('id', toShowId); // restore id
     187                                }, 500);
     188                            }
     189                            scrollTo(0, 0);
     190                            return false; // break
     191                        }
     192                    } else if (o.cookie) {
     193                        o.initial = parseInt($.cookie( $.ui.tabs.INSTANCE_KEY + $.data(self.source) )) || 0;
     194                        return false; // break
     195                    } else if ( self.$lis.eq(i).hasClass(o.selectedClass) ) {
     196                        o.initial = i;
     197                        return false; // break
     198                    }
     199                });
     200                var n = this.$lis.length;
     201                while (this.$lis.eq(o.initial).hasClass(o.disabledClass) && n) {
     202                    o.initial = ++o.initial < this.$lis.length ? o.initial : 0;
     203                    n--;
     204                }
     205                if (!n) { // all tabs disabled, set option unselected to true
     206                    o.unselected = o.unselect = true;
     207                }
     208
     209                // highlight selected tab
     210                this.$panels.addClass(o.hideClass);
     211                this.$lis.removeClass(o.selectedClass);
     212                if (!o.unselected) {
     213                    this.$panels.eq(o.initial).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before
     214                    this.$lis.eq(o.initial).addClass(o.selectedClass);
     215                }
     216
     217                // load if remote tab
     218                var href = !o.unselected && $.data(this.$tabs[o.initial], 'href');
     219                if (href) {
     220                    this.load(o.initial + 1, href);
     221                }
     222               
     223                // disable click if event is configured to something else
     224                if (!/^click/.test(o.event)) {
     225                    this.$tabs.bind('click', function(e) { e.preventDefault(); });
     226                }
     227
     228            }
     229
     230            // setup animations
     231            var showAnim = {}, showSpeed = o.fxShowSpeed || o.fxSpeed,
     232                hideAnim = {}, hideSpeed = o.fxHideSpeed || o.fxSpeed;
     233            if (o.fxSlide || o.fxFade) {
     234                if (o.fxSlide) {
     235                    showAnim['height'] = 'show';
     236                    hideAnim['height'] = 'hide';
     237                }
     238                if (o.fxFade) {
     239                    showAnim['opacity'] = 'show';
     240                    hideAnim['opacity'] = 'hide';
     241                }
     242            } else {
     243                if (o.fxShow) {
     244                    showAnim = o.fxShow;
     245                } else { // use some kind of animation to prevent browser scrolling to the tab
     246                    showAnim['min-width'] = 0; // avoid opacity, causes flicker in Firefox
     247                    showSpeed = 1; // as little as 1 is sufficient
     248                }
     249                if (o.fxHide) {
     250                    hideAnim = o.fxHide;
     251                } else { // use some kind of animation to prevent browser scrolling to the tab
     252                    hideAnim['min-width'] = 0; // avoid opacity, causes flicker in Firefox
     253                    hideSpeed = 1; // as little as 1 is sufficient
     254                }
     255            }
     256
     257            // reset some styles to maintain print style sheets etc.
     258            var resetCSS = { display: '', overflow: '', height: '' };
     259            if (!$.browser.msie) { // not in IE to prevent ClearType font issue
     260                resetCSS['opacity'] = '';
     261            }
     262
     263            // Hide a tab, animation prevents browser scrolling to fragment,
     264            // $show is optional.
     265            function hideTab(clicked, $hide, $show) {
     266                $hide.animate(hideAnim, hideSpeed, function() { //
     267                    $hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
     268                    if ($.browser.msie && hideAnim['opacity']) {
     269                        $hide[0].style.filter = '';
     270                    }
     271                    o.hide(clicked, $hide[0], $show && $show[0] || null);
     272                    if ($show) {
     273                        showTab(clicked, $show, $hide);
     274                    }
     275                });
     276            }
     277
     278            // Show a tab, animation prevents browser scrolling to fragment,
     279            // $hide is optional
     280            function showTab(clicked, $show, $hide) {
     281                if (!(o.fxSlide || o.fxFade || o.fxShow)) {
     282                    $show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels
     283                }
     284                $show.animate(showAnim, showSpeed, function() {
     285                    $show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
     286                    if ($.browser.msie && showAnim['opacity']) {
     287                        $show[0].style.filter = '';
     288                    }
     289                    o.show(clicked, $show[0], $hide && $hide[0] || null);
     290                });
     291            }
     292
     293            // switch a tab
     294            function switchTab(clicked, $li, $hide, $show) {
     295                /*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click
     296                    $.ajaxHistory.update(clicked.hash);
     297                }*/
     298                $li.addClass(o.selectedClass)
     299                    .siblings().removeClass(o.selectedClass);
     300                hideTab(clicked, $hide, $show);
     301            }
     302
     303            // attach tab event handler, unbind to avoid duplicates from former tabifying...
     304            this.$tabs.unbind(o.event).bind(o.event, function() {
     305
     306                //var trueClick = e.clientX; // add to history only if true click occured, not a triggered click
     307                var $li = $(this).parents('li:eq(0)'),
     308                    $hide = self.$panels.filter(':visible'),
     309                    $show = $(this.hash);
     310
     311                // If tab is already selected and not unselectable or tab disabled or click callback returns false stop here.
     312                // Check if click handler returns false last so that it is not executed for a disabled tab!
     313                if (($li.hasClass(o.selectedClass) && !o.unselect) || $li.hasClass(o.disabledClass)
     314                    || o.click(this, $show[0], $hide[0]) === false) {
     315                    this.blur();
     316                    return false;
     317                }
     318               
     319                if (o.cookie) {
     320                    $.cookie($.ui.tabs.INSTANCE_KEY + $.data(self.source), self.$tabs.index(this), o.cookie);
     321                }
     322                   
     323                // if tab may be closed
     324                if (o.unselect) {
     325                    if ($li.hasClass(o.selectedClass)) {
     326                        $li.removeClass(o.selectedClass);
     327                        self.$panels.stop();
     328                        hideTab(this, $hide);
     329                        this.blur();
     330                        return false;
     331                    } else if (!$hide.length) {
     332                        self.$panels.stop();
     333                        if ($.data(this, 'href')) { // remote tab
     334                            var a = this;
     335                            self.load(self.$tabs.index(this) + 1, $.data(this, 'href'), function() {
     336                                $li.addClass(o.selectedClass).addClass(o.unselectClass);
     337                                showTab(a, $show);
     338                            });
     339                        } else {
     340                            $li.addClass(o.selectedClass).addClass(o.unselectClass);
     341                            showTab(this, $show);
     342                        }
     343                        this.blur();
     344                        return false;
     345                    }
     346                }
     347
     348                // stop possibly running animations
     349                self.$panels.stop();
     350
     351                // show new tab
     352                if ($show.length) {
     353
     354                    // prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled
     355                    /*if ($.browser.msie && o.bookmarkable) {
     356                        var showId = this.hash.replace('#', '');
     357                        $show.attr('id', '');
     358                        setTimeout(function() {
     359                            $show.attr('id', showId); // restore id
     360                        }, 0);
     361                    }*/
     362
     363                    if ($.data(this, 'href')) { // remote tab
     364                        var a = this;
     365                        self.load(self.$tabs.index(this) + 1, $.data(this, 'href'), function() {
     366                            switchTab(a, $li, $hide, $show);
     367                        });
     368                    } else {
     369                        switchTab(this, $li, $hide, $show);
     370                    }
     371
     372                    // Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash
     373                    /*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0;
     374                    var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0;
     375                    setTimeout(function() {
     376                        scrollTo(scrollX, scrollY);
     377                    }, 0);*/
     378
     379                } else {
     380                    throw 'jQuery UI Tabs: Mismatching fragment identifier.';
     381                }
     382
     383                // Prevent IE from keeping other link focussed when using the back button
     384                // and remove dotted border from clicked link. This is controlled in modern
     385                // browsers via CSS, also blur removes focus from address bar in Firefox
     386                // which can become a usability and annoying problem with tabsRotate.
     387                if ($.browser.msie) {
     388                    this.blur();
     389                }
     390
     391                //return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE
     392                return false;
     393
     394            });
     395
     396        },
     397        add: function(url, text, position) {
     398            if (url && text) {
     399                position = position || this.$tabs.length; // append by default 
     400               
     401                var o = this.options,
     402                    $li = $(o.tabTemplate.replace(/#\{href\}/, url).replace(/#\{text\}/, text));
     403               
     404                var id = url.indexOf('#') == 0 ? url.replace('#', '') : this.tabId( $('a:first-child', $li)[0] );
     405               
     406                // try to find an existing element before creating a new one
     407                var $panel = $('#' + id);
     408                $panel = $panel.length && $panel
     409                    || $(o.panelTemplate).attr('id', id).addClass(o.panelClass).addClass(o.hideClass);
     410                if (position >= this.$lis.length) {
     411                    $li.appendTo(this.source);
     412                    $panel.appendTo(this.source.parentNode);
     413                } else {
     414                    $li.insertBefore(this.$lis[position - 1]);
     415                    $panel.insertBefore(this.$panels[position - 1]);
     416                }
     417               
     418                this.tabify();
     419               
     420                if (this.$tabs.length == 1) {
     421                     $li.addClass(o.selectedClass);
     422                     $panel.removeClass(o.hideClass);
     423                     var href = $.data(this.$tabs[0], 'href');
     424                     if (href) {
     425                         this.load(position + 1, href);
     426                     }
     427                }
     428                o.add(this.$tabs[position], this.$panels[position]); // callback
     429            } else {
     430                throw 'jQuery UI Tabs: Not enough arguments to add tab.';
     431            }
     432        },
     433        remove: function(position) {
     434            if (position && position.constructor == Number) {               
     435                var o = this.options, $li = this.$lis.eq(position - 1).remove(),
     436                    $panel = this.$panels.eq(position - 1).remove();
     437                   
     438                // If selected tab was removed focus tab to the right or
     439                // tab to the left if last tab was removed.
     440                if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1) {
     441                    this.click(position + (position < this.$tabs.length ? 1 : -1));
     442                }
     443                this.tabify();
     444                o.remove($li.end()[0], $panel[0]); // callback
     445            }
     446        },
     447        enable: function(position) {
     448            var o = this.options, $li = this.$lis.eq(position - 1);
     449            $li.removeClass(o.disabledClass);
     450            if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...
     451                $li.css('display', 'inline-block');
     452                setTimeout(function() {
     453                    $li.css('display', 'block')
     454                }, 0)
     455            }
     456            o.enable(this.$tabs[position - 1], this.$panels[position - 1]); // callback
     457        },
     458        disable: function(position) {
     459            var o = this.options;     
     460            this.$lis.eq(position - 1).addClass(o.disabledClass);
     461            o.disable(this.$tabs[position - 1], this.$panels[position - 1]); // callback
     462        },
     463        click: function(position) {
     464            this.$tabs.eq(position - 1).trigger(this.options.event);
     465        },
     466        load: function(position, url, callback) {
     467            var self = this, o = this.options,
     468                $a = this.$tabs.eq(position - 1), a = $a[0], $span = $('span', a);
     469           
     470            // shift arguments
     471            if (url && url.constructor == Function) {
     472                callback = url;
     473                url = null;
     474            }
     475
     476            // set new URL or get existing
     477            if (url) {
     478                $.data(a, 'href', url);
     479            } else {
     480                url = $.data(a, 'href');
     481            }
     482
     483            // load
     484            if (o.spinner) {
     485                $.data(a, 'title', $span.html());
     486                $span.html('<em>' + o.spinner + '</em>');
     487            }
     488            var finish = function() {
     489                self.$tabs.filter('.' + o.loadingClass).each(function() {
     490                    $(this).removeClass(o.loadingClass);
     491                    if (o.spinner) {
     492                        $('span', this).html( $.data(this, 'title') );
     493                    }
     494                });
     495                self.xhr = null;
     496            };
     497            var ajaxOptions = $.extend(o.ajaxOptions, {
     498                url: url,
     499                success: function(r) {
     500                    $(a.hash).html(r);
     501                    finish();
     502                    // This callback is required because the switch has to take
     503                    // place after loading has completed.
     504                    if (callback && callback.constructor == Function) {
     505                        callback();
     506                    }
     507                    if (o.cache) {
     508                        $.removeData(a, 'href'); // if loaded once do not load them again
     509                    }
     510                    o.load(self.$tabs[position - 1], self.$panels[position - 1]); // callback
     511                }
     512            });
     513            if (this.xhr) {
     514                // terminate pending requests from other tabs and restore title
     515                this.xhr.abort();
     516                finish();
     517            }
     518            $a.addClass(o.loadingClass);
     519            setTimeout(function() { // timeout is again required in IE, "wait" for id being restored
     520                self.xhr = $.ajax(ajaxOptions);
     521            }, 0);
     522           
     523        },
     524        href: function(position, href) {
     525            $.data(this.$tabs.eq(position - 1)[0], 'href', href);
     526        }
     527    });
     528
     529})(jQuery);
  • wp-includes/js/wp-lists.js

     
    309309                if ( 'none' != s.addColor ) {
    310310                        var b = e.css( 'background-color' );
    311311                        if ( b == 'transparent' ) { b = ''; }
    312                        
    313                         $('#' + s.element).css('background-color', s.addColor).animate( { backgroundColor: '#fff' }, 300 );
     312                        e.css('background-color', s.addColor).animate( { backgroundColor: '#fff' }, 300 );
    314313                }
    315314                list.each( function() { this.wpList.process( e ); } );
    316315                return e;
     
    321320                e = $(e);
    322321                if ( list.wpList && e.parents( '#' + list.id ).size() ) { return; }
    323322                e.find(':input').each( function() {
     323                        if ( $(this).parents('.form-no-clear').size() )
     324                                return;
    324325                        var t = this.type.toLowerCase(); var tag = this.tagName.toLowerCase();
    325326                        if ( 'text' == t || 'password' == t || 'textarea' == tag ) { this.value = ''; }
    326327                        else if ( 'checkbox' == t || 'radio' == t ) { this.checked = false; }
  • wp-includes/script-loader.php

     
    6060                        'delText' => __('Are you sure you want to delete this %thing%?')
    6161                ) );
    6262
    63                 $this->add( 'wp-lists', '/wp-includes/js/wp-lists.js', array('jquery'), '20071101' );
     63                $this->add( 'wp-lists', '/wp-includes/js/wp-lists.js', array('jquery'), '20080109' );
    6464                $this->localize( 'wp-lists', 'wpListL10n', array(
    6565                        'url' => get_option( 'siteurl' ) . '/wp-admin/admin-ajax.php'
    6666                ) );
     
    8585                $this->add( 'schedule', '/wp-includes/js/jquery/jquery.schedule.js', array('jquery'), '20');
    8686                $this->add( 'thickbox', '/wp-includes/js/thickbox/thickbox.js', array('jquery'), '3.1');
    8787
     88                $this->add( 'jquery-ui-tabs', '/wp-includes/js/jquery/ui.tabs.js', array('jquery'), '3' );
     89
    8890                if ( is_admin() ) {
    8991                        $this->add( 'ajaxcat', '/wp-admin/js/cat.js', array( 'wp-lists' ), '20071101' );
    9092                        $this->localize( 'ajaxcat', 'catL10n', array(
     
    106108                        $this->add( 'admin-forms', '/wp-admin/js/forms.js', array('wp-lists'), '20080108' );
    107109                        $this->add( 'xfn', '/wp-admin/js/xfn.js', false, '3517' );
    108110                        $this->add( 'upload', '/wp-admin/js/upload.js', array('jquery'), '20070518' );
    109                         $this->add( 'post', '/wp-admin/js/post.js', array('suggest'), '20080102' );
     111                        $this->add( 'post', '/wp-admin/js/post.js', array('suggest', 'jquery-ui-tabs', 'wp-lists'), '20080109' );
    110112                        $this->localize( 'post', 'postL10n', array(
    111113                                'tagsUsed' =>  __('Tags used on this post:'),
    112114                                'add' => attribute_escape(__('Add')),
     
    137139                                'saveText' => attribute_escape(__('Save &raquo;')),
    138140                                'confirmText' => __("Are you sure you want to delete the file '%title%'?\nClick ok to delete or cancel to go back.")
    139141                        ) );
    140                         $this->add( 'admin-widgets', '/wp-admin/js/widgets.js', array( 'interface' ), mt_rand() );
     142                        $this->add( 'admin-widgets', '/wp-admin/js/widgets.js', array( 'interface' ), '20080109' );
    141143                }
    142144        }
    143145
  • wp-admin/admin-ajax.php

     
    157157        if ( !current_user_can( 'manage_categories' ) )
    158158                die('-1');
    159159        $names = explode(',', $_POST['newcat']);
     160        if ( 0 > $parent = (int) $_POST['newcat_parent'] )
     161                $parent = 0;
     162
     163        $checked_categories = array_map( 'absint', (array) $_POST['post_category'] );
     164
    160165        $x = new WP_Ajax_Response();
    161166        foreach ( $names as $cat_name ) {
    162167                $cat_name = trim($cat_name);
    163168                $category_nicename = sanitize_title($cat_name);
    164169                if ( '' === $category_nicename )
    165170                        continue;
    166                 $cat_id = wp_create_category( $cat_name );
    167                 $cat_name = wp_specialchars(stripslashes($cat_name));
     171                $cat_id = wp_create_category( $cat_name, $parent );
     172                $checked_categories[] = $cat_id;
     173                if ( $parent ) // Do these all at once in a second
     174                        continue;
     175                $category = get_category( $cat_id );
     176                $category->_is_checked = true;
     177                ob_start();
     178                        dropdown_categories( 0, $category );
     179                $data = ob_get_contents();
     180                ob_end_clean();
    168181                $x->add( array(
    169182                        'what' => 'category',
    170183                        'id' => $cat_id,
    171                         'data' => "<li id='category-$cat_id'><label for='in-category-$cat_id' class='selectit'><input value='$cat_id' type='checkbox' checked='checked' name='post_category[]' id='in-category-$cat_id'/> $cat_name</label></li>",
     184                        'data' => $data,
    172185                        'position' => -1
    173186                ) );
    174187        }
     188        if ( $parent ) { // Foncy - replace the parent and all its children
     189                $parent = get_category( $parent );
     190                ob_start();
     191                        dropdown_categories( 0, $parent );
     192                $data = ob_get_contents();
     193                ob_end_clean();
     194                $x->add( array(
     195                        'what' => 'category',
     196                        'id' => $parent->term_id,
     197                        'old_id' => $parent->term_id,
     198                        'data' => $data,
     199                        'position' => -1
     200                ) );
     201
     202        }
    175203        $x->send();
    176204        break;
    177205case 'add-link-category' : // On the Fly
  • wp-admin/wp-admin.css

     
    687687        height: 22px;
    688688}
    689689
    690 #categorydiv ul {
    691         list-style: none;
    692         padding: 0;
    693         margin-left: 10px;
    694 }
    695 
    696 #categorychecklist {
    697         height: 12em;
    698         overflow: auto;
    699         margin-top: 8px;
    700 }
    701 
    702 #categorychecklist li {
    703         margin: 0;
    704         padding: 0;
    705 }
    706 
    707 #ajaxcat input {
    708         border: 1px solid #ccc;
    709 }
    710 
    711690#your-profile #rich_editing {
    712691        border: none;
    713692        background: #fff;
     
    737716        font-size: 22px;
    738717}
    739718
    740 
    741 
    742 #newcat {
    743         width: 120px;
    744         margin-right: 5px;
    745 }
    746 
    747 input #catadd {
    748         background: #a4a4a4;
    749         border-bottom: 1px solid #898989;
    750         border-left: 1px solid #bcbcbc;
    751         border-right: 1px solid #898989;
    752         border-top: 1px solid #bcbcbc;
    753         color: #fff;
    754         font-size: 10px;
    755         padding: 0;
    756         margin: 0;
    757         font-weight: bold;
    758         height: 20px;
    759         margin-bottom: 2px;
    760         text-align: center;
    761         width: 37px;
    762 }
    763 
    764719#howto {
    765720        font-size: 11px;
    766721        margin: 0 5px;
    767722        display: block;
    768723}
    769724
    770 #jaxcat {
    771         margin: 0;
    772         padding: 0;
    773 }
    774 
    775725#ajax-response.alignleft {
    776726        margin-left: 2em;
    777727}
     
    12791229        background-image:url(images/toggle-arrow.gif);
    12801230        background-position: 4px 18px;
    12811231}
     1232
     1233/* Categories */
     1234
     1235#categorydiv #category-adder {
     1236        margin-left: 120px;
     1237        padding: 4px 0;
     1238}
     1239
     1240#category-add input, #category-add select {
     1241        width: 30%;
     1242}
     1243
     1244#categorydiv ul#category-tabs {
     1245        float: left;
     1246        width: 120px;
     1247        text-align: right;
     1248        /* Negative margin for the sake of those without JS: all tabs display */
     1249        margin: 0 -120px 0 0;
     1250        padding: 0;
     1251}
     1252
     1253ul#category-tabs li {
     1254        padding: 8px;
     1255}
     1256
     1257ul#category-tabs li.ui-tabs-selected {
     1258        background-color: #CEE1EF;
     1259}
     1260
     1261div.ui-tabs-panel {
     1262        margin: 0 0 0 120px;
     1263        padding: .5em .9em;
     1264        height: 12em;
     1265        overflow: auto;
     1266        border: 4px solid #CEE1EF;
     1267}
     1268
     1269#categorydiv ul {
     1270        list-style: none;
     1271        padding: 0;
     1272        margin: 0;
     1273}
     1274
     1275#categorydiv ul.categorychecklist ul {
     1276        margin-left: 18px;
     1277}
     1278
     1279ul.categorychecklist li {
     1280        margin: 0;
     1281        padding: 0;
     1282}
     1283
     1284/* Global classes */
     1285.wp-hidden-children .wp-hidden-child { display: none; }
     1286.ui-tabs-hide { display: none; }
  • wp-admin/includes/template.php

     
    118118                return strcasecmp( $cat1['cat_name'], $cat2['cat_name'] );
    119119}
    120120
    121 function get_nested_categories( $default = 0, $parent = 0 ) {
     121function wp_set_checked_post_categories( $default = 0 ) {
    122122        global $post_ID, $checked_categories;
    123123
    124124        if ( empty($checked_categories) ) {
     
    134134                }
    135135        }
    136136
    137         $cats = get_categories("parent=$parent&hide_empty=0&fields=ids");
     137}
     138function get_nested_categories( $default = 0, $parent = 0 ) {
     139        global $checked_categories;
    138140
    139         $result = array ();
    140         if ( is_array( $cats ) ) {
    141                 foreach ( $cats as $cat) {
    142                         $result[$cat]['children'] = get_nested_categories( $default, $cat);
    143                         $result[$cat]['cat_ID'] = $cat;
    144                         $result[$cat]['checked'] = in_array( $cat, $checked_categories );
    145                         $result[$cat]['cat_name'] = get_the_category_by_ID( $cat);
     141        wp_set_checked_post_categories( $default = 0 );
     142
     143        if ( is_object($parent) ) { // Hack: if passed a category object, will return nested cats with parent as root
     144                $root = array(
     145                        'children' => get_nested_categories( $default, $parent->term_id ),
     146                        'cat_ID' => $parent->term_id,
     147                        'checked' => isset($parent->_is_checked) && $parent->_is_checked,
     148                        'cat_name' => get_the_category_by_ID( $parent->term_id )
     149                );
     150                $result = array( $parent->term_id => $root );
     151        } else {
     152                $parent = (int) $parent;
     153
     154                $cats = get_categories("parent=$parent&hide_empty=0&fields=ids");
     155
     156                $result = array();
     157                if ( is_array( $cats ) ) {
     158                        foreach ( $cats as $cat ) {
     159                                $result[$cat]['children'] = get_nested_categories( $default, $cat );
     160                                $result[$cat]['cat_ID'] = $cat;
     161                                $result[$cat]['checked'] = in_array( $cat, $checked_categories );
     162                                $result[$cat]['cat_name'] = get_the_category_by_ID( $cat );
     163                        }
    146164                }
    147165        }
    148166
     
    165183        }
    166184}
    167185
    168 function dropdown_categories( $default = 0 ) {
    169         write_nested_categories( get_nested_categories( $default) );
     186function dropdown_categories( $default = 0, $parent = 0 ) {
     187        write_nested_categories( get_nested_categories( $default, $parent ) );
    170188}
    171189
     190function wp_popular_categories_checklist( $default = 0, $number = 10 ) {
     191        global $checked_categories;
     192
     193        wp_set_checked_post_categories( $default );
     194
     195        $categories = get_categories( array( 'orderby' => 'count', 'order' => 'DESC', 'number' => $number ) );
     196
     197        foreach ( (array) $categories as $category ) {
     198                $id = "popular-category-$category->term_id";
     199                $checked = in_array( $category->term_id, $checked_categories ) ? ' checked="checked"' : '';             
     200                ?>
     201
     202                <li id="<?php echo $id; ?>">
     203                        <label class="selectit" for="in-<?php echo $id; ?>">
     204                                <input id="in-<?php echo $id; ?>" type="checkbox" name="post_category[]" value="<?php echo (int) $category->term_id; ?>"<?php echo $checked; ?> />
     205                                <?php echo wp_specialchars( apply_filters( 'the_category', $category->name ) ); ?>
     206                        </label>
     207                </li>
     208
     209                <?php
     210        }
     211}
     212
    172213function dropdown_link_categories( $default = 0 ) {
    173214        global $link_id;
    174215
  • wp-admin/includes/taxonomy.php

     
    1616        return $category;
    1717}
    1818
    19 function wp_create_category($cat_name) {
     19function wp_create_category( $cat_name, $parent = 0 ) {
    2020        if ( $id = category_exists($cat_name) )
    2121                return $id;
    2222
    23         return wp_insert_category( array('cat_name' => $cat_name) );
     23        return wp_insert_category( array('cat_name' => $cat_name, 'category_parent' => $parent) );
    2424}
    2525
    2626function wp_create_categories($categories, $post_id = '') {
  • wp-admin/js/post.js

     
    9090
    9191        // postboxes
    9292        add_postbox_toggles();
     93
     94        // category tabs
     95        var categoryTabs =jQuery('#category-tabs').tabs();
     96
     97        // Ajax Cat
     98        var newCat = jQuery('#newcat').one( 'focus', function() { jQuery(this).val( '' ) } );
     99        jQuery('#category-add-sumbit').click( function() { newCat.focus(); } );
     100        var catAddAfter = function( r, s ) {
     101                jQuery(s.what + ' response_data', r).each( function() {
     102                        var t = jQuery(jQuery(this).text());
     103                        var o = jQuery( '<option value="' +  parseInt( t.find(':input').val(), 10 ) + '"></option>' );
     104                        o.text( jQuery.trim( t.text() ) );
     105                        jQuery('#newcat_parent').prepend( o );
     106                } );
     107        };
     108        jQuery('#categorychecklist').wpList( {
     109                alt: '',
     110                response: 'category-ajax-response',
     111                addAfter: catAddAfter
     112        } );
     113        jQuery('#category-add-toggle').click( function() {
     114                jQuery(this).parents('div:first').toggleClass( 'wp-hidden-children' );
     115                categoryTabs.tabsClick( 1 );
     116                return false;
     117        } );
    93118});
  • wp-admin/edit-form-advanced.php

     
    121121<div id="categorydiv" class="postbox <?php echo postbox_classes('categorydiv'); ?>">
    122122<h3><?php _e('Categories') ?></h3>
    123123<div class="inside">
    124 <p id="jaxcat"><?php wp_nonce_field( 'add-category', '_ajax_nonce', false ); ?></p>
    125 <ul id="categorychecklist" class="list:category"><?php dropdown_categories(); ?></ul>
     124
     125<div id="category-adder" class="wp-hidden-children">
     126        <h4><a id="category-add-toggle" href="#category-add"><?php _e( '+ Add New Category' ); ?></a></h4>
     127        <p id="category-add" class="wp-hidden-child">
     128                <input type="text" name="newcat" id="newcat" class="form-required" value="<?php _e( 'New category name' ); ?>" />
     129                <?php wp_dropdown_categories( array( 'hide_empty' => 0, 'name' => 'newcat_parent', 'orderby' => 'name', 'hierarchical' => 1, 'show_option_none' => __('Parent category') ) ); ?>
     130                <a id="category-add-sumbit" class="add:categorychecklist:categorydiv button" href="<?php echo wp_nonce_url( '', 'add-category' ); ?>"><?php _e( 'Add' ); ?></a>
     131                <span id="category-ajax-response"></span>
     132        </p>
    126133</div>
     134
     135<ul id="category-tabs">
     136        <li class="ui-tabs-selected"><a href="#categories-all"><?php _e( 'All Categories' ); ?></a></li>
     137        <li><a href="#categories-pop"><?php _e( 'Most Used' ); ?></a></li>
     138</ul>
     139
     140<div id="categories-all" class="ui-tabs-panel">
     141        <ul id="categorychecklist" class="list:category categorychecklist form-no-clear">
     142                <?php dropdown_categories(); ?>
     143        </ul>
    127144</div>
    128145
     146<div id="categories-pop" class="ui-tabs-panel">
     147        <ul id="categorychecklist-pop" class="categorychecklist form-no-clear">
     148                <?php wp_popular_categories_checklist(); ?>
     149        </ul>
     150</div>
     151
     152</div>
     153</div>
     154
    129155<?php do_action('edit_form_advanced'); ?>
    130156
    131157<?php
  • wp-admin/admin-header.php

     
    22@header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
    33if (!isset($_GET["page"])) require_once('admin.php');
    44if ( $editing ) {
    5         if ( current_user_can('manage_categories') )
    6                 wp_enqueue_script( 'ajaxcat' );
    75        if ( user_can_richedit() )
    86                wp_enqueue_script( 'wp_tiny_mce' );
    97}