Jump to content

Robin S

  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by Robin S

  1. @MaierGrem, do you have percentage-based widths enabled in AdminThemeUikit?
  2. This is a module that is similar in purpose to the Runtime Markup module. I made it primarily for my own use but am posting it here because I had a request to add it to the modules directory. Fieldtype Runtime Only Not a proper fieldtype because it doesn't save data to the database. The fieldtype only exists to provide a convenient way to add an inputfield to templates that will render some markup at runtime. For a field named "my_field"... Inputfield markup will be rendered from a file at /site/templates/RuntimeOnly/my_field.php. In addition to the standard ProcessWire variables this file receives: $page - the page being edited. $field - the Field object. $inputfield - the Inputfield object. JS file /site/templates/RuntimeOnly/my_field.js will be added to admin if that file exists. CSS file /site/templates/RuntimeOnly/my_field.css will be added to admin if that file exists. Tips If the RuntimeOnly field is used inside a Repeater field then you can get the Repeater page it is on via $inputfield->hasPage. E.g. $repeater_page = $inputfield->hasPage; // Use $repeater_page as needed echo "The name of the repeater page is $repeater_page->name"; https://github.com/Toutouwai/FieldtypeRuntimeOnly https://modules.processwire.com/modules/inputfield-runtime-only/
  3. Wow, that's a motherload of new search operators. Awesome! I usually want to include as many results as possible to so I tend use the LIKE operator for text searches. To bring in even more results it would be cool to use query expansion too, but I noticed that there isn't an operator that combines those two. Is that combination not possible for technical reasons?
  4. A few more ideas... 1. If the fields that are updated programmatically are only a subset of the fields in the template then you could give those fields special treatment in Page Edit. So if fields A, B and C may be updated programmatically but fields D, E and F are not then in Page Edit DEF will be rendered normally but ABC could be rendered "Closed + load only when opened (AJAX)". Or (trickier) rendered read-only via renderValue() with a button that loads them on demand via AJAX if the editor needs to change the value. The idea here is that the values for ABC are only present in the POST data if the editor has needed to load and change them. 2. In conjunction with your first idea, when your script sets field values have it also store the changed field names and update time in the $page->meta of updated pages. Hook before processInput and remove any clashing field values from POST. Use $session->warning() to alert the user if any values that they changed manually were discarded (the programmatic changes will always take priority because even if the clash doesn't happen during editing they can potentially occur one second after a user saves a manual value). 3. Store changed field names in $page->meta as per idea 2, but use JavaScript in Page Edit to regularly poll and see if any field values have been changed programmatically. If so, remove the inputfield from Page Edit and alert the user to explain. Not as bulletproof as 2 because the programmatic update could occur between polls.
  5. I think the reason might be that a week, day, hour and minute is a fixed number of seconds whereas a month or a year is a variable number of seconds. So from a given number of seconds you can't accurate calculate if a month or year has passed without knowing which month (e.g. February or March) in which year (leap year or common year). Having said that, the elapsedTimeStr() method does get supplied all the information it would need to accurately calculate elapsed months and years, it just doesn't currently take account of the actual calendar dates and simply uses the difference in seconds. For now you could use Carbon to get an accurate relative time string including months and years.
  6. Alerting the user when their session expires is one of the features of pro UserActivity module.
  7. For a brief moment I was contemplating parsing HTML with regex but then StackOverflow taught me this: https://stackoverflow.com/a/1732454/1036672 My sides are now hurting 😂
  8. Those are really feature requests for Repeater Matrix rather than relating to what this module is focused on. You could validate the Repeater Matrix field with a Pages::saveReady hook - you'd loop over each repeater item and check its matrix type and level, and give the user feedback if they make an error. But you'd be relying on the user correcting mistakes afterwards because you probably wouldn't want to be automatically deleting repeater items that are in error. If you are talking about Javascript validation then that would be more complex.
  9. Ooh, I love these kinds of challenges. 🙂 Give this a go: https://github.com/Toutouwai/IndividualSelectablePages Recommended for a better experience: https://github.com/Toutouwai/PageListSelectMultipleQuickly
  10. https://github.com/processwire/processwire-issues/issues/480#issuecomment-382383357 https://processwire.com/blog/posts/pw-3.0.99/ Percentage-based widths should be the default IMO.
  11. The issue of paginating results when sort=random has come up before. Ryan suggested finding all the IDs with a random sort, then loading pages from slices of that array. His example assumes normal pagination but could be adapted for ajax loading. $limit = 10; $start = $limit * ($input->pageNum()-1); $ids = $session->get('ids'); if(!$ids) $ids = $pages->findIDs("template=project, sort=random"); $session->set('ids', $ids); $a = array_slice($ids, $start, $limit); if(!empty($a)) { $items = $pages->getByID($a)->setStart($start)->setLimit($limit)->setTotal(count($ids)); echo $items->implode("<li>{title}</li>") . $items->renderPager(); }
  12. Ryan introduced it at the end of 2016. In my mind it doesn't seem like that long ago. I must be getting old. 😄 https://processwire.com/blog/posts/pw-3.0.44-repeaters/
  13. I just noticed that the topic title mentions field type. The jqTree library you linked to can read/write to/from JSON format, so that data can be stored in a FieldtypeTextarea. For the inputfield you could create a custom inputfield module that extends InputfieldTextarea - in the renderReady() and render() methods you would make use of jqTree. If you are not up for coding that another idea is to use the depth option available for Repeater fields. If you go this route you might also find my Repeater Depth Helper module useful.
  14. This is a module I made as an experiment a while ago and never got around to releasing publicly. At the time it was prompted by discussions around using Repeater fields for "page builder" purposes, where the depth feature could possibly be used for elements that would be nested inside other elements. I thought it would be useful to enforce some depth rules and translate the depth data into a multi-dimensional array structure. I'm not using this module anywhere myself but maybe it's useful to somebody. Repeater Depth Helper This module does two things relating to Repeater fields that have the "Item depth" option enabled: It enforces some depth rules for Repeater fields on save. Those rules are: The first item must have a depth of zero. Each item depth must not be more than one greater than previous item depth. It provides a RepeaterPageArray::getDepthStructure helper method that returns a nested depth structure for a Repeater field value. Helper method The module adds a RepeaterPageArray::getDepthStructure method that returns a multi-dimensional array where the key is the page ID and the value is an array of nested "child" items, or null if there are no nested children. Example The module doesn't make any assumptions about how you might want to use the depth structure array, but here is a way you might use it to output a nested unordered list. // Output a nested unordered list from a depth structure array function outputNestedList($depth_structure, $repeater_items) { $out = "<ul>"; foreach($depth_structure as $page_id => $nested_children) { $out .= "<li>" . $repeater_items->get("id=$page_id")->title; // Go recursive if there are nested children if(is_array($nested_children)) $out .= outputNestedList($nested_children, $repeater_items); $out .= "</li>"; } $out .= "</ul>"; return $out; } $repeater_items = $page->my_repeater; $depth_structure = $repeater_items->getDepthStructure(); echo outputNestedList($depth_structure, $repeater_items); https://github.com/Toutouwai/RepeaterDepthHelper https://modules.processwire.com/modules/repeater-depth-helper/
  15. Not exactly a module, but the page tree emulates a tree, allows drag and drop organisation of elements, and returns results as a (Page)Array. 😉 You could also use exactly that example. If you are talking about the frontend then PW doesn't place any limitations on what JS libraries you can use. And you could use it in the backend too if needed, via RuntimeMarkup for example.
  16. You would strip apostrophes from the search input also. The general idea is you strip out any characters that shouldn't affect the search from both the input and the stored index. There is discussion in this topic: On one site I've implemented a fuzzy search that uses the Levenshtein distance with the approach described here, but it was done with plain SQL and searched only the title field. Using it on multiple fields has the potential to generate a huge number of queries so performance could become an issue.
  17. I took the liberty of opening a GitHub issue for this problem: https://github.com/processwire/processwire-issues/issues/1192 As a workaround for now you could use this hook in /site/ready.php: $pages->addHookBefore('added', function(HookEvent $event) { /** @var Page $page */ $page = $event->arguments(0); /** @var Pages $pages */ $pages = $event->object; // Only for a particular template if($page->template != 'your_template') return; // Check if there is a name clash with an existing sibling page $default_name = $this->wire('sanitizer')->pageName($page->title, true); if($pages->count("parent=$page->parent, id!=$page->id, name=$default_name, include=all")) { // Manually create a proposed name $name = $default_name . '-1'; // Auto-adjust the name when needed $name = $pages->names()->uniquePageName($name, $page); // Set the name $page->setAndSave('name', $name); } });
  18. The normal way to match content in a Repeater is by searching the subfields of the Repeater. Instead of... my_field%=foo, template=repeater_my_repeater_field ...you would do... my_repeater_field.my_field%=foo That way you are matching the pages that contain the repeater field so you don't need getForPage(), plus you don't have to deal with the access restrictions on the Repeater template, unpublished repeater items, sorting of the container pages, etc. Have you considered merging the text of all the fields you want to search into a hidden "index" textarea field? It's not too difficult to do this with a Pages::saveReady hook, but to make it really easy you can use the SearchEngine module which takes this approach. Doing this has the potential to solve the other issues you raised here and here (you could strip apostrophes from text that is saved to the index field).
  19. https://github.com/processwire/processwire-requests/issues/353 I expect that is a Page Reference field and not a Select Options field.
  20. That's the thing that isn't possible due to the circular reference issue with "single" Page Reference fields. My suggestion: make one of your Page Reference fields a "multiple" field, even if you are only going to store a single page in it. That way you can use Connect Page Fields and your job will be a lot simpler. You won't need to use PHP to define the selectable pages so you'll be able to use the Page Autocomplete inputfield. Instead you can use a selector string to define the selectable pages and identify pages that not selected by another user with a string like "selected_by_user.count=0" where selected_by_user is a Page Reference field. If your user pages are only managed by superuser then you don't need to do anything special with the inputfield - it won't matter if it technically allows multiple pages to be selected because you'll know to only select a single page. Or if others need to manage the users and you think they'll be confused if the inputfield allows multiple selections then you can limit the number of selectable pages with a hook: $wire->addHookAfter('InputfieldPageAutocomplete::renderReadyHook', function(HookEvent $event) { /** @var InputfieldPageAutocomplete $inputfield */ $inputfield = $event->object; $field = $inputfield->hasField; if($field && $field->name === 'colour') { $inputfield->maxSelectedItems = 1; } }); And of course the value of this field will be a PageArray but you can get the selected page by using the first() method.
  21. Thanks for the update @ryan! Could you please take a look at what might be causing the main download button for the dev version to be stuck on 3.0.153? It's been this way for several weeks. I know that the button always links to the current state of the dev branch but it's potentially confusing to users having the version number out of sync like this. Thanks 🙂
  22. I couldn't confidently say "impossible" but the front-end is a totally different context to the back-end so it would require substantial changes to the module, and I expect there would need to be changes to PageFrontEdit to allow modules to inject CSS and JS into the frontend. I'm not that motivated to spend a lot of time on it because I never use front-end editing and if I did and needed Hanna Code Dialog I would just use Option D because in my opinion it's no great loss to switch to a modal editor for such cases. So sorry to disappoint but the response for now is "if you need Hanna Code Dialog on the front-end bad enough then use Option D". Of course the module is open-source so you are welcome to experiment with it and modify it as needed.
  23. Only if you use Option D for front-end editing in a dialog. Hanna Code Dialog works by hooking ProcessPageEdit::execute and this method isn't called when using inline front-end editing. PageFrontEdit doesn't even have any hookable methods so there's really no scope for the kind of customisation done by Hanna Code Dialog.
  24. A FieldsetPage field is a kind of Repeater, and conditionally setting the required status of inputfields within a Repeater is difficult. AFAIK you can't do this from a ProcessPageEdit::buildForm hook. And what's worse is that you'd need to hook one method to conditionally show the required asterisk in Page Edit and a different method to actually enforce the required status when the input is processed for each inputfield type within the FieldsetPage. So you'd end up needing to apply your logic in three different places. Long story short, you'll make things much simpler if you have Profields and can change your FieldsetPage to a FieldsetGroup, or failing that a standard Fieldset.
  25. You can also configure your CKEditor field to insert <br> tags instead of <p> tags on Enter. https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR.html#property-ENTER_BR
  • Create New...