Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 02/13/2021 in all areas

  1. A couple weeks ago there were a lot of ideas about page builders and different approaches in ProcessWire. Some really interesting ideas actually, and great proof of concepts as well. The conversation started moving faster than I could keep up with, and I think Teppo's summary in ProcessWire Weekly 351 is a great overview, if you haven't yet seen it. These are so great in fact, that I don't think anything I build could live up to what some of you have already built. In part because my focus is more server-side than client-side development, and I can clearly see most of these page builders are much more client-side based than I have expertise in (though would like to learn). Whereas some of you are clearly amazing client-side developers; I'm blown away by what's been built, and how quickly it happened. One struggle I have with page builders is that I don't have my own good use cases for them, with the projects that I work on. Others here (like Jonathan) already have a lot of good use cases. Clearly there are a lot of benefits. I'm fascinated and enthusiastic by all of it, but can't envision how or if I'd use such a tool in my own projects. And having experience with (and particularly close use cases for) a tool is important in hitting the right notes in building it. Likely page builder support belongs in ProcessWire in some form or another, and ProcessWire can be an excellent platform for it. But the actual page builder needs to be designed and built by the people that have expertise in the tools needed to build it, and by the people that will actually use it. I think it should be a community collaboration. For anything needed to support this on the PHP side, count me in. I don't think I've got the background to "lead" the development of the page builder, but I do think I've got plenty to contribute to it. I'd also like to continue building out existing tools like Repeater/Matrix to further support page builder type use cases. I'd like to rebuild and move the auto-save and Live Preview features from ProDrafts into the core, which should also help support some of these page builder cases. Whether these will eventually apply to the larger page-builder project, I don't know, but they'll be useful either way. What are the next steps? Who's interested in working on this? Let's keep the conversion going and move forward with it.
    12 points
  2. @Robin S - I have been using this module since it was released and always thought it was a necessary tool for inserting Hanna codes, but I just starting using some of its other features like: linked_page__pagelistselect which makes it an entirely new beast - amazing. Thanks!
    1 point
  3. @MoritzLost Thanks again! This seems to be the best way to handle it. I will further investigate if it complicates my current setup too much. But I get the benefits now. Hopefully this will help others too. I'm generally ok with making some assumptions in my case, because you can change the CSS stuff inside the backend for each item (and the breakpoints you want) anyway, also its easy enough to overwrite some css rules with plane css/scss. Maybe I provide some api options and helper functions along the way, so this is definitely helpful. Here is a preview of the module I'm developing to give you a little more context:
    1 point
  4. @jploch Ok, so currently you have a procedural approach, which is fine for a fixed use-case. My proposed solution might be overkill for what you're trying to achieve. And it will definitely be more work - and maybe the more general application for your module (which I don't even know the scope or precise purpose of) that I'm imagining isn't even what you're trying to achieve. So before you start refactoring, consider if it will actually be of benefit to your module! And of course, if you have to use code that you don't fully understand the purpose of, it won't help you in the end. If what you have is working fine for your use-case, maybe you don't need all that stuff. So just take my approach with a grain of salt ? I would start by creating classes that represent the building blocks of your page builder. That would probably include a class that represents a list of CSS rules (that can use WireArray), a class for individual items (with a reference to a list of CSS rules) and a class for a list of items (this again can use WireArray). Decoding JSON would probably be the responsibility of the latter. Though of course you can also go with a more eleborate approach to transforming JSON to classes like the builder pattern. Here's a start (I wrote this in the browser, so it will need some polish and might include some errors, but hopefully it communicates the idea behind it): // this class represents a list of CSS rules, as included in your JSON data class PageGridCSS extends WireArray { /** This class gets methods to set, get and remove CSS rules, and render them to CSS. */ } class PageGridItem { // PHP 7.4+, for older PHP versions use a protected property with getters and setters public int $id; // each item holds a reference to a set of rules public PageGridCSS $cssRules; /** This class gets properties and methods corresponding to the data it represents */ } class PageGridData extends WireArray { // guarantee that this can only hold PageGridItem objects public isValidItem ($item) { return $item instanceof PageGridItem; } // make PageGridItems accessible by their ID public function getItemKey($item) { return $item->id; } // convert json to the appropriate classes public static fromJSON (string $json): PageGridData { $items = json_deocde($data)['items']; $dataList = new self(); foreach ($items as $item) { $dataItem = new PageGridItem(); $dataItem->id = $item->id; /** Add all the properties to the item, catching missing or malformed data */ $dataList->add($dataItem); } return $dataList; } public renderCSS() { // render the CSS for the items this instance contains } } Why even do all this? Currently, your dynamic template makes a couple of assumptions that I, as a user of your module, may not agree with. For example: It always includes style tags. What if I want to save the output in a CSS file and serve it statically? You infer the context (backend / frontend) which doesn't always work reliably. I also can think of some reasons why I would like to get the code for the frontend in the backend - for example, to save it to a field. Your ".breakpoint-{...}" classes may interfere with my own stylesheets, so I could use a way to rename them. Maybe I want only a part of the stylesheet, like the rules for a specific breakpoint. ... Making all this modular and giving users access to the functionality through a well-defined API with utility methods allows me to customize all this and access the parts that I want to use, changing those that I need to. Though again, maybe I'm totally wrong regarding the intent and scope of your module. This way a fun exercise to think through anyway, hopefully it will be helpful to you or others looking for something similar ? Hm, maybe that stuff would make a good article for processwire.dev ... ?
    1 point
  5. Following the above discussion, I decided that it made more sense to display the title rather than the path (since it is only for display purposes). I also wanted a solution for attribute types pagelistselectmultiple, not just pagelistselect. In case it is useful to anyone else, my suggested js is: $(document).ready(function() { /* Author: Mark Evens, based on an original script by Robin Sallis */ /* This version displays the title text rather than the path name */ /* It also works for pagelistselectmultiple as well as pagelistselect */ /* Hide the text field */ /* id_title is the name of a text attribute in the hanna code*/ /* change id_title throughout the code below to match your attribute name */ $('#wrap_id_title').addClass('hide-field'); // Must use mousedown instead of click event due to frustrating event propagation issues across PW core // https://github.com/processwire/processwire-issues/issues/1028 // .PageListActionSelect is the button 'Select' with appears when a page is clicked (no normally visible - loaded by js) $(document).on('mousedown', '.PageListActionSelect a', function (event) { var id_title; // Adapt unselect label to suit your language if ($(this).text() === 'Unselect') { id_title = ''; } else { id_title = ($(this).closest('.PageListItem').children('.PageListPage').text()); // replace .text() by .attr('title') for path name } $('#id_title').val(id_title); }); // For pagelistselectmultiple, get all the selected pages when the selection is updated // This returns the contents of the label displayed in the pagelist item. This can be set in your HannaCodeDialog::buildForm hook // The default is the page title. For the path name, set $f->labelFieldName = 'path'; in your hook $(document).on('change', '.InputfieldPageListSelectMultiple', function(event) { var id_title = []; $(this).find('.InputfieldContent ol li:not(.itemTemplate)').each(function(){ id_title.push($(this).children('span.itemLabel').text()) }) $('#id_title').val(id_title); }); }); To hide the id_title attribute in the dialog, you need to add the following css: #hanna-form .hide-field { display: none !important; }
    1 point
  6. @MoritzLost Thank you for the detailed answer! I'm still at a very beginner level with php, all I know about it, I basically learned from using PW and it's api. Doing mainly frontend development, this is the first bigger module I'm building. So I'm still new to how classes work. Now that I have another look at it, what you sad makes a lot of sense. I will try to implement the class approach with my own utility methods. I will also have a look at WireArray, this seems like a nice solution. Thanks again for your help. I might come back at you if I hit another roadblock.
    1 point
  7. Another way? // Make all field inputfields non-editable in Page Edit $wire->addHookBefore('ProcessPageEdit::execute', function(HookEvent $event) { if(!$event->wire()->user->hasRole('read-only')) return; $event->wire()->addHookAfter('Field::getInputfield', function(HookEvent $event) { $event->return->editable(false); }); }); // Remove the Settings tab $wire->addHookAfter('ProcessPageEdit::buildForm', function(HookEvent $event) { if(!$event->wire()->user->hasRole('read-only')) return; $form = $event->return; $tab = $form->find('id=ProcessPageEditSettings')->first(); $form->remove($tab); $event->object->removeTab('ProcessPageEditSettings'); });
    1 point
  8. Hey Ryan... you're impressing me - now you can also timetravel ? Thank you for your update!
    1 point
  9. Please see upgrade note for 2.0.0 - After the update, you need to perform a module refresh directly so that the database schema is updated.
    1 point
  10. Then the user is your own module. All the points in my post above still apply – your module has to make some assumptions about the structure of the JSON data. Even if the data is only consumed internally, passing unstructred data around can cause unexpected errors at any point. So it's still better to parse the data into a representation that makes guarantees a specific data structure, and raise errors during parsing (as opposed to a random error anywhere in your module's lifecycle that's hard to track down). Also, will your module not allow customization through, for example, custom page builder elements or hooks? As soon as that's the case, developers using your module will have to use your data, so it should provide a uniform interface to accessing that data. Basically, any ProcessWire class representing some sort of collection, so you can check out those. For example, check out Pagefiles, FieldsArray and PageArray which all extend WireArray. See how they make use of all the utility methods WireArray provides and override just the methods they need to customize to adapt the WireArray to a specific type of data? For example, check out FieldsArray::isValidKey only allows Field objects to be added to it, so adding anything else will immediately throw an error. You can use this to map your pagebuilder items to a specific class and then have a class like PageBuilderItems extending WireArray that only accepts this class as items. This will go a long way towards having a uniform data structure. Again, don't mix up storage and representation. For storage, I would prefer the second example you posted, with items being an array instead of a map and the ID being just a regular property. Simply because arrays are more convenient to create, parse and map (in JS especially, but also in PHP). Though again, it doesn't matter as soon as you parse the data. The representation your module (or others, see above) uses to access the data can provide utility methods, like accessing an item by key. Regarding the last point specifically, WireArray can help you with this. The documentation is kind of handwaivy about how WireArrays handle item keys – WireArray::add doesn't take the key as an argument, but WireArray::get allows you to get an item by key, so where does the key come from? If you check the source code, turns out WireArray automatically infers a key based on the item – see WireArray::getItemKey. Your custom class can extend this to use the ID property of a given item as the key. For example, FieldsArray::getItemKey does exactly this. This allows you to use page IDs to access items without having to store your data specifically as a map. On top of that, you can use all the other utility methods WireArray provides to access elements in the any way you like.
    1 point
  11. I must admit that this is something I had not envisaged.. my mind was focus on people existing contents ?
    1 point
  12. What is about starting at early state without that feature? Just with the possibility or limitation to use it for new (empty) projects? Who has said this: "Release early and often"? Don't remember. And yes, I know, there are not only pros with this strategy. ?
    1 point
  13. Another SchedulePages user here. Works just fine for PW3 ?
    1 point
×
×
  • Create New...