Plugin Directory

Changeset 3763715


Ignore:
Timestamp:
10/24/2026 08:32:32 PM (5 hours ago)
Author:
nickfmc
Message:

Release 1.1.2: parent folders include their subfolders' files and counts, and can be collapsed

Location:
apex-folders
Files:
20 edited
1 copied

Legend:

Unmodified
Added
Removed
  • apex-folders/tags/1.1.2/apex-folders.php

    r3740158 r3763715  
    1212 * Plugin URI: https://apex.mountainairweb.com/
    1313 * Description: Reach the apex of media library organization.
    14  * Version: 1.1.1
     14 * Version: 1.1.2
    1515 * Author: Nick Murray
    1616 * Author URI: https://mountainairweb.com
    … …  
    2929define( 'APEX_FOLDERS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    3030define( 'APEX_FOLDERS_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
    31 define( 'APEX_FOLDERS_VERSION', '1.1.1' );
     31define( 'APEX_FOLDERS_VERSION', '1.1.2' );
    3232
    3333// Core includes.
  • apex-folders/tags/1.1.2/assets/css/apex-main.css

    r3740158 r3763715  
    235235}
    236236
     237/* Collapsible parent folders */
     238.apexfo-toggle {
     239    position: absolute;
     240    top: 50%;
     241    left: 2px;
     242    z-index: 1;
     243    display: inline-flex;
     244    align-items: center;
     245    justify-content: center;
     246    width: 22px;
     247    height: 22px;
     248    padding: 0;
     249    margin: 0;
     250    transform: translateY(-50%);
     251    color: var(--apexfo-faint);
     252    background: transparent;
     253    border: 0;
     254    border-radius: 4px;
     255    cursor: pointer;
     256}
     257
     258.apexfo-toggle .dashicons {
     259    font-size: 16px;
     260    width: 16px;
     261    height: 16px;
     262    transform: rotate(90deg);
     263    transition: transform 0.15s ease;
     264}
     265
     266.apex-folder-list li.apexfo-collapsed .apexfo-toggle .dashicons {
     267    transform: none;
     268}
     269
     270.apexfo-toggle:hover,
     271.apexfo-toggle:focus {
     272    color: var(--apexfo-ink);
     273    background: var(--apexfo-cream);
     274    outline: none;
     275}
     276
     277.apexfo-toggle:focus-visible {
     278    box-shadow: var(--apexfo-focus);
     279}
     280
     281.apex-folder-list li.has-children > a {
     282    padding-left: 26px;
     283}
     284
     285.apex-folder-list li.child-folder.apexfo-hidden {
     286    display: none;
     287}
     288
    237289/* Actions: rename, subfolder, delete. Shown on hover and keyboard focus. */
    238290.apexfo-actions {
    … …  
    597649}
    598650
     651/* The chip row has no room to fold; show every folder */
     652.apex-mode-list .apexfo-toggle {
     653    display: none;
     654}
     655
     656.apex-mode-list .apex-folder-list li.has-children > a {
     657    padding-left: 10px;
     658}
     659
     660.apex-mode-list .apex-folder-list li.child-folder.apexfo-hidden {
     661    display: flex;
     662}
     663
    599664.apex-mode-list .apexfo-actions {
    600665    position: static;
  • apex-folders/tags/1.1.2/assets/js/apex-folders.js

    r3740158 r3763715  
    3232
    3333    /**
     34     * Files in a folder, including its subfolders for a parent folder
     35     */
     36    function getFolderTotal(folder) {
     37        var total = parseInt(folder.count, 10) || 0;
     38
     39        _.each(folders, function(candidate) {
     40            if (parseInt(candidate.parent, 10) === parseInt(folder.id, 10)) {
     41                total += parseInt(candidate.count, 10) || 0;
     42            }
     43        });
     44
     45        return total;
     46    }
     47
     48    /**
     49     * Whether a file in one folder belongs in the view of another:
     50     * the same folder, or a parent folder of it
     51     */
     52    function isInFolderView(attachmentFolderId, viewFolderId) {
     53        if (attachmentFolderId === viewFolderId) {
     54            return true;
     55        }
     56
     57        var folder = _.find(folders, function(candidate) {
     58            return parseInt(candidate.id, 10) === attachmentFolderId;
     59        });
     60
     61        return !!folder && parseInt(folder.parent, 10) === viewFolderId;
     62    }
     63
     64    /**
    3465     * Text shown for a folder in the filter dropdown
    3566     */
    3667    function getFolderLabel(folder) {
    37         return (folder.parent ? '\u2014 ' : '') + folder.name + ' (' + folder.count + ')';
     68        return (folder.parent ? '\u2014 ' : '') + folder.name + ' (' + getFolderTotal(folder) + ')';
    3869    }
    3970
    … …  
    6899
    69100            folder.count = counts[folder.id].count;
     101        });
     102
     103        _.each(folders, function(folder) {
    70104            jQuery('select#media-attachment-folder-filter option[value="folder-' + folder.id + '"]').text(getFolderLabel(folder));
    71105        });
    … …  
    182216        var folderId = getFolderId(this.props.get('apex_folder'));
    183217
    184         if (folderId && attachment.has('apexFolder') && parseInt(attachment.get('apexFolder'), 10) !== folderId) {
     218        if (folderId && attachment.has('apexFolder') && !isInFolderView(parseInt(attachment.get('apexFolder'), 10), folderId)) {
    185219            return false;
    186220        }
  • apex-folders/tags/1.1.2/assets/js/folder-counts.js

    r3740158 r3763715  
    8888                        .replace('%2$d', total);
    8989
    90                     showCount($item, folderData.count, title, skipHighlight);
     90                    // A parent folder shows everything inside it, subfolders included
     91                    showCount($item, total === null ? folderData.count : total, title, skipHighlight);
    9192                });
    9293
  • apex-folders/tags/1.1.2/assets/js/folder-drag-drop.js

    r3740158 r3763715  
    254254                    // Highlight this folder
    255255                    $folder.addClass('drag-over');
     256
     257                    // Open a folded parent so its subfolders can be dropped on too
     258                    if ($folder.hasClass('apexfo-collapsed')) {
     259                        $folder.find('.apexfo-toggle').trigger('click');
     260                    }
    256261                },
    257262                out: function(event, ui) {
  • apex-folders/tags/1.1.2/assets/js/folder-management.js

    r3740097 r3763715  
    7373    }
    7474
     75    /**
     76     * Collapsible parent folders. The choice is remembered in this browser;
     77     * the folder being viewed always starts open.
     78     */
     79    var collapsedKey = 'apexfo_collapsed';
     80    var collapsed = {};
     81
     82    try {
     83        collapsed = JSON.parse(localStorage.getItem(collapsedKey)) || {};
     84    } catch (e) {
     85        collapsed = {};
     86    }
     87
     88    function setExpanded($parent, expanded) {
     89        var folderId = $parent.data('folder-id');
     90
     91        $parent.toggleClass('apexfo-collapsed', !expanded);
     92        $parent.find('.apexfo-toggle').attr('aria-expanded', expanded ? 'true' : 'false');
     93        $('.apex-folder-list li.child-folder[data-parent-id="' + folderId + '"]').toggleClass('apexfo-hidden', !expanded);
     94    }
     95
     96    // Apply remembered choices, except where the current folder lives
     97    $('.apex-folder-list li.parent-folder.has-children').each(function() {
     98        var $parent = $(this);
     99        var folderId = $parent.data('folder-id');
     100        var holdsCurrent = $parent.hasClass('current') ||
     101            $('.apex-folder-list li.child-folder.current[data-parent-id="' + folderId + '"]').length > 0;
     102
     103        if (!holdsCurrent && typeof collapsed[folderId] === 'boolean') {
     104            setExpanded($parent, !collapsed[folderId]);
     105        }
     106    });
     107
     108    $('.apex-folder-list').on('click', '.apexfo-toggle', function(e) {
     109        e.preventDefault();
     110        e.stopPropagation();
     111
     112        var $parent = $(this).closest('li');
     113        var expanded = $parent.hasClass('apexfo-collapsed');
     114
     115        setExpanded($parent, expanded);
     116
     117        collapsed[$parent.data('folder-id')] = !expanded;
     118        try {
     119            localStorage.setItem(collapsedKey, JSON.stringify(collapsed));
     120        } catch (e) {
     121            // Remembering the choice is a convenience only
     122        }
     123    });
     124
    75125    // Add subfolder handler
    76126    $('.add-subfolder').on('click', function(e) {
  • apex-folders/tags/1.1.2/includes/class-apex-folders-ui.php

    r3740158 r3763715  
    116116     * @param int     $parent_id      Parent folder ID for subfolders.
    117117     * @param int     $total          Count including subfolders, for parent folders.
    118      */
    119     private function render_folder_item( $folder, $current_folder, $classes, $parent_id = 0, $total = 0 ) {
     118     * @param bool    $expanded       Whether a parent folder's subfolders are shown.
     119     */
     120    private function render_folder_item( $folder, $current_folder, $classes, $parent_id = 0, $total = 0, $expanded = true ) {
    120121        $is_current = $current_folder === $folder->slug;
    121122        $url        = wp_nonce_url( admin_url( 'upload.php?apex_folder=' . $folder->slug ), 'apex_folder_view' );
    122123        $is_system  = (int) $folder->term_id === (int) apex_folders_get_unassigned_id();
     124        $has_children = false !== strpos( $classes, 'has-children' );
     125
     126        if ( $has_children && ! $expanded ) {
     127            $classes .= ' apexfo-collapsed';
     128        }
    123129
    124130        echo '<li class="' . esc_attr( trim( ( $is_current ? 'current ' : '' ) . $classes ) ) . '" data-folder-id="' . intval( $folder->term_id ) . '"' . ( $parent_id ? ' data-parent-id="' . intval( $parent_id ) . '"' : '' ) . '>';
     131
     132        // Parent folders fold their subfolders away
     133        if ( $has_children ) {
     134            echo '<button type="button" class="apexfo-toggle" data-folder-id="' . intval( $folder->term_id ) . '" aria-expanded="' . ( $expanded ? 'true' : 'false' ) . '" aria-label="' . esc_attr__( 'Show or hide subfolders', 'apex-folders' ) . '"><span class="dashicons dashicons-arrow-right-alt2"></span></button>';
     135        }
     136
    125137        echo '<a href="' . esc_url( $url ) . '"' . ( $is_current ? ' aria-current="page"' : '' ) . '>';
    126138        echo $this->icon( $is_system ? 'inbox' : 'folder' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Static SVG markup.
    … …  
    132144            $count_title = sprintf( __( '%1$d in this folder, %2$d including subfolders', 'apex-folders' ), $folder->count, $total );
    133145        }
    134         echo '<span class="apexfo-count"' . ( $count_title ? ' title="' . esc_attr( $count_title ) . '"' : '' ) . '>' . intval( $folder->count ) . '</span>';
     146        // A parent folder shows everything inside it, subfolders included
     147        echo '<span class="apexfo-count"' . ( $count_title ? ' title="' . esc_attr( $count_title ) . '"' : '' ) . '>' . intval( max( $total, $folder->count ) ) . '</span>';
    135148        echo '</a>';
    136149
    … …  
    231244            }
    232245
    233             $this->render_folder_item( $folder, $current_folder, 'custom-folder parent-folder' . ( $has_children ? ' has-children' : '' ), 0, $total );
     246            // Subfolders start folded away, unless the folder being viewed is in this group.
     247            // The visitor's own choice, remembered by the browser, is applied by JavaScript.
     248            $expanded = $current_folder === $folder->slug;
     249            if ( $has_children && ! $expanded ) {
     250                foreach ( $child_folders[ $folder->term_id ] as $child ) {
     251                    if ( $current_folder === $child->slug ) {
     252                        $expanded = true;
     253                    }
     254                }
     255            }
     256
     257            $this->render_folder_item( $folder, $current_folder, 'custom-folder parent-folder' . ( $has_children ? ' has-children' : '' ), 0, $total, $expanded );
    234258
    235259            // Display children if any
    236260            if ( $has_children ) {
    237261                foreach ( $child_folders[ $folder->term_id ] as $child ) {
    238                     $this->render_folder_item( $child, $current_folder, 'custom-folder child-folder', $folder->term_id );
     262                    $this->render_folder_item( $child, $current_folder, 'custom-folder child-folder' . ( $expanded ? '' : ' apexfo-hidden' ), $folder->term_id );
    239263                }
    240264            }
  • apex-folders/tags/1.1.2/includes/class-media-query.php

    r3740097 r3763715  
    5151                            'field' => 'term_id',
    5252                            'terms' => $term->term_id,
    53                             'include_children' => false,
     53                            'include_children' => true,
    5454                            'operator' => 'IN' // Explicitly set operator
    5555                        ),
    … …  
    9595        }
    9696       
    97         // Show only the folder's own files, the same as the list view does
     97        // A parent folder shows its own files and its subfolders' files
    9898        unset( $query['apex_folder'] );
    9999       
    … …  
    106106            'field'            => 'term_id',
    107107            'terms'            => array( (int) $term->term_id ),
    108             'include_children' => false,
     108            'include_children' => true,
    109109        );
    110110       
  • apex-folders/tags/1.1.2/languages/apex-folders.pot

    r3740158 r3763715  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Apex Folders 1.1.1\n"
     5"Project-Id-Version: Apex Folders 1.1.2\n"
    66"Report-Msgid-Bugs-To: https://mountainairweb.com\n"
    77"MIME-Version: 1.0\n"
    … …  
    189189msgstr ""
    190190
     191#: includes/class-apex-folders-ui.php:134
     192msgid "Show or hide subfolders"
     193msgstr ""
     194
    191195#. translators: %1$d: files in this folder, %2$d: files including subfolders
    192 #: includes/class-apex-folders-ui.php:132 includes/class-apex-folders-ui.php:320
     196#: includes/class-apex-folders-ui.php:144 includes/class-apex-folders-ui.php:344
    193197msgid "%1$d in this folder, %2$d including subfolders"
    194198msgstr ""
    195199
    196 #: includes/class-apex-folders-ui.php:140 includes/class-apex-folders-ui.php:140
     200#: includes/class-apex-folders-ui.php:153 includes/class-apex-folders-ui.php:153
    197201msgid "Add subfolder"
    198202msgstr ""
    199203
    200 #: includes/class-apex-folders-ui.php:142 includes/class-apex-folders-ui.php:142
     204#: includes/class-apex-folders-ui.php:155 includes/class-apex-folders-ui.php:155
    201205msgid "Rename folder"
    202206msgstr ""
    203207
    204 #: includes/class-apex-folders-ui.php:143 includes/class-apex-folders-ui.php:143
     208#: includes/class-apex-folders-ui.php:156 includes/class-apex-folders-ui.php:156
    205209msgid "Delete folder"
    206210msgstr ""
    207211
    208 #: includes/class-apex-folders-ui.php:197
     212#: includes/class-apex-folders-ui.php:210
    209213msgid "Apex Folders"
    210214msgstr ""
    211215
    212 #: includes/class-apex-folders-ui.php:206
     216#: includes/class-apex-folders-ui.php:219
    213217msgid "All files"
    214218msgstr ""
    215219
    216 #: includes/class-apex-folders-ui.php:216 includes/class-apex-folders-utilities.php:33
     220#: includes/class-apex-folders-ui.php:229 includes/class-apex-folders-utilities.php:33
    217221msgid "Folders"
    218222msgstr ""
    219223
    220 #: includes/class-apex-folders-ui.php:219
     224#: includes/class-apex-folders-ui.php:232
    221225msgid "No folders yet. Add one below, then drag files onto it."
    222226msgstr ""
    223227
    224 #: includes/class-apex-folders-ui.php:245
     228#: includes/class-apex-folders-ui.php:269
    225229msgid "Add folder"
    226230msgstr ""
    227231
    228 #: includes/class-apex-folders-ui.php:247
     232#: includes/class-apex-folders-ui.php:271
    229233msgid "Drag a file onto a folder to move it. Use Bulk select to move several at once."
    230234msgstr ""
    231235
    232 #: includes/class-apex-folders-ui.php:251
     236#: includes/class-apex-folders-ui.php:275
    233237msgid "is a free tool from Apex by Mountain Air Web."
    234238msgstr ""
    235239
    236 #: includes/class-apex-folders-ui.php:252
     240#: includes/class-apex-folders-ui.php:276
    237241msgid "Meet the other Apex tools"
    238242msgstr ""
    239243
    240 #: includes/class-apex-folders-ui.php:297
     244#: includes/class-apex-folders-ui.php:321
    241245msgid "Create New Folder"
    242246msgstr ""
    243247
    244 #: includes/class-apex-folders-ui.php:298
     248#: includes/class-apex-folders-ui.php:322
    245249msgid "Create Folder"
    246250msgstr ""
    247251
    248 #: includes/class-apex-folders-ui.php:299
     252#: includes/class-apex-folders-ui.php:323
    249253msgid "Folder Name:"
    250254msgstr ""
    251255
    252 #: includes/class-apex-folders-ui.php:300
     256#: includes/class-apex-folders-ui.php:324
    253257msgid "Parent Folder (optional):"
    254258msgstr ""
    255259
    256 #: includes/class-apex-folders-ui.php:301
     260#: includes/class-apex-folders-ui.php:325
    257261msgid "None (top level)"
    258262msgstr ""
    259263
    260 #: includes/class-apex-folders-ui.php:302
     264#: includes/class-apex-folders-ui.php:326
    261265msgid "Create New Subfolder"
    262266msgstr ""
    263267
    264 #: includes/class-apex-folders-ui.php:303
     268#: includes/class-apex-folders-ui.php:327
    265269msgid "Create Subfolder"
    266270msgstr ""
    267271
    268 #: includes/class-apex-folders-ui.php:304
     272#: includes/class-apex-folders-ui.php:328
    269273msgid "Subfolder Name:"
    270274msgstr ""
    271275
    272 #: includes/class-apex-folders-ui.php:305
     276#: includes/class-apex-folders-ui.php:329
    273277msgid "Parent folder:"
    274278msgstr ""
    275279
    276 #: includes/class-apex-folders-ui.php:306
     280#: includes/class-apex-folders-ui.php:330
    277281msgid "Rename Folder"
    278282msgstr ""
    279283
    280 #: includes/class-apex-folders-ui.php:307
     284#: includes/class-apex-folders-ui.php:331
    281285msgid "New Name:"
    282286msgstr ""
    283287
    284 #: includes/class-apex-folders-ui.php:308
     288#: includes/class-apex-folders-ui.php:332
    285289msgid "Cancel"
    286290msgstr ""
    287291
    288 #: includes/class-apex-folders-ui.php:309
     292#: includes/class-apex-folders-ui.php:333
    289293msgid "Save"
    290294msgstr ""
    291295
    292296#. translators: %s: folder name
    293 #: includes/class-apex-folders-ui.php:311
     297#: includes/class-apex-folders-ui.php:335
    294298msgid "Are you sure you want to delete the folder \"%s\"?"
    295299msgstr ""
    296300
    297301#. translators: %s: folder name
    298 #: includes/class-apex-folders-ui.php:312
     302#: includes/class-apex-folders-ui.php:336
    299303msgid "Files in this folder will be moved to the Unassigned folder."
    300304msgstr ""
    301305
    302306#. translators: %s: folder name
    303 #: includes/class-apex-folders-ui.php:313
     307#: includes/class-apex-folders-ui.php:337
    304308msgid "Error creating folder:"
    305309msgstr ""
    306310
    307311#. translators: %s: folder name
    308 #: includes/class-apex-folders-ui.php:314
     312#: includes/class-apex-folders-ui.php:338
    309313msgid "Error creating subfolder:"
    310314msgstr ""
    311315
    312316#. translators: %s: folder name
    313 #: includes/class-apex-folders-ui.php:315
     317#: includes/class-apex-folders-ui.php:339
    314318msgid "Error renaming folder:"
    315319msgstr ""
    316320
    317 #: includes/class-apex-folders-ui.php:316
     321#: includes/class-apex-folders-ui.php:340
    318322msgid "Error deleting folder:"
    319323msgstr ""
    320324
    321 #: includes/class-apex-folders-ui.php:317
     325#: includes/class-apex-folders-ui.php:341
    322326msgid "Unknown error"
    323327msgstr ""
    324328
    325 #: includes/class-apex-folders-ui.php:318
     329#: includes/class-apex-folders-ui.php:342
    326330msgid "Network error. Please try again."
    327331msgstr ""
    328332
    329333#. translators: %1$d: folder's own file count, %2$d: total file count including subfolders
    330 #: includes/class-apex-folders-ui.php:402
     334#: includes/class-apex-folders-ui.php:426
    331335msgid "%1$d / %2$d total"
    332336msgstr ""
    333337
    334 #: includes/class-apex-folders-ui.php:439
     338#: includes/class-apex-folders-ui.php:463
    335339msgid "Folder"
    336340msgstr ""
    337341
    338 #: includes/class-apex-folders-ui.php:442
     342#: includes/class-apex-folders-ui.php:466
    339343msgid "Select a folder for this media item"
    340344msgstr ""
  • apex-folders/tags/1.1.2/readme.txt

    r3740158 r3763715  
    44Requires at least: 5.3
    55Tested up to: 7.1
    6 Stable tag: 1.1.1
     6Stable tag: 1.1.2
    77Requires PHP: 7.2
    88License: GPLv2 or later
    … …  
    8686== Changelog ==
    8787
     88= 1.1.2 =
     89* Parent folders now show their subfolders' files too, in the Media Library and in the editor's media picker, and their counts include subfolders.
     90* Parent folders can be collapsed. The folder you are viewing always starts open, and your choice is remembered.
     91* Hovering a collapsed folder while dragging opens it, so you can drop onto a subfolder.
     92
    8893= 1.1.1 =
    8994* New look: the folder sidebar, uploader and filters follow the Apex design, with folder icons, count badges and hover actions.
    … …  
    109114
    110115== Upgrade Notice ==
     116
     117= 1.1.2 =
     118Parent folders include their subfolders' files and counts, and can be collapsed.
    111119
    112120= 1.1.1 =
  • apex-folders/trunk/apex-folders.php

    r3740158 r3763715  
    1212 * Plugin URI: https://apex.mountainairweb.com/
    1313 * Description: Reach the apex of media library organization.
    14  * Version: 1.1.1
     14 * Version: 1.1.2
    1515 * Author: Nick Murray
    1616 * Author URI: https://mountainairweb.com
    … …  
    2929define( 'APEX_FOLDERS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    3030define( 'APEX_FOLDERS_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
    31 define( 'APEX_FOLDERS_VERSION', '1.1.1' );
     31define( 'APEX_FOLDERS_VERSION', '1.1.2' );
    3232
    3333// Core includes.
  • apex-folders/trunk/assets/css/apex-main.css

    r3740158 r3763715  
    235235}
    236236
     237/* Collapsible parent folders */
     238.apexfo-toggle {
     239    position: absolute;
     240    top: 50%;
     241    left: 2px;
     242    z-index: 1;
     243    display: inline-flex;
     244    align-items: center;
     245    justify-content: center;
     246    width: 22px;
     247    height: 22px;
     248    padding: 0;
     249    margin: 0;
     250    transform: translateY(-50%);
     251    color: var(--apexfo-faint);
     252    background: transparent;
     253    border: 0;
     254    border-radius: 4px;
     255    cursor: pointer;
     256}
     257
     258.apexfo-toggle .dashicons {
     259    font-size: 16px;
     260    width: 16px;
     261    height: 16px;
     262    transform: rotate(90deg);
     263    transition: transform 0.15s ease;
     264}
     265
     266.apex-folder-list li.apexfo-collapsed .apexfo-toggle .dashicons {
     267    transform: none;
     268}
     269
     270.apexfo-toggle:hover,
     271.apexfo-toggle:focus {
     272    color: var(--apexfo-ink);
     273    background: var(--apexfo-cream);
     274    outline: none;
     275}
     276
     277.apexfo-toggle:focus-visible {
     278    box-shadow: var(--apexfo-focus);
     279}
     280
     281.apex-folder-list li.has-children > a {
     282    padding-left: 26px;
     283}
     284
     285.apex-folder-list li.child-folder.apexfo-hidden {
     286    display: none;
     287}
     288
    237289/* Actions: rename, subfolder, delete. Shown on hover and keyboard focus. */
    238290.apexfo-actions {
    … …  
    597649}
    598650
     651/* The chip row has no room to fold; show every folder */
     652.apex-mode-list .apexfo-toggle {
     653    display: none;
     654}
     655
     656.apex-mode-list .apex-folder-list li.has-children > a {
     657    padding-left: 10px;
     658}
     659
     660.apex-mode-list .apex-folder-list li.child-folder.apexfo-hidden {
     661    display: flex;
     662}
     663
    599664.apex-mode-list .apexfo-actions {
    600665    position: static;
  • apex-folders/trunk/assets/js/apex-folders.js

    r3740158 r3763715  
    3232
    3333    /**
     34     * Files in a folder, including its subfolders for a parent folder
     35     */
     36    function getFolderTotal(folder) {
     37        var total = parseInt(folder.count, 10) || 0;
     38
     39        _.each(folders, function(candidate) {
     40            if (parseInt(candidate.parent, 10) === parseInt(folder.id, 10)) {
     41                total += parseInt(candidate.count, 10) || 0;
     42            }
     43        });
     44
     45        return total;
     46    }
     47
     48    /**
     49     * Whether a file in one folder belongs in the view of another:
     50     * the same folder, or a parent folder of it
     51     */
     52    function isInFolderView(attachmentFolderId, viewFolderId) {
     53        if (attachmentFolderId === viewFolderId) {
     54            return true;
     55        }
     56
     57        var folder = _.find(folders, function(candidate) {
     58            return parseInt(candidate.id, 10) === attachmentFolderId;
     59        });
     60
     61        return !!folder && parseInt(folder.parent, 10) === viewFolderId;
     62    }
     63
     64    /**
    3465     * Text shown for a folder in the filter dropdown
    3566     */
    3667    function getFolderLabel(folder) {
    37         return (folder.parent ? '\u2014 ' : '') + folder.name + ' (' + folder.count + ')';
     68        return (folder.parent ? '\u2014 ' : '') + folder.name + ' (' + getFolderTotal(folder) + ')';
    3869    }
    3970
    … …  
    6899
    69100            folder.count = counts[folder.id].count;
     101        });
     102
     103        _.each(folders, function(folder) {
    70104            jQuery('select#media-attachment-folder-filter option[value="folder-' + folder.id + '"]').text(getFolderLabel(folder));
    71105        });
    … …  
    182216        var folderId = getFolderId(this.props.get('apex_folder'));
    183217
    184         if (folderId && attachment.has('apexFolder') && parseInt(attachment.get('apexFolder'), 10) !== folderId) {
     218        if (folderId && attachment.has('apexFolder') && !isInFolderView(parseInt(attachment.get('apexFolder'), 10), folderId)) {
    185219            return false;
    186220        }
  • apex-folders/trunk/assets/js/folder-counts.js

    r3740158 r3763715  
    8888                        .replace('%2$d', total);
    8989
    90                     showCount($item, folderData.count, title, skipHighlight);
     90                    // A parent folder shows everything inside it, subfolders included
     91                    showCount($item, total === null ? folderData.count : total, title, skipHighlight);
    9192                });
    9293
  • apex-folders/trunk/assets/js/folder-drag-drop.js

    r3740158 r3763715  
    254254                    // Highlight this folder
    255255                    $folder.addClass('drag-over');
     256
     257                    // Open a folded parent so its subfolders can be dropped on too
     258                    if ($folder.hasClass('apexfo-collapsed')) {
     259                        $folder.find('.apexfo-toggle').trigger('click');
     260                    }
    256261                },
    257262                out: function(event, ui) {
  • apex-folders/trunk/assets/js/folder-management.js

    r3740097 r3763715  
    7373    }
    7474
     75    /**
     76     * Collapsible parent folders. The choice is remembered in this browser;
     77     * the folder being viewed always starts open.
     78     */
     79    var collapsedKey = 'apexfo_collapsed';
     80    var collapsed = {};
     81
     82    try {
     83        collapsed = JSON.parse(localStorage.getItem(collapsedKey)) || {};
     84    } catch (e) {
     85        collapsed = {};
     86    }
     87
     88    function setExpanded($parent, expanded) {
     89        var folderId = $parent.data('folder-id');
     90
     91        $parent.toggleClass('apexfo-collapsed', !expanded);
     92        $parent.find('.apexfo-toggle').attr('aria-expanded', expanded ? 'true' : 'false');
     93        $('.apex-folder-list li.child-folder[data-parent-id="' + folderId + '"]').toggleClass('apexfo-hidden', !expanded);
     94    }
     95
     96    // Apply remembered choices, except where the current folder lives
     97    $('.apex-folder-list li.parent-folder.has-children').each(function() {
     98        var $parent = $(this);
     99        var folderId = $parent.data('folder-id');
     100        var holdsCurrent = $parent.hasClass('current') ||
     101            $('.apex-folder-list li.child-folder.current[data-parent-id="' + folderId + '"]').length > 0;
     102
     103        if (!holdsCurrent && typeof collapsed[folderId] === 'boolean') {
     104            setExpanded($parent, !collapsed[folderId]);
     105        }
     106    });
     107
     108    $('.apex-folder-list').on('click', '.apexfo-toggle', function(e) {
     109        e.preventDefault();
     110        e.stopPropagation();
     111
     112        var $parent = $(this).closest('li');
     113        var expanded = $parent.hasClass('apexfo-collapsed');
     114
     115        setExpanded($parent, expanded);
     116
     117        collapsed[$parent.data('folder-id')] = !expanded;
     118        try {
     119            localStorage.setItem(collapsedKey, JSON.stringify(collapsed));
     120        } catch (e) {
     121            // Remembering the choice is a convenience only
     122        }
     123    });
     124
    75125    // Add subfolder handler
    76126    $('.add-subfolder').on('click', function(e) {
  • apex-folders/trunk/includes/class-apex-folders-ui.php

    r3740158 r3763715  
    116116     * @param int     $parent_id      Parent folder ID for subfolders.
    117117     * @param int     $total          Count including subfolders, for parent folders.
    118      */
    119     private function render_folder_item( $folder, $current_folder, $classes, $parent_id = 0, $total = 0 ) {
     118     * @param bool    $expanded       Whether a parent folder's subfolders are shown.
     119     */
     120    private function render_folder_item( $folder, $current_folder, $classes, $parent_id = 0, $total = 0, $expanded = true ) {
    120121        $is_current = $current_folder === $folder->slug;
    121122        $url        = wp_nonce_url( admin_url( 'upload.php?apex_folder=' . $folder->slug ), 'apex_folder_view' );
    122123        $is_system  = (int) $folder->term_id === (int) apex_folders_get_unassigned_id();
     124        $has_children = false !== strpos( $classes, 'has-children' );
     125
     126        if ( $has_children && ! $expanded ) {
     127            $classes .= ' apexfo-collapsed';
     128        }
    123129
    124130        echo '<li class="' . esc_attr( trim( ( $is_current ? 'current ' : '' ) . $classes ) ) . '" data-folder-id="' . intval( $folder->term_id ) . '"' . ( $parent_id ? ' data-parent-id="' . intval( $parent_id ) . '"' : '' ) . '>';
     131
     132        // Parent folders fold their subfolders away
     133        if ( $has_children ) {
     134            echo '<button type="button" class="apexfo-toggle" data-folder-id="' . intval( $folder->term_id ) . '" aria-expanded="' . ( $expanded ? 'true' : 'false' ) . '" aria-label="' . esc_attr__( 'Show or hide subfolders', 'apex-folders' ) . '"><span class="dashicons dashicons-arrow-right-alt2"></span></button>';
     135        }
     136
    125137        echo '<a href="' . esc_url( $url ) . '"' . ( $is_current ? ' aria-current="page"' : '' ) . '>';
    126138        echo $this->icon( $is_system ? 'inbox' : 'folder' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Static SVG markup.
    … …  
    132144            $count_title = sprintf( __( '%1$d in this folder, %2$d including subfolders', 'apex-folders' ), $folder->count, $total );
    133145        }
    134         echo '<span class="apexfo-count"' . ( $count_title ? ' title="' . esc_attr( $count_title ) . '"' : '' ) . '>' . intval( $folder->count ) . '</span>';
     146        // A parent folder shows everything inside it, subfolders included
     147        echo '<span class="apexfo-count"' . ( $count_title ? ' title="' . esc_attr( $count_title ) . '"' : '' ) . '>' . intval( max( $total, $folder->count ) ) . '</span>';
    135148        echo '</a>';
    136149
    … …  
    231244            }
    232245
    233             $this->render_folder_item( $folder, $current_folder, 'custom-folder parent-folder' . ( $has_children ? ' has-children' : '' ), 0, $total );
     246            // Subfolders start folded away, unless the folder being viewed is in this group.
     247            // The visitor's own choice, remembered by the browser, is applied by JavaScript.
     248            $expanded = $current_folder === $folder->slug;
     249            if ( $has_children && ! $expanded ) {
     250                foreach ( $child_folders[ $folder->term_id ] as $child ) {
     251                    if ( $current_folder === $child->slug ) {
     252                        $expanded = true;
     253                    }
     254                }
     255            }
     256
     257            $this->render_folder_item( $folder, $current_folder, 'custom-folder parent-folder' . ( $has_children ? ' has-children' : '' ), 0, $total, $expanded );
    234258
    235259            // Display children if any
    236260            if ( $has_children ) {
    237261                foreach ( $child_folders[ $folder->term_id ] as $child ) {
    238                     $this->render_folder_item( $child, $current_folder, 'custom-folder child-folder', $folder->term_id );
     262                    $this->render_folder_item( $child, $current_folder, 'custom-folder child-folder' . ( $expanded ? '' : ' apexfo-hidden' ), $folder->term_id );
    239263                }
    240264            }
  • apex-folders/trunk/includes/class-media-query.php

    r3740097 r3763715  
    5151                            'field' => 'term_id',
    5252                            'terms' => $term->term_id,
    53                             'include_children' => false,
     53                            'include_children' => true,
    5454                            'operator' => 'IN' // Explicitly set operator
    5555                        ),
    … …  
    9595        }
    9696       
    97         // Show only the folder's own files, the same as the list view does
     97        // A parent folder shows its own files and its subfolders' files
    9898        unset( $query['apex_folder'] );
    9999       
    … …  
    106106            'field'            => 'term_id',
    107107            'terms'            => array( (int) $term->term_id ),
    108             'include_children' => false,
     108            'include_children' => true,
    109109        );
    110110       
  • apex-folders/trunk/languages/apex-folders.pot

    r3740158 r3763715  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Apex Folders 1.1.1\n"
     5"Project-Id-Version: Apex Folders 1.1.2\n"
    66"Report-Msgid-Bugs-To: https://mountainairweb.com\n"
    77"MIME-Version: 1.0\n"
    … …  
    189189msgstr ""
    190190
     191#: includes/class-apex-folders-ui.php:134
     192msgid "Show or hide subfolders"
     193msgstr ""
     194
    191195#. translators: %1$d: files in this folder, %2$d: files including subfolders
    192 #: includes/class-apex-folders-ui.php:132 includes/class-apex-folders-ui.php:320
     196#: includes/class-apex-folders-ui.php:144 includes/class-apex-folders-ui.php:344
    193197msgid "%1$d in this folder, %2$d including subfolders"
    194198msgstr ""
    195199
    196 #: includes/class-apex-folders-ui.php:140 includes/class-apex-folders-ui.php:140
     200#: includes/class-apex-folders-ui.php:153 includes/class-apex-folders-ui.php:153
    197201msgid "Add subfolder"
    198202msgstr ""
    199203
    200 #: includes/class-apex-folders-ui.php:142 includes/class-apex-folders-ui.php:142
     204#: includes/class-apex-folders-ui.php:155 includes/class-apex-folders-ui.php:155
    201205msgid "Rename folder"
    202206msgstr ""
    203207
    204 #: includes/class-apex-folders-ui.php:143 includes/class-apex-folders-ui.php:143
     208#: includes/class-apex-folders-ui.php:156 includes/class-apex-folders-ui.php:156
    205209msgid "Delete folder"
    206210msgstr ""
    207211
    208 #: includes/class-apex-folders-ui.php:197
     212#: includes/class-apex-folders-ui.php:210
    209213msgid "Apex Folders"
    210214msgstr ""
    211215
    212 #: includes/class-apex-folders-ui.php:206
     216#: includes/class-apex-folders-ui.php:219
    213217msgid "All files"
    214218msgstr ""
    215219
    216 #: includes/class-apex-folders-ui.php:216 includes/class-apex-folders-utilities.php:33
     220#: includes/class-apex-folders-ui.php:229 includes/class-apex-folders-utilities.php:33
    217221msgid "Folders"
    218222msgstr ""
    219223
    220 #: includes/class-apex-folders-ui.php:219
     224#: includes/class-apex-folders-ui.php:232
    221225msgid "No folders yet. Add one below, then drag files onto it."
    222226msgstr ""
    223227
    224 #: includes/class-apex-folders-ui.php:245
     228#: includes/class-apex-folders-ui.php:269
    225229msgid "Add folder"
    226230msgstr ""
    227231
    228 #: includes/class-apex-folders-ui.php:247
     232#: includes/class-apex-folders-ui.php:271
    229233msgid "Drag a file onto a folder to move it. Use Bulk select to move several at once."
    230234msgstr ""
    231235
    232 #: includes/class-apex-folders-ui.php:251
     236#: includes/class-apex-folders-ui.php:275
    233237msgid "is a free tool from Apex by Mountain Air Web."
    234238msgstr ""
    235239
    236 #: includes/class-apex-folders-ui.php:252
     240#: includes/class-apex-folders-ui.php:276
    237241msgid "Meet the other Apex tools"
    238242msgstr ""
    239243
    240 #: includes/class-apex-folders-ui.php:297
     244#: includes/class-apex-folders-ui.php:321
    241245msgid "Create New Folder"
    242246msgstr ""
    243247
    244 #: includes/class-apex-folders-ui.php:298
     248#: includes/class-apex-folders-ui.php:322
    245249msgid "Create Folder"
    246250msgstr ""
    247251
    248 #: includes/class-apex-folders-ui.php:299
     252#: includes/class-apex-folders-ui.php:323
    249253msgid "Folder Name:"
    250254msgstr ""
    251255
    252 #: includes/class-apex-folders-ui.php:300
     256#: includes/class-apex-folders-ui.php:324
    253257msgid "Parent Folder (optional):"
    254258msgstr ""
    255259
    256 #: includes/class-apex-folders-ui.php:301
     260#: includes/class-apex-folders-ui.php:325
    257261msgid "None (top level)"
    258262msgstr ""
    259263
    260 #: includes/class-apex-folders-ui.php:302
     264#: includes/class-apex-folders-ui.php:326
    261265msgid "Create New Subfolder"
    262266msgstr ""
    263267
    264 #: includes/class-apex-folders-ui.php:303
     268#: includes/class-apex-folders-ui.php:327
    265269msgid "Create Subfolder"
    266270msgstr ""
    267271
    268 #: includes/class-apex-folders-ui.php:304
     272#: includes/class-apex-folders-ui.php:328
    269273msgid "Subfolder Name:"
    270274msgstr ""
    271275
    272 #: includes/class-apex-folders-ui.php:305
     276#: includes/class-apex-folders-ui.php:329
    273277msgid "Parent folder:"
    274278msgstr ""
    275279
    276 #: includes/class-apex-folders-ui.php:306
     280#: includes/class-apex-folders-ui.php:330
    277281msgid "Rename Folder"
    278282msgstr ""
    279283
    280 #: includes/class-apex-folders-ui.php:307
     284#: includes/class-apex-folders-ui.php:331
    281285msgid "New Name:"
    282286msgstr ""
    283287
    284 #: includes/class-apex-folders-ui.php:308
     288#: includes/class-apex-folders-ui.php:332
    285289msgid "Cancel"
    286290msgstr ""
    287291
    288 #: includes/class-apex-folders-ui.php:309
     292#: includes/class-apex-folders-ui.php:333
    289293msgid "Save"
    290294msgstr ""
    291295
    292296#. translators: %s: folder name
    293 #: includes/class-apex-folders-ui.php:311
     297#: includes/class-apex-folders-ui.php:335
    294298msgid "Are you sure you want to delete the folder \"%s\"?"
    295299msgstr ""
    296300
    297301#. translators: %s: folder name
    298 #: includes/class-apex-folders-ui.php:312
     302#: includes/class-apex-folders-ui.php:336
    299303msgid "Files in this folder will be moved to the Unassigned folder."
    300304msgstr ""
    301305
    302306#. translators: %s: folder name
    303 #: includes/class-apex-folders-ui.php:313
     307#: includes/class-apex-folders-ui.php:337
    304308msgid "Error creating folder:"
    305309msgstr ""
    306310
    307311#. translators: %s: folder name
    308 #: includes/class-apex-folders-ui.php:314
     312#: includes/class-apex-folders-ui.php:338
    309313msgid "Error creating subfolder:"
    310314msgstr ""
    311315
    312316#. translators: %s: folder name
    313 #: includes/class-apex-folders-ui.php:315
     317#: includes/class-apex-folders-ui.php:339
    314318msgid "Error renaming folder:"
    315319msgstr ""
    316320
    317 #: includes/class-apex-folders-ui.php:316
     321#: includes/class-apex-folders-ui.php:340
    318322msgid "Error deleting folder:"
    319323msgstr ""
    320324
    321 #: includes/class-apex-folders-ui.php:317
     325#: includes/class-apex-folders-ui.php:341
    322326msgid "Unknown error"
    323327msgstr ""
    324328
    325 #: includes/class-apex-folders-ui.php:318
     329#: includes/class-apex-folders-ui.php:342
    326330msgid "Network error. Please try again."
    327331msgstr ""
    328332
    329333#. translators: %1$d: folder's own file count, %2$d: total file count including subfolders
    330 #: includes/class-apex-folders-ui.php:402
     334#: includes/class-apex-folders-ui.php:426
    331335msgid "%1$d / %2$d total"
    332336msgstr ""
    333337
    334 #: includes/class-apex-folders-ui.php:439
     338#: includes/class-apex-folders-ui.php:463
    335339msgid "Folder"
    336340msgstr ""
    337341
    338 #: includes/class-apex-folders-ui.php:442
     342#: includes/class-apex-folders-ui.php:466
    339343msgid "Select a folder for this media item"
    340344msgstr ""
  • apex-folders/trunk/readme.txt

    r3740158 r3763715  
    44Requires at least: 5.3
    55Tested up to: 7.1
    6 Stable tag: 1.1.1
     6Stable tag: 1.1.2
    77Requires PHP: 7.2
    88License: GPLv2 or later
    … …  
    8686== Changelog ==
    8787
     88= 1.1.2 =
     89* Parent folders now show their subfolders' files too, in the Media Library and in the editor's media picker, and their counts include subfolders.
     90* Parent folders can be collapsed. The folder you are viewing always starts open, and your choice is remembered.
     91* Hovering a collapsed folder while dragging opens it, so you can drop onto a subfolder.
     92
    8893= 1.1.1 =
    8994* New look: the folder sidebar, uploader and filters follow the Apex design, with folder icons, count badges and hover actions.
    … …  
    109114
    110115== Upgrade Notice ==
     116
     117= 1.1.2 =
     118Parent folders include their subfolders' files and counts, and can be collapsed.
    111119
    112120= 1.1.1 =
Note: See TracChangeset for help on using the changeset viewer.