Jump to content

Prev & next navigation links in admin - help needed


slkwrm
 Share

Recommended Posts

Hi, guys. I need your help with my firs very basic module (the code is below). So here go my questions:

1) I want to place this links on the left from submit button. The thing is I can't do this with PHP because jquery script modifies the page after it's loaded (for ex. the bottom submit button is copied by jquery script to the top). So I'm not sure how I should handle it. I suppose using additional jquery script wich adds my links, but I don't really know how to do this. Should I use $this->script->add? Is it right to extend ModuleJS in this case instead of WireData? Where should I hook to inject my jquery? For now the links are placed for testing purpose near the logo at the top.

2) I can't get it working on the module edit pages and I don't know why. I think maybe it's because of the find() method is overriden in Modules class. I commented this part.

3) Is it the code too ugly and this could be solved using just a one-liner? :huh:

Not so much related questions:

1) Wouldn't it be better to initially generate admin pages using php and let jquery only init classes of elements, so that when a page is hooked after rendering it has more predictable structure. Is it possible at all, or maybe I'm overcomplicating things and there is an easier way to handle this problem?

2) Does anybody uses 3rd party libs to handle DOM manipulation or just DOMdocument and Xpath?

Thank you in advance. I'm going to go sleep now so won't be able to discuss it in the nearest hours ;)

<?php

class PageNextPrevLinks extends ModuleJS implements Module {
/**
 * getModuleInfo is a module required by all modules to tell ProcessWire about them
 *
 * @return array
 *
 */

public static function getModuleInfo() {

 return array(
  'title' => 'Page Next Prev Links',
  'version' => 101,
  'summary' => 'This module places next and prev links in a page\'s editor if the page has siblings.',
  'href' => 'http://www.processwire.com',
  'singular' => true,
  'autoload' => false,
  );

}

public function init() {

 if($this->user->isGuest()) return;
 $this->addHookAfter('Page::render', $this, 'addLinks');

}

public function addLinks($event) {

 //get current page
 $editpage = $event->object;
 //if it's not one of the edit pages then exit
 //if(!in_array((string) $editpage->process, array('ProcessPageEdit', 'ProcessTemplate', 'ProcessField', 'ProcessLanguage'))) return;
 $adminUrl = $this->config->urls->admin;
 $siblings = New PageArray();
 if ($editpage->process == 'ProcessPageEdit') {
  $page = $this->pages->get($this->input->get->id);
  $siblings = $page->siblings("include=all");
  $adminUrl .= 'page/';
 }
 elseif ($editpage->process == 'ProcessTemplate' && isset($this->input->get->id)) {
  $page = $this->templates->get($this->input->get->id);
  $siblings = $this->templates->find('');
  $adminUrl .= 'setup/template/';
 }
 elseif ($editpage->process == 'ProcessField' && isset($this->input->get->id)) {
  $page = $this->fields->get($this->input->get->id);
  $siblings = $this->fields->find('');
  $adminUrl .= 'setup/field/';
 }
 elseif ($editpage->process == 'ProcessLanguage' && isset($this->input->get->id)) {
  $page = $this->languages->get($this->input->get->id);
  $siblings = $this->languages->find('');
  $adminUrl .= 'setup/languages/';
 }
 elseif ($editpage->process == 'ProcessUser' && isset($this->input->get->id)) {
  $page = $this->users->get($this->input->get->id);
  $siblings = $this->users->find('');
  $adminUrl .= 'access/users/';
 }
 elseif ($editpage->process == 'ProcessRole' && isset($this->input->get->id)) {
  $page = $this->roles->get($this->input->get->id);
  $siblings = $this->roles->find('');
  $adminUrl .= 'access/roles/';
 }
 elseif ($editpage->process == 'ProcessPermission' && isset($this->input->get->id)) {
  $page = $this->permissions->get($this->input->get->id);
  $siblings = $this->permissions->find('');
  $adminUrl .= 'access/permissions/';
 }
 //TODO can't get it working, throws an error
 /*elseif ($editpage->process == 'ProcessModule' && isset($this->input->get->name)) {
  $page = $this->modules->get("{$this->input->get->name}");
  $siblings = $this->modules->find('');
  $adminUrl .= 'module/';
 }*/
 $out = "";
 //generate next & prev links output
 if (count($siblings)) {
  if (($prev = $siblings->getPrev($page)) && $prev) {
$out .= "<a href='{$adminUrl}edit/?id={$prev->id}'>< prev</a>";//« prev</a>";
  }
  if (($next = $siblings->getNext($page)) && $next) {
//$out .= $out ? " • " : "";
$out .= $out ? " | " : "";
$out .= "<a href='{$adminUrl}edit/?id={$next->id}'>next ></a>";//'>next »</a>";
$out .= $next->id;
  }
  if ($out <> "") $out = "<div class='NextPrevLinks'>".$out."</div>";
 }
 $event->return = str_replace('<p id="logo">ProcessWire</p>', $out.'<p id="logo">ProcessWire</p>', $event->return);

 return $event->return;

}
}
Link to comment
Share on other sites

Looking good Slkwrm!

1) I want to place this links on the left from submit button.

You may want to instead hook into ProcessPageEdit::buildForm. That function returns an InputfieldWrapper that you can add new fields to. Here's how your hook function might do it:

$f = wire('modules')->get('InputfieldSubmit');
$f->attr('name', 'submit_something'); 
$f->attr('value', 'hello');

$form = $event->return;
$form->add($f); 

I'm not positive this will do exactly what you want, but it's a good place to start.

2) I can't get it working on the module edit pages and I don't know why.

I think that the problem may be here:

$page = $this->modules->get("{$this->input->get->name}");

A module is not a $page (and it's one of the few things that isn't). There isn't such thing as a module having siblings because modules are not in any hierarchy. Though I suppose that you could sort the modules by name and figure out which is next by doing a foreach(), but you'd want to be careful here as you don't want to instantiate all the modules at once. I think it may be less hassle not to bother with the modules here. :) But if you still want to do it, let me know and I can suggest a good way.

Wouldn't it be better to initially generate admin pages using php and let jquery only init classes of elements, so that when a page is hooked after rendering it has more predictable structure.

I don't understand the question. Can you provide additional context?

Does anybody uses 3rd party libs to handle DOM manipulation or just DOMdocument and Xpath?

I think we're all just using jQuery? :)

Link to comment
Share on other sites

Wouldn't it be better to initially generate admin pages using php and let jquery only init classes of elements, so that when a page is hooked after rendering it has more predictable structure.

I don't understand the question. Can you provide additional context?

I'm not that well-versed in jQuery, so maybe my question doesn't make much sense). What I meant is that when I use inspector in Chrome and find some element and then try to use it in hook after page render it seems like it doesn't exist yet.

Also wanted to ask what is the best way to inject javascript in admin pages.

Thank you.

Link to comment
Share on other sites

What I meant is that when I use inspector in Chrome and find some element and then try to use it in hook after page render it seems like it doesn't exist yet.

I'm not sure about Chrome in that case, but in jQuery, most manipulations are done in $(document).ready(), which executes once the DOM is ready. The way you describe it, it sounds like maybe Chrome's inspector is giving you a picture of the structure before the javascript executed?

Also wanted to ask what is the best way to inject javascript in admin pages.

I think that the best way is with a separate JS file. Inputfield modules will automatically load a CSS or JS file with has the same name as the module in the same dir. The same goes for any module that extends ModuleJS. However, there isn't much to it, and it would be easy to duplicate anywhere else. This is how it does it:


public function init() {
   $class = $this->className();
   if(is_file($this->config->paths->$class . "$class.css")) {
       $this->config->styles->add($this->config->urls->$class . "$class.css");
   }
   if(is_file($this->config->paths->$class . "$class.js")) {
       $this->config->scripts->add($this->config->urls->$class . "$class.js");
   }
}

Then your js file should look like this:

jQuery(document).ready(function() {
   // your JS code
}); 
  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...