Aupajo / middleman-pagination

General purpose pagination for Middleman.
MIT License
25 stars 22 forks source link

Paginating with proxy routes #1

Open mkleywegt opened 11 years ago

mkleywegt commented 11 years ago

Hi Aupajo,

It is indeed getting rather specific. I realized that what I am trying to paginate are not really pages per se (they are now they have a route assigned to them). The payoff to this, I guess, would be having flexible general purpose pagination module for Middleman.

I will add an example for this later today.

Below is the original post from the Middleman Forum:

Background:

Here are my findings:

I have experimented with including a variable to the pageable directive, with no notable difference.

I also tried to activate pagination within the loop that defines the proxy. Middleman then reports it already activated pagination (as it tries to do it a couple of times), also without a notable difference.

mkleywegt commented 11 years ago

So, here is the relevant part of my config.rb

data.projects.details.each do |project|
  proxy "/#{project[:slug]}", "/localizable/project.html", :locals => { :project => project }, locale: :en, :ignore => false

  proxy "/#{project[:slug]}/patterns", "/localizable/patterns.html", :locals => { :project => project, :haspatterns => true }, locale: :en, :ignore => false

  project.patterns.each do |pattern|
    proxy "/#{project[:slug]}/patterns/#{pattern[:bundle]}", "/localizable/patterns.html", :locals => { :pattern => pattern, :project => project }, locale: :en, :ignore => false 
  end

  project.patterns.each do |pattern|
    p = data.patterns.details.find{ |x| x['bundle'] == pattern[:bundle]}

    p.details.each do |single|
      proxy "/#{project[:slug]}/patterns/#{pattern[:bundle]}/#{single[:slug]}", "/localizable/pattern_single.html", :locals => { :single => single, :pattern => pattern, :project => project }, locale: :en, :ignore => false
    end
  end
end
activate :pagination do
  pageable :so do |page|
  # Match any page whose URL includes "/patterns/"
  page.path.start_with?('patterns/')
  #page.data.so.present?
  end
end

As you can see, there are some variables involved that are used to pull data out of yaml files (in the templates as well).

In the template for patterns.html I have the pagination frontmatter:


pagination: for: so per_page: 2


Which is correctly read out by the extension. (Showing 2 per page) The amount of pages currently in the set cannot be determined, as are the previous and back links. So, the status is 'Page 1 of 0', all the links point to the current page, and it is not paginating the patterns.

Aupajo commented 11 years ago

Thanks, @mkleywegt, this is great. I think I can help you out.

I'll reproduce this first moment I get a chance and diagnose it from there.

Can you post an example of your data/projects.yml?

mkleywegt commented 11 years ago

Hi @Aupajo, thanks again for looking at it.

These lists get unwieldy, so I've abridged the contents.

Here's projects.yaml

---
details:
  - id: "1"
    name: "First"
    slug: "first"
    patterns:
      - id: "1"
        bundle: "main"
      - id: "2"
        bundle: "dashboard"
      - id: "3"
        bundle: "users"
  - id: "2"
    name: "Second"
    slug: "second"
    patterns:
      - id: "1"
        bundle: "main"
      - id: "2"
        bundle: "additional"
      - id: "3"
        bundle: "users"

And patterns.yaml

---
details:
  - bundle: "main"
    name: "Main"
    details:
      - id: "1"
        name: "First Button"
        slug: "first-button"
      - id: "5"
        name: "Fifth Button"
        slug: "fifth-button"
      - id: "9"
        name: "Nineth Button"
        slug: "nineth-button"
      - id: "10"
        name: "Tenth Button"
        slug: "tenth-button"
  - bundle: "additional"
    name: "Additional"
    details:
      - id: "2"
        name: "Second Button"
        slug: "second-button"
      - id: "6"
        name: "Sixth Button"
        slug: "sixth-button"
  - bundle: "dashboard"
    name: "Dashboard"
    details:
      - id: "3"
        name: "Third Button"
        slug: "third-button"
      - id: "7"
        name: "Seventh Button"
        slug: "seventh-button" 
  - bundle: "users"
    name: "Users"
    details:
      - id: "4"
        name: "Fourth Button"
        slug: "fourth-button"
      - id: "8"
        name: "Eighth Button"
        slug: "eighth-button"

Let me know if you need anything else.

Aupajo commented 11 years ago

Hey, sorry it's taken me a little while to get round to this issue.

I've successfully reproduced the issue with the configuration you've supplied, which is good news as it means it'll be easier for me to diagnose the problem.

As a side note, I found the YAML/proxy configuration set-up very hard to follow. If you're specifying slugs and making cross-references, you might find it easier to store the data in separate templates rather than in the YAML.

For instance, you could have a set up that looks like:

source/
   - layouts/
     - layout.erb
     - project.erb
     - pattern.erb
   - projects/
      - first.html.erb
      - second.html.erb
   - patterns/
      - main.html.erb
      - additional.html.erb

projects/first.html.erb can look like this:

---
name: First
patterns: [main, additional]
---

You might find it cleaner.

You might find this technique for extracting objects in Middleman of use, too.

Stay tuned for the fix with the existing set-up, though.

Aupajo commented 11 years ago

Okay, there are two steps to getting this working.

The first is with the current configuration. The solution is to have a separate pageable resource for each proxy set. Basically, the trick is to keep track of the different sets in a variable outside the data.projects.each block and share it with the activate :pagination block. You'd also need to pass in a unique name for each pageable resource and modify the pagination metadata in each proxied resource. This is a really complicated set-up.

The second is the fact you're using directory-index-style paths in your proxies (e.g. the route is /my-project-name rather than /my-project-name.html). That will prevent Middleman Pagination from being able to correctly generate the secondary index pages, but I consider it a common enough (mis)use of proxy to consider it a bug with Middleman Pagination, so I'll introduce a fix for it.

Once that fix is in place, I'll try to paste a working code example for you of how you can solve the first problem.

mkleywegt commented 11 years ago

Thank you for your suggestions. My inclination towards the YAML-heavy setup is easy of maintenance (hmm) by preventing duplicating templates (there would not have to be any difference between e.g. first.html.erb and second.html.erb). I would also be able to add and remove paginated items without having to touch the source folder.

Having said that, I agree with your sentiment that it is hard to follow and certainly not clean enough (needing slugs et cetera). I will look into refactoring that. Extracting objects will help there too. I'll wait for your fix.

Aupajo commented 10 years ago

@mkleywegt Thanks. You wouldn't have to have any duplication with the approach above (you can use layouts in place of proxied files).

Aupajo commented 10 years ago

@mkleywegt Thanks for waiting! It took sitting down for a couple of hours to hash it out :D

I've got a basic working example for you at https://github.com/Aupajo/middleman-example-for-mkleywegt

It's fairly procedural, and it might be missing a layer of pagination indexes, but hopefully it's enough for you to go on.

Some subtle things to note:

Hope that helps!

mkleywegt commented 10 years ago

@Aupajo - that is great work. Very much appreciated.

Re: proxy paths ending in .html — while the .html is included in the proxy route in the config.rb (as per your example), visiting the proxy paths only works without appending .html .

With this addition, I have the setup pretty much working. I posted a specific problem over in the other repository, see Memory leak (unless you'd like that here).

mkleywegt commented 10 years ago

And I noticed that paginated subpages use the lay-out assigned to the first page, but they don't have access to local variables. Where would I pass those?