Jump to content

Robin S

Members
  • Content Count

    3,797
  • Joined

  • Last visited

  • Days Won

    225

Posts posted by Robin S


  1. 2 hours ago, regesh said:

    It has some bugs with toggle field value as dependency and when is used for field_tab

    @regesh, that's a pretty vague statement. A proper bug report needs to include an exact description of the bugs and steps to reproduce them. Otherwise it's difficult to respond.

    As far as I can see the module works with FieldtypeToggle just fine. If you want to match a Toggle field in a selector you have to use the integer value - that isn't specific to this module, it's the way the PW core works.

    2020-07-15_101907.png.d0a8080b04c2e29824c7a791f832867a.png

    And by "field_tab" do you mean the core "Fieldset in Tab (Open)" aka FieldtypeFieldsetTabOpen? The module also works fine with this fieldtype so I don't understand the problem.

    If instead you are talking about the tab option of the non-core FieldsetGroup module that is part of ProFields then I've added support for that in v0.2.2.


  2. 15 hours ago, schwarzdesign said:

    I have the HTML Entity Encoder turned off (because that is handled by Twig in our setup), but I'm still getting the cut-off title.

    Yes, what I'm saying is that if you have HTML Entity Encoder enabled for the Title field then you wont get the cut off title, because < will be encoded to &lt; and so strip_tags() will leave it alone. The issue you've raised probably hasn't been noticed before because PW has the HTML Entity Encoder textformatter applied to the Title field by default and it's rare to disable it.

    If you're wanting to avoid double-encoding by Twig then until the issue is fixed you could just encode the title field before Page List renders the label:

    $wire->addHookBefore('ProcessPageListRender::getPageLabel', function(HookEvent $event) {
    	$page = $event->arguments(0);
    	$page->title = htmlspecialchars($page->title);
    });

     

    • Like 3

  3. Another approach to try:

    // Store page changes in custom property on $wire
    $wire->addHookAfter('Page(template=contact|sample)::changed', function(HookEvent $event) {
    	$page = $event->object;
    	$what = $event->arguments(0);
    	$old = $event->arguments(1);
    	$new = $event->arguments(2);
    
    	$page_changes = $event->wire('page_changes') ?: [];
    	$page_changes[$page->id][$what] = [
    		'old' => $old,
    		'new' => $new,
    	];
    	$event->wire('page_changes', $page_changes);
    });
    
    // Send email if there are page changes after the request is finished
    $wire->addHookAfter('ProcessWire::finished', function(HookEvent $event) {
    	$page_changes = $event->wire('page_changes');
    	if($page_changes) {
    		// Send the email using the values in $page_changes ...
    	}
    });

     

    • Like 3
    • Thanks 1

  4. @xportde, the ouput is trimmed of whitespace because the field render makes use of TemplateFile::render and by default the trim option is set to true.

    /**
     * Trim leading/trailing whitespace from rendered output?
     * 
     * @var bool
     * 
     */
    protected $trim = true;

    There's no built-in way to change that setting in the render() call but you can change it with a hook if it's important:

    $wire->addHookBefore('TemplateFile::render', function(HookEvent $event) {
    	$tpl = $event->object;
    	if($tpl->field && $tpl->field->name === 'your_field_name') {
    		$tpl->setTrim(false);
    	}
    });

     

    • Like 2

  5. @digitex, thanks for alerting me to this issue. I've made a change in v0.2.0 that should solve the issue.

    A note for all users of the module...

    Before v0.2.0 the Custom Inputfield Dependencies module did not render an inputfield in Page Edit if it determined that the inputfield should be hidden. But this creates problems if the inputfield and its neighbours have column widths of less than 100%. So from v0.2.0 onwards hidden fields will be rendered in Page Edit and hidden with CSS, so effectively the same type of hiding as occurs with the core inputfield dependencies feature.

    • Like 1
    • Thanks 1

  6. 7 hours ago, adrian said:

    In my humble opinion, that module is too broken to use and hasn't seen any updates since 2017

    And it's also unique AFAIK in being the only module in the directory that doesn't have a support thread, which isn't great because it causes questions to be scattered all across the PW forums. And potential users should probably interpret the absence of a support thread as meaning "you are on your own if you use this module".

    • Like 2

  7. 14 hours ago, Juergen said:

    Therefore you can get the values (array) only by using

    
    $this->hasField->data['foo']

    instead of

    
    $this->foo

    Well, this depends on if the stored value for the inputfield has been set as a property of the class. There are multiple different places you might use an inputfield and it's up to you to get the value you want to set to it. How you get it doesn't have anything to with InputfieldCheckboxes per se - you just need to make sure you are setting an array as the value.

    If the inputfield is used in the getModuleConfigInputfields() method of a module then the value stored in the module config is automatically set as a property of the module class.

    Alternatively, if you have a config field for an Inputfield module (in the getConfigInputfields() method) that is used with a PW field then this config data is stored on the field, because only the field has a record in the database. In other words there is a "fields" table but no "inputfields" table. So you can get the stored value from the $field object as you are doing, but arguably it's better to make use of the features that PW has built in to automatically populate Inputfield properties from the corresponding Field. The Field class has this code in the getInputfield() method:

    // custom field settings
    foreach($this->data as $key => $value) {
    	if($inputfield instanceof InputfieldWrapper) {
    		$has = $inputfield->hasSetting($key) || $inputfield->hasAttribute($key);
    	} else {
    		$has = $inputfield->has($key);
    	}
    	if($has) {
    		if(is_array($this->trackGets)) $this->trackGets($key); 
    		$inputfield->set($key, $value); 
    	}
    }

    What this boils down to is:

    "For every data property set on this Field object, check to see if a property of that name exists on the Inputfield object used by this field. If it does, set the value stored on this Field object as a property of the Inputfield object".

    So to make use of this you just need to set a property name in your Inputfield module's init() method, so that the property can be seen to exist when Field::getInputfield() is called. And typically you would set a default value for this property when appropriate. You can see how this is done in InputfieldRadios for example:

    public function init() {
    	$this->set('optionColumns', 0); 
    	parent::init();
    }

    By doing this:

    1. A default value of 0 is set for optionColumns

    2. Any value for optionColumns that is stored on a corresponding Field object automatically becomes available in the InputfieldRadios class as $this->optionColumns.

    • Like 3

  8. The below assumes that your Page Reference field on the child pages is named "categories".

    If you want duplicates or don't care about duplicates:

    foreach($page->children() as $child) {
    	foreach($child->categories as $category) {
    		echo $category->title;
    	}
    }

    If you don't want duplicates:

    // Create empty PageArray that will hold the categories
    // By default each page can only exist once in a PageArray (hence no duplicates)
    $categories = new PageArray();
    foreach($page->children() as $child) {
    	$categories->add($page->categories);
    }
    foreach($categories as $category) {
    	echo $category->title;
    }

     

    • Like 1
    • Thanks 1

  9. 10 hours ago, maddmac said:

    I would need to send a list of files to a form processor page that would collect the files to be zipped dynamically. Of course to do that I need a unique identifier to be passed.

    What will suffice for the unique identifier depends on if the selectable files are all stored in the same field on the same page. If they are then the values in your select multiple that the user chooses the files with can just be the filenames of the files,  e.g.

    <option value="filename_foo.pdf">Foo</option>

    But if the files come from multiple Files fields on the same page then you'd also need to include the field name, e.g.

    <option value="my_files_field|filename_foo.pdf">Foo</option>

    And if they come from multiple pages then you'd also need to include the page ID, e.g.

    <option value="1234|my_files_field|filename_foo.pdf">Foo</option>

    With the second two options your processor page template would explode the received values on the pipe character so you can validate and get the relevant file from the relevant field on the relevant page.

    10 hours ago, maddmac said:

    I would need to send a list of files to a form processor page that would collect the files to be zipped dynamically. Of course to do that I need a unique identifier to be passed.

    What will suffice for the unique identifier depends on if the selectable files are all stored in the same field on the same page. If they are then the values in your select multiple that the user chooses the files with can just be the filenames of the files,  e.g.

    <option value="filename_foo.pdf">Foo</option>

    But if the files come from multiple Files fields on the same page then you'd also need to include the field name, e.g.

    <option value="my_files_field|filename_foo.pdf">Foo</option>

    And if they come from multiple pages then you'd also need to include the page ID, e.g. <%


  10. Two problems...

    1. As soon as you do this...

    5 minutes ago, 3fingers said:

    $insieme = $pages->find("id=$lun_sorted_up|$lun_sorted_down");

    ...you are going to lose any sorting that has been applied those PageArrays. Using $pages->find() and matching by ID doesn't preserve the order that the IDs are supplied in. Aside: $pages->getByID() does preserve the order of supplied IDs but you can't set a limit for pagination so it won't help you here.

    2.

    7 minutes ago, 3fingers said:

    if i put a "limit=20" to the selector (for pagination)

    You can't use pagination in the normal sense with this kind of sorting. Normally you use pagination for performance reasons, to avoid loading the entire result set into memory, but in this case you need the entire result set in memory so you can foreach over them to set the custom sort. That's why I said that hopefully you don't have too many results. If you have thousands of results you probably can't use this technique. If you want pagination for some other reason besides performance then you could look at something like saving the sorted PageArray to $session and then getting slices of that PageArray on each numbered results page. This post will get you started on that (substitute the sorted PageArray for images in that example):

     


  11. $pagefile->hash() is a method - it calculates/returns a value when you call the method. It doesn't represent some data that is stored in the database, so it's probably not a good candidate for finding a file.

    The unique property of a file in a Files field is the name. In other words, a given file name can only occur once in a given Files field on a given page. You can use phpMyAdmin or Tracy Adminer to take a look at the data that is stored in the database for a Files field.

    If you explain more about your scenario and what you're wanting to do then people might be able to suggest a workable approach.

    • Like 1

  12. 5 hours ago, 3fingers said:

    How can i sort the results ($insieme) from the closest to $lunghezza onwards?

    I don't think it will be possible to achieve this sort via SQL in the $pages->find() selector - you'll have to do it via PHP in memory, so hopefully you don't have too many results.

    I don't know what sort of field variante_prodotto is so you may need to adapt this if it holds multiple values but here is the general idea:

    foreach($insieme as $product) {
    	// Here you might need to cast $product.variante_prodotto.lunghezza and $lunghezza to int or float as appropriate
    	// Get difference as an absolute value as store as a custom property on $product
    	$product->difference = abs($product.variante_prodotto.lunghezza - $lunghezza);
    }
    // Sort by custom property
    $insieme->sort('difference');
    // Now output your results
    foreach($insieme as $product) {
    	// ...
    }

     


  13. 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/

    • Like 9

  14. 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?

    • Like 1

  15. 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.

     

    • Like 1

  16. On 4/22/2019 at 12:03 AM, dragan said:

    Is that by design?

    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.

    2020-06-19_103359.png.e30490ac8f4d58f1870cc17bbc428f30.png

×
×
  • Create New...