Peter Falkenberg Brown Posted October 3, 2021 Share Posted October 3, 2021 Hi All, I'm using ready.php to add some values to new pages, so that after I type in the title of the page and hit save, when I get to the edit page of the full set of fields, certain fields have pre-filled values. The routine is working well, but I want to add one more item, to wit: - I want to set the field focus (i.e. the cursor is in that field) to a field called "list_price." Can that be done, in ready.php, and if so, what's the best method? Here's the code I have already: $pages->addHook('added', function(HookEvent $event) { $page = $event->arguments(0); if ( $page->template == 'book_sales' ) { #............................................. $parent = $page->parent(); $parent_path = $parent->path(); $last_item_number_selectors = "parent=$parent_path," . "sort=-item_number," . "$skiptrash," . "limit=1"; $last_item_number = wire("pages")->get("$last_item_number_selectors")->item_number; # the item_number has a 2 letter prefix, followed by 4 digits that have leading zeroes, # and the number has to be incremented, while retaining the leading zeroes. $part1 = substr($last_item_number,0,2); $part2 = substr($last_item_number,2); $part2inc = intval($part2) + 1; $part2new = sprintf('%04d', $part2inc); $new_item_number = $part1 . $part2new; $page->item_number = $new_item_number; #............................................. $admin_now = time(); $page->list_date = wire(datetime)->date($format='Y-m-d', $admin_now); $page->list_year = wire(datetime)->date($format='Y', $admin_now); #............................................. $page->of(false); $page->save(); $page->of(true); } }); Thanks! Peter Link to comment Share on other sites More sharing options...
kongondo Posted October 3, 2021 Share Posted October 3, 2021 1 hour ago, Peter Falkenberg Brown said: I want to set the field focus (i.e. the cursor is in that field) to a field called "list_price." Can that be done, in ready.php, and if so, what's the best method? No, you cannot focus an input using PHP. Autofocus is usually achieved using JavaScript. E.g. // get input you want to focus // in this case we know its ID, so we are grabbing it that way // we focus it using the focus() method // you could throw this into a function if you wanted document.getElementById("your_input_id").focus(); Alternatively, you can do this in the HTML, i.e. the PHP code that is outputting the HTML by using the autofocus attribute. <label for="my_input">Book Title:</label> <!-- the browser will focus this input when the page loads --> <input type="text" id="my_input" name="my_input" autofocus> <label for="my_input">First name:</label> <!-- the browser will focus this input when the page loads --> <input type="text" id="my_input" name="my_input" autofocus> References https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus https://www.w3schools.com/tags/att_input_autofocus.asp Read about the accessibility considerations if you will be using autofocus. Link to comment Share on other sites More sharing options...
Peter Falkenberg Brown Posted October 3, 2021 Author Share Posted October 3, 2021 Thanks, @kongondo... In the PW admin, when you click on "New" to add a record, the title field has focus, with the cursor in it. However, when you then hit save and get to the edit page, none of the fields have focus. These pages are part of the built in admin, so I'm wondering if they can be tweaked without editing the core files. Based on your description, it would seem that the New record page must have some type of focus mechanism, either with Javascript or HTML. What are your thoughts? Thanks! Peter Link to comment Share on other sites More sharing options...
MarkE Posted October 4, 2021 Share Posted October 4, 2021 Just a thought. Could you use $config->js() or $config->jsConfig() to set the field name having the focus and then have the js in admin.js defaulting to title if required? Link to comment Share on other sites More sharing options...
dotnetic Posted October 4, 2021 Share Posted October 4, 2021 To focus an Inputfield there is a method since 3.0.145 (ProcessWire 3.0.145 core updates) Inputfields.focus(f) which you could put into an custom admin.js file. There is also a possibility to do a redirect and focus the field via PHP but I don't remember the query parameter. Maybe @bernhard can jump in for the correct syntax. 1 Link to comment Share on other sites More sharing options...
Peter Falkenberg Brown Posted October 4, 2021 Author Share Posted October 4, 2021 Thanks, @dotnetic and @MarkE... And thanks, @bernhard, in advance. :-) Peter Link to comment Share on other sites More sharing options...
bernhard Posted October 4, 2021 Share Posted October 4, 2021 1 hour ago, dotnetic said: There is also a possibility to do a redirect and focus the field via PHP but I don't remember the query parameter. Maybe @bernhard can jump in for the correct syntax. you can add ?field=foo or ?fields=foo,bar but that will then show only the fields listet in the url and I think it does not change the focus. Should this field always get the focus? Then I'd probably hook Inputfield::render and add the js there. Link to comment Share on other sites More sharing options...
Peter Falkenberg Brown Posted October 4, 2021 Author Share Posted October 4, 2021 Yes, it should always get the focus when it goes from adding a new record to the edit page of the new record. At other times, it doesn't matter, either way. Any JS gurus want to demonstrate the code and where / how to put it? I'm not a JS person. :-) Thanks! Peter Link to comment Share on other sites More sharing options...
kongondo Posted October 4, 2021 Share Posted October 4, 2021 35 minutes ago, Peter Falkenberg Brown said: it should always get the focus when it goes from adding a new record to the edit page of the new record. What field is this? Title field? There's two steps to this: Add your custom JS to the admin Add your code to the custom JS file. For #1, there's many different ways to do this. Have a look at these two threads, for instance: For #2, it depends on the input you want to target. The easiest way is to target it by ID. Or grab it using ProcessWire Inputfields API and focus it. If you can be a bit more specific about the field, we can provide ready-to-go code (some of which have been posted here already, actually). Link to comment Share on other sites More sharing options...
Peter Falkenberg Brown Posted October 4, 2021 Author Share Posted October 4, 2021 Thank you, @kongondo! It's a field called "list_price." It's a field of type float. It's in a template called "book_sales." See my ready.php code at the beginning of the thread for what I'm doing with adding values to fields, on a new add record routine. Thanks again for your help! Peter 1 Link to comment Share on other sites More sharing options...
kongondo Posted October 4, 2021 Share Posted October 4, 2021 (edited) OK. STEP #1 Create a file, e.g admin.js and save it to your preferred location. In this example, we have saved it at site/templates/scripts/admin/admin.js STEP #2 Add either of the below JS code in admin.js (you don't need both; choose one or the other). jQuery version: $(document).ready(function () { // #wrap_Inputfield_list_price is the ID ProcessWire will assign to your list_price field's wrapper (an li element). // you can confirm this by examining the markup around your 'list_price' input in dev tools. // Inputfields is a utility files that ships with ProcessWire. // more details: inputfields.js - JS specific to behavior of ProcessWire Inputfield forms. Inputfields.focus("#wrap_Inputfield_list_price") }) Plain JavaScript version: const InputfieldAdminScripts = { focusAnInputfield: function (inputfield_id) { const inputfieldToFocus = document.getElementById(inputfield_id) // if we found the element,focus it if (inputfieldToFocus) { inputfieldToFocus.focus() } }, } // DOM ready document.addEventListener("DOMContentLoaded", function () { InputfieldAdminScripts.focusAnInputfield("Inputfield_list_price") // this will also work here. you can use it instead of the above // Inputfields.focus("#wrap_Inputfield_list_price") }) STEP #3 Inside ready.php, add this code to load admin.js. You can modify this to only load under certain conditions if you wish. <?php namespace ProcessWire; $this->addHookBefore('AdminTheme::getExtraMarkup', function (HookEvent $event) { $config = $this->wire->config; $url = $config->urls->templates; $config->scripts->add($url . "scripts/admin/admin.js"); }); Please note that in Chrome (and maybe FF as well), if you have your dev tools opened and the cursor currently focused on it, the inputfield might not seem to be focused, but it actually is. ? Edited October 4, 2021 by kongondo 4 Link to comment Share on other sites More sharing options...
Peter Falkenberg Brown Posted October 5, 2021 Author Share Posted October 5, 2021 Hi @kongondo, This is so cool. Thank you VERY much. It works perfectly. I'm wondering what the best way to load it under certain conditions would be. Right now, it places the cursor in the field whenever I go into edit mode, not just on the initial edit that comes right after adding a record. In my ready.php file I have this: $this->addHookBefore('AdminTheme::getExtraMarkup', function (HookEvent $event) { $config = $this->wire->config; $url = $config->urls->templates; $config->scripts->add($url . "scripts/admin.js"); }); $pages->addHook('added', function(HookEvent $event) { $page = $event->arguments(0); if ( $page->template == 'book_sales' ) { .... etc.... So, in the code that comes after the addHook('added') it only operates in the subsequent edit screen, but not when I go back to a record and click on edit. (At least I don't think so.) Is there a way to only initiate the cursor focus during that initial edit? Thank you again! Peter 1 Link to comment Share on other sites More sharing options...
kongondo Posted October 5, 2021 Share Posted October 5, 2021 2 hours ago, Peter Falkenberg Brown said: Is there a way to only initiate the cursor focus during that initial edit? Below is one way to detect if the page is new, in which case add our script. The disadvantage of this is that the whole file is only included under certain conditions as opposed to a just a function inside the file being called under certain conditions. This means the admin.js file will only be used for focusing the list_price field. There are other ways around this. Hopefully others will chime in with better solutions/ideas. Change the ready.php code I suggested above to this one: <?php namespace ProcessWire; $this->addHookBefore('ProcessPageEdit::buildForm', function (HookEvent $event) { $page = $event->object->getPage(); // new pages GET a 'new' query string/parameter, i.e. &new=1 // we check that $new = (int) $this->wire('input')->get('new'); if ($new && $page->template == 'book_sales') { $config = $this->wire->config; $url = $config->urls->templates; $config->scripts->add($url . "scripts/admin/admin.js"); } }); There's probably other more elegant ways to detect if a page is new but I cannot remember any of the top of my head at the moment. 1 Link to comment Share on other sites More sharing options...
bernhard Posted October 5, 2021 Share Posted October 5, 2021 On 10/3/2021 at 9:12 AM, Peter Falkenberg Brown said: Based on your description, it would seem that the New record page must have some type of focus mechanism, either with Javascript or HTML. ProcessPageAdd.module has this (that is the process module that is executed when adding a page): $form->addClass('InputfieldFormFocusFirst'); And inputfields.js has this note: * - InputfieldFormFocusFirst: Class assigned to form that should focus the first field. ProcessPageEdit does not add this class, so there is no field focus on edit screens. What I'd do is probably this: // in site/ready.php $wire->addHookAfter("Inputfield(name=title)::render", function(HookEvent $event) { // we focus the field only if it is empty if($event->object->value) return; // show a hint and focus the field $event->return .= "<div>Please enter something here</div>" ."<script>$(function() { Inputfields.focus('#Inputfield_title') })</script>"; }); 3 Link to comment Share on other sites More sharing options...
dotnetic Posted October 5, 2021 Share Posted October 5, 2021 I just love our community and all the good ideas. Link to comment Share on other sites More sharing options...
dotnetic Posted October 5, 2021 Share Posted October 5, 2021 Guys, I found the method that I meant. It is not the field=fieldname URL that Bernhard mentioned. A long time ago I also tried to tackle a similar task, where I wanted to remember and focus the last edited field after you saved a page. I opened a github issue for this and later Ryan added some methods that he mentioned in a reply, that achieve the behaviour I and @Peter Falkenberg Brown want. Just add a #focus-field_name to the URL when the page is saved and the redirect is executed and the field gets focused. An example URL looks like https://domain.com/processwire/page/edit/?id=1056#focus-subheadline and would focus the field named "subheadline". I am a fan of using native methods that ProcessWire offers, over custom ones. But what the others wrote is also viable. I will provide a hook, just have to test it out, but it goes somewhat like this: <?php namespace ProcessWire; $this->addHookBefore('ProcessPageEdit::processSaveRedirect', function (HookEvent $event) { $url = $event->arguments(0); $page = $event->object->getPage(); if ($page->template == "book_sales" && !$page->isTrash()) { if ($url !== "../") { $goto =$page->url . '#focus-list_price"; $event->arguments = array($goto); } } 3 Link to comment Share on other sites More sharing options...
Peter Falkenberg Brown Posted October 5, 2021 Author Share Posted October 5, 2021 Thank you, @kongondo, @bernhard, and @dotnetic! Yes, this is why the PW community ROCKS. I'll test these out soon. Thanks again! Peter Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now