Dynamic slug generation in custom page creation modal

admin

#1

I’m creating a Blueprint to allow a user to easily create a new blog post, and I’d like to know if it’s possible to mimic the behaviour of the Folder Name field of the Add Page modal.

image

As you type in the Page Title field, the slug dynamically appears in the Folder Name field.

I’ve followed the Add a custom page creation modal Admin Recipe and I’ve created my modal, but I’m not sure how to get the dynamic slug behaviour of the Add Page modal—if indeed it’s possible.

image

Any help is very much appreciated!

Thanks,

Chris


#2

@christhorn The Grav ‘add’ page modal uses some Javascript for this. I think you can find it at Github in https://github.com/getgrav/grav-plugin-admin/blob/develop/themes/grav/app/pages/page/add.js

A ‘slugify’ function is being used when typing the ‘Page Title’ field.

title.on('input focus blur', (event) => {
    if (custom) { return true; }
    let elements = getFields('title', event.currentTarget);

    let slug = $.slugify(elements.title.val(), {custom: {"'": ''}});
    elements.folder.val(slug);
});

This ‘add.js’ file imports a utils file, which in turn imports the npm module ‘speakingurl’.

Hope this gives you some hints as to where to look…


#3

Thanks very much for the reply!

I had come across the add.js file, but I hadn’t made the connection to the ../../utils/jquery-utils.js file which contains the slugify function - thanks for that.

What I haven’t quite got my head around yet is how to use some custom JavaScript with a custom admin blueprint.

I feel like I need to create my own version of add.js and have the admin plugin incorporate it somehow, but it looks like I’d need to recompile /user/plugins/admin/themes/grav/js/admin.min.js to do that…?

I can see in add.js that the title field is targeted with:

let title = $('[data-remodal-id="modal"] input[name="data[title]"], [data-remodal-id="modular"] input[name="data[title]"]');

… but when on inspecting the source when my custom modal is open I can see that the attribute data-remodal-id has the value modal-add_modal-0, whereas it’s simply modal for the regular Add Page modal… if that makes sense.

Do you have any more hints?!

Chris


#4

Update: On rereading you last post, the below sample might not be what you are looking for… And maybe it does lead to something anyway…

@christhorn I tried the following which seems to work. It ‘slugifies’ the title field and sets the folder field to the uppercase value of the slug.

  • I ceated a new plugin:
    $ ./bin/plugin devtools new-plugin
    
  • In ‘user/plugins/myplugin.php’ I added the ‘onAssetsInitialized’ event:
    public function onPluginsInitialized()
    {
        if ($this->isAdmin()) {
            // Enable the main event we are interested in
            $this->enable([
                'onAssetsInitialized' => ['onAssetsInitialized', 0]
            ]);
        }
    }
    
    public function onAssetsInitialized(Event $e)
    {
        $assets = $this->grav['assets'];
        $assets->addJs('plugin://myplugin/js/myjs.js');
    }
    
  • I created a javascript in ‘/user/plugins/myplugin/js/myjs.js’ containing:
    $(document).ready(function () {
        const folder = $('[data-remodal-id="modal"] input[name="data[folder]"], [data-remodal-id="modular"] input[name="data[folder]"]');
        const title = $('[data-remodal-id="modal"] input[name="data[title]"], [data-remodal-id="modular"] input[name="data[title]"]');
    
        title.on('input focus blur', (event) => {
            const slug = $.slugify(title.val(), { custom: { "'": '' } }).toUpperCase();
            folder.val(slug);
        });
    });
    

Guess what happens…


#5

Aha fantastic! It’s basically working like it should now!

I’ve done what you said and created a plugin, and I’ve targeted that specific modal using [data-remodal-id="modal-add_modal-0"] and sure enough it generates the capitalised slug of the title field in the folder field!

My original intention was to have today’s date automatically prepended to the slug to aid automatic sorting of blog posts, which is now just a trivial step.

Thanks so much for your detailed answers, I really appreciate it :grinning:

Chris

Edit

image

Custom JS:

function formatDate() {
  var d = new Date(),
    month = '' + (d.getMonth() + 1),
    day = '' + d.getDate(),
    year = d.getFullYear();
  
  if (month.length < 2) month = '0' + month;
  if (day.length < 2) day = '0' + day;
  
  return [year, month, day].join('-');
}

$(document).ready(function () {
  const folder  = $('[data-remodal-id="modal-add_modal-0"] input[name="data[folder]"]');
  const title   = $('[data-remodal-id="modal-add_modal-0"] input[name="data[title]"]');
  
  title.on('input focus blur', (event) => {
    const slug = formatDate() + '-' + $.slugify(title.val(), { custom: { "'": '' } });
    folder.val(slug);
  });
});

#6

@christhorn Good to hear! It was an interesting exercise…

I was just about asking if you would mind sharing the final solution… You beat me to it. Thanks for sharing.

You might even consider creating a new plugin based on this…

@dydaevskiy I recall you were looking for a similar solution in Is it possible to assign the creation date to the folder of the sub-page?. It this something that might solve your requirements?

Cheers!


#7

@christhorn Instead of the formatDate() function you might try the single line:

new Date().toISOString().slice(0, 10)
// 2018-11-07

#8

Great, that’s much neater! I was looking for a simple date function - that’ll do nicely.

I will consider the plugin idea, as the apparent lack of a really simple interface for creating blog posts—as per Wordpress, for example—has held me back from using Grav in a couple of instances.

I’m not sure how the plugin would deal with modals that were assigned different IDs though. My custom modal is modal-add_modal-0. Additional custom modals would no doubt have different IDs, so it would be a case of being able to control the ID the “new blog post” modal is assigned.

I will have a fiddle with it though!

Chris