Jump to content

MarkE

Members
  • Posts

    931
  • Joined

  • Last visited

  • Days Won

    10

Posts posted by MarkE

  1. Maybe there is something for this already in the API, or elsewhere, but I couldn't find it, so here is my suggestion.

    The problem is that you can't simply copy the repeater using the API in the usual way: $page2->repeater = $page1->repeater; appears to work for page 2 but messes up page1 where the repeaters get duplicated. Instead you have to copy over each of the field values within each repeater item.

    So  I wrote this. It seems to work, at least in my context. I placed it in init.php. (However, it would be better if the core handled this more intuitively 😁)

    /**
     * Copies a repeater field to another page
     * Operates on the RepeaterPageArray object e.g. $page->repeater->copyTo($page2)
     *
     * @param HookEvent $event
     *
     */
    wire()->addHook('RepeaterPageArray::copyTo', function ($event) {
    	$repeater = $event->object;
    	$repeaterField = $repeater->getForField();
    	$page = $event->arguments(0);
    	if(!$page->hasField($repeaterField)) {
    		$event->error("Field $repeaterField does not exist on page");
    		return;
    	}
    	$page->of(false);
    	foreach ($repeater as $item) {
    		$newItem = $page->$repeaterField->getNew();
    		foreach($item->getFields() as $f) {
    			$newItem->$f = $item->$f;
    		}
    		$newItem->save();
    		$page->$repeaterField->add($newItem);
    	}
    	$page->save();
    });

     

    • Like 2
  2. On 7/18/2017 at 11:12 AM, Robin S said:

    Not sure why it half-works with role names, but the Roles field is a Page field and the correct way to match a Page field in an inputfield dependency is by ID.

    https://processwire.com/api/selectors/inputfield-dependencies/#example-page

    Resurrecting an old post here! The reference above says "Note: we will soon support specification of page references by /path/to/page/ as well." That was a while back, but still seems not to be the case. I like to use page paths wherever possible, as it is so much easier to see what is happening (although to be safe, setting the page to 'system' may be wise as I doubt it could be made to track moves).

  3. On 2/11/2024 at 6:41 PM, szabesz said:

    I am also a big fan of Unpoly, which (to me) IS "ProcessWire" but in the JavaScript world. If I were to modernize ProcessWire's JavaScript code, I would certainly choose Unpoly while also keeping jQuery. They can complement each other instead of conflicting in terms of concurrency.

    Prompted by this, I tried using Unpoly in the back end, to achieve a bit more customisation than with pw-modal. It looks nice but loading a page edit content in an overlay seems to lose all the tabbing.

    • Like 1
  4. 1 hour ago, netcarver said:

    PR against the original, maybe with some suitable config settings to allow control of target templates/roles etc?

    I considered that, but my use case does not really need it to be configurable. I could allow superuser to configure template and parent in the module settings, but I would then need a more generic title for the setup page (presently it is “Import members from csv” so it refers to the specific context so as to be more meaningful to the user). If others wanted a configurable module, then it would not be too hard to do. 

  5. Does anyone have any views on the merits of extending another module when you can't hook the required methods? I came across this recently with ImportPagesCSV. I wanted to restrict the target template and parent and then make the module accessible to a certain role (less than superuser). The buildForm1 and processForm1 methods are not hookable. Even if they were, I would have to re-use most of the code in the hook and replace the $event->return, which seems a bit messy. I guess I could hook the whole execute method, but that would be messier still. Also, the module has no permission set. Alternatively, I could suggest some additional features to @ryan, but that might take a little while to resolve. 

    So my solution was just to extend the module with my own module - 3 methods and done. It also meant I could rename the setup page to something more specific.

    I've not done this before, but was very easy and seems to work well. Are there any downsides? I guess the obvious one is if some incompatible change was made to the original module and I update it, but that seems unlikely and would also affect the 'messy' hook. It seems better than hacking the original module 🙂 

  6. 57 minutes ago, bernhard said:

    but do you think this is related?

    Absolutely! I guessed you had come across something similar. So I did an analagous edit to pwimage.js (but not specifically aimed at a repeater - the editable item might be an ordinary page, in my case in a page table). That saves having to mess with PageFrontEdit.module and is a lot simpler. I need to look more closely at the rest of the issue commentary to see what applies...

  7. On 1/22/2024 at 10:03 AM, MarkE said:

    In any case, is there a way of making the image select field pick up the 'right' page?

    I have done this by hacking PageFrontEdit.module as follows.

    There are two parts to the hack. Part 1 puts the id of the page being edited with the inline editor into the (hidden) tag with #Inputfield_id, rather putting the host page id there (this is what is used in the js to pick up the page id). Part 2 then partially suppresses the error that arises because the page being edited is not the host page (there may be a more elegant and safer way of doing this).

    I'd be grateful for any comments (esp from @bernhard) as to whether

    • you think some change to this effect should be made
    • you have any problems with the suggested changes or have a better idea
    • I should raise an issue for this?

    Part 1

    Line 429 if($hasEditTags) $numEditable += $this->populateEditTags($page, $out); - replace by

    		$editPage = $page;
    		if($hasEditTags) {
    			$editTags = $this->populateEditTags($page, $out);
    			$numEditable += $editTags['num'];
    			$editPage = $editTags['page'];
    		}

    then in lines 442 & 444 replace $this->renderAssets() by $this->renderAssets($editPage)

    In populateEditTags() change the return PHPDoc comment to @return array [Number of tags populated, page being edited], change the return in line 510 to 

    	if(!preg_match_all('!<' . $tag . '([^>]+)>(.*?)</' . $tag . '>!is', $out, $matches)) return ['num' => 0, 'page' => $page];

    and change the return at the end of the method to

    return ['num' => $numEditable, 'page' => $p];

    In renderAssets(), change the top to 

    	public function renderAssets($editPage = null) {
    		if(!$editPage) $editPage = $this->page;

    and add the @param comment @param null|Page $editPage

    Then change line 853      "<input type='hidden' id='Inputfield_id' class='PageFrontEdit' value='{$this->page->id}' />" . // for CKE plugins to

    			"<input type='hidden' id='Inputfield_id' class='PageFrontEdit' value='{$editPage->id}' />" . // for CKE plugins

    Part 2

    In inlineSaveEdits() change lines 1077-8 from

    		} else if($pageID != $this->page->id) {
    			$data['error'] = "Edited page does not match current page ID ($pageID != {$this->page->id})";

    to 

    		} else if($pageID != $this->page->id && !$this->pages()->find("id=$pageID, has_parent={$this->page}")) {
    			$data['error'] = "Edited page does not match current page ID (or is not a child) ($pageID != {$this->page->id})";

     

  8. I think this is a bug rather than anything specific with my set-up, but it would be nice to know if anyone else has this problem.

    If I have a page table field in a page which is itself in a page table field and I edit the (intermediate) page containing it (in a modal), but the only change I make is the sort order of the page table items, then the save button has no effect - I need to change something else (and change it back) in order for the save to be effective.

  9. I have a page ('host page') with a Page Table field. The host page template is designed to render content from it and its children in the page table - a fairly standard set-up. The children have a text area field called motif_body (which I currently have set as TinyMCE, but the situation is the same with CKEditor). I am using front-end editing of this text area field, like this (in Latte):

        <edit page="{$page->id}" field="motif_body">
        {$page->motif_body|noescape}
        </edit>

    where $page is the child page in this case. That works correctly and the child textarea field is made available for in-line editing in the front end. The problem arises when embedding images in the field. The child page also has an images field but, if 'insert image' is chosen, then the 'select image' modal shows the images on the host page, not the child page. (In my case it shows no images as the host page does not have an images field). You then have to navigate all the way through the page tree to find the child page and add the images from there. Once images are embedded in the textarea field then they are editable perfectly normally.

    It seems wrong to me that editing a field in the child page should look to the host page for images rather than the page the holds the field you are editing. I assume that this is because the 'image select field' in the modal is defaulting to the page which is open in the page editor rather than the page which holds the field being edited. Is this the intentional behaviour and, if so, why?

    In any case, is there a way of making the image select field pick up the 'right' page?

    • Like 1
  10. 1 hour ago, Robin S said:

    As far as I know, this is all that's needed to initialise an inputfield in all circumstances regardless of if AJAX-loaded or inside new or existing repeater items:

    I think that's right @gornycreative. I hit this problem with htmx and repeaters - this was my solution:

    // To make sure that hx- attributes fire in lazy-loaded repeater fields
    $(document).on('reloaded', '.InputfieldRepeater', function (event) {
        htmx.process(this);
    })

     

    • Like 1
  11. Thanks @matjazp. The issue is well-documented there.  In my case, it ocurred after a database load and a modules refresh (not a PW update). I suspect the issue was caused by loading a database from a later PW version (3.0.229). I removed the rows from the modules table and all seemed OK after that.
    I then updated to 3.0.235 and the rows are back in the table, but no errors are shown.
    So it appears to not be a bug as such (or at least is fixed) but will probably still happen if someone downgrades or loads a database to an older PW version.

  12. 1 hour ago, Jonathan Lahijani said:

    browser capabilities are now much more robust and perhaps much of its capabilities are not using JavaScript's newer, native features

    .. or even taking advantage of newer html5 developments. For example, <details><summary>. I guess the fundamental issue is that this is always a moving target, so it makes sense to not try and track the latest fashion, but to move when it is clear that the way forward is established and generally accepted.

    • Like 2
  13. I kept getting these errors on my modules page on one site

    2043843114_Screenshot2024-01-19230635.thumb.png.2f4a5193c37c36e4b08f2cd7c70b7d0f.png

    I have no such modules listed, but inspection via Adminer shows that they have entries in the modules database. Each entry has data listing a number of modules, such as (for .ModulesVerbose.info).

    178
    summary
    Tracy debugger from Nette with many PW specific custom tools.
    author
    Adrian Jones
    href
    https://processwire.com/talk/forum/58-tracy-debugger/
    versionStr
    4.23.33

    I assumed that the database got corrupted somehow (but how?), so I deleted the entries. Everything seems to be OK....

    Any ideas what might have caused this? Anyway, thanks @adrianfor Adminer - always useful in extremis.

  14. 7 hours ago, Robin S said:

    But you could use a hook to call InputfieldRuntimeOnly::renderReady() after the method that calls FieldtypeRuntimeOnly::renderMarkup().

    Hmm. Thanks @Robin S. I had already tried something similar with no success. I tried your hook, but it doesn't seem to get triggered in the particular circumstances I described (i.e. when the field is not added to the templates, just included as a column).

    UPDATE: However, $wire->addHookBefore('FieldtypeRuntimeOnly::markupValue', function(HookEvent $event) seems to do the trick

    In fact, since I was using a forked hacked version of your module anyway, it was simpler to add 

    			$inputfield = $field->getInputfield($page);
    			$inputfield->renderReady();

    in markupValue() - just before return $this->renderMarkup($page, $field); 😀

  15. OK - a really simple solution if you only concerned about one Page Table Field on the relevant pages. In my case, this is in the context of a module, where the name of the Page Table field is 'motif_block_table'.

    In the module's ready():

    $this->addHookAfter('Pages::moved', $this, 'afterPagesMoved');

    then:

    	protected function afterPagesMoved(HookEvent $event) {
    		$page = $event->arguments(0);
    		$oldParent = $page->parentPrevious;
    		$newParent = $page->parent;
    		if($oldParent->id == $newParent->id) return;
    		if($oldParent->hasField('motif_block_table')) {
    			$oldParent->motif_block_table->remove($page);
    			$oldParent->setAndSave('motif_block_table', $oldParent->motif_block_table);
    		}
    		if($newParent->hasField('motif_block_table')) {
    			$newParent->motif_block_table->add($page);
    			$newParent->setAndSave('motif_block_table', $newParent->motif_block_table);
    		}
    	}

    So now I have only one operation - namely to move the page in the page tree - and both fields get reset accordingly (although it may be necessary to re-sort the receiving page table as the new child will be added at the end, regardless of where you drag it in the tree). NB this will not work unless your page naming ensures unique names, as there is a risk that the new parent already has a page with the same name as the one you are moving and the move will be forbidden until you rename one of them.

    This could easily be generalised to operate outside of a module.

    It could also be adapted to refer to an unspecific Page Table field, provided there is only one. If there is more than one Page Table field and you want to track moves, it gets a bit trickier: finding the field to remove the page from is easy enough; then you either need to do something clever in js to select which field it is added to, or else (probably simpler) just go to the page and add the new child to the relevant field.

  16. It would be nice to have a simple-to-use solution for this - like the copy/clone/paste options now available for repeaters. My current method is:

    1. In the page tree (using the 'children' tab is best, assuming there is a common parent), copy the page
    2. Delete (trash) the old page
    3. Move the copied page to the new location, edit the title and any other required fields and publish it.
    4. In the Page Table listing for the new parent, add the new child

    It would be super to halve the number of steps:

    1. In the old Page Table list, cut/copy the page
    2. In the new Page Table list, paste the page
×
×
  • Create New...