Go to main content

Textpattern CMS support forum

You are not logged in. Register | Login | Help

#1 2017-05-24 14:12:10

jeroenvg
Member
From: netherlands
Registered: 2010-04-21
Posts: 34

raising errors during plugin setup

for a plugin i’m building, i need to check some things before allowing it to be used (e.g. check preference settings, plugin dependencies, database table creation, …).

these checks run during the ‘enabled’ step of my plugin; if i find a problem/ error, i want to do two things:

  1. report error to the pilot,
  2. disable the plugin, so (the rest of) my checks run when pilot fixed the problem and activates my plugin again.

what goes wrong

(please bear with me, this is hard to explain clearly.)

for every error my plugin detects, it calls:

jvg_booking_announce_async(array($message, E_ERROR), true);

where $message holds the problem report, and true makes it modal. the function itself looks like this:

/**
 * wrapper for Textpattern announce_async()
 *
 * Output notification message for asynchronous JavaScript views.
 *
 * @param   array   $message Message text and status flag
 * @param   bool    $modal If TRUE, immediate user interaction suggested
 * @return  string  JavaScript
 */
function jvg_booking_announce_async($message = array('', 0), $modal = false) {

  global $theme;

  echo script_js(
    $theme->announce_async($message, $modal)
  );

  echo script_js(
    <<<'EOS'
    $(document).ready(function () {
      sendAsyncEvent('event=plugin&step=switch_status&thing=jvg_booking&value=Yes', function () {}, 'text');
    });
EOS
  );
}

(the first script reports the error, the second one disables my plugin by calling switch_status() again.)

normally, a pilot click on ‘Admin: Plugins: jvg_booking: Active: No’ posts ‘No’ in an XMLHttpRequest to TXP’s switch_status() function on the server, which does its thing and then echoes ‘Yes’ to the client to replace ’No’.

all fair and good, if it wasn’t for my function. because it adds two scripts to switch_status()’s output, things start hitting the fan. where the normal HTML structure for ‘No’ would be:

<td class="txp-list-col-status">
  <a class="switch_status async" href="?event=plugin&amp;step=switch_status&amp;thing=jvg_booking">No</a>
</td>

after i reported an error, it will be:

<td class="txp-list-col-status">
  <a class="switch_status async" href="?event=plugin&step=switch_status&thing=jvg_booking">
    <script>
      window.alert(“<error_message>“)
    </script>
    <script>
      $(document).ready(function () {
        sendAsyncEvent('event=plugin&step=switch_status&thing=jvg_booking&value=Yes', function () {}, 'text');
      });
    </script>
    "Yes"
  </a>
</td>

(note that both scripts from jvg_booking_anounce_async() are inserted into the A element.)

on pilot’s next click on ‘No’, all of A’s contents will be posted to the server (TXP), confusing switch_status() to conclude i meant ‘No’ (because i sent garbage instead of ‘Yes’), resulting in enabling my plugin and returning ‘Yes’ (the opposite of what i’m after).

what i’d like to know

  • is it possible to output both of my scripts somewhere else, preferably in html HEAD?
  • the documentation for script_js() for example, mentions: “The $route parameter allows script_js() to be included in fixed page locations (e.g. prior to the </body> tag) but to only render its content if the event / step match.”
    but i don’t understand how to use this parameter, and can’t find a more elaborate example.
  • am i going about this the ‘right’ way? is there an easier/ better way to setup a plugin, while maintaining to possibility to throw fatal errors?

Offline

#2 2017-05-24 15:16:37

Bloke
Developer
From: Leeds, UK
Registered: 2006-01-29
Posts: 11,250
Website GitHub

Re: raising errors during plugin setup

I’ve never done this, so I’m not sure how successful it’ll be. If you intercept the state switch, you’re right that it expects its return package to be a simple gTxt() yes/no. It’s a bit limited in that respect. If you return anything else, it’ll display it on the page!

is it possible to output both of my scripts somewhere else, preferably in html HEAD?

Yes. You can raise a callback on admin_side > head_end. If you import the global $event / $step into that function, you can test if it matches what you want and take action, or just return nothing if you don’t care about that event/step:

function jvg_booking_inject($evt, $stp)
{
   global $event, $step;
   if ($event === 'something_you_want') {
      echo script_js('...');
   }
}

“The $route parameter allows script_js() to be included in fixed page locations (e.g. prior to the </body> tag) but to only render its content if the event / step match.”

Look in the end_page() function in lib/txplib_html.php. It’s used there to restrict zxcvbn to only appear on certain pages. See if that helps get you on the right track.


The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.

Txp Builders – finely-crafted code, design and Txp

Offline

#3 2017-05-25 13:12:35

jeroenvg
Member
From: netherlands
Registered: 2010-04-21
Posts: 34

Re: raising errors during plugin setup

thanks for the pointers!

Offline

#4 2017-06-10 19:24:32

jeroenvg
Member
From: netherlands
Registered: 2010-04-21
Posts: 34

Re: raising errors during plugin setup

Bloke wrote #305758:

Yes. You can raise a callback on admin_side > head_end. […]

i tried that like this…

if (txpinterface === 'admin') {
    ...
    register_callback('jvg_booking_attach', 'admin_side', 'head_end');
}

...

function jvg_booking_attach($evt, $stp) {

    global $event, $step;

    if ($event === 'plugin') {

        echo script_js(
<<<'EOS'
$(function () {

    $("a.switch_status.async[href*='jvg_booking']").on(
        'click',
        function () {
            sendAsyncEvent(
                'event=jvg_booking&step=jvg_booking_setup',
                function (data) {
                    $('head').append(data);
                },
                'text'
            );
        }
    );
});
EOS
        );
    }
}

…to attach an event listener to the Active link for my plugin, that calls my jvg_booking_setup() when pilot enables it.

(note that i’m not calling jvg_booking_setup() anymore in the enabled step of my plugin, as i did in my first message. that’s because its output will then be added to the A element, like i described there. in the code in this message, i’m calling jvg_booking_setup() directly, the same way TXP calls switch_status().)

won’t work, tho: on a normal page that lists installed plugins, my script is not added to HEAD. this may be because plugin developers are not allowed to hook into the plugin event. Admin-side events and steps says: “Third party plugins do not run on this panel.” 1.

i’ve worked around that by adding my script to custom.js for the theme, and only attach my event listener when we’re on the right admin page, like:

$(function () {

    if ('textpattern' in window) {

        if ((textpattern.event === 'plugin' && textpattern.step === 'plugin_install') ||
            (textpattern.event === 'plugin' && textpattern.step === '')) {
            $("a.switch_status.async[href*='jvg_booking']").on(
                'click',
                function () {
                    sendAsyncEvent(
                        'event=jvg_booking&step=jvg_booking_setup',
                        function (data) {
                            $('head').append(data);
                        },
                        'text'
                    );
                }
            );
        }
    }
});

this works, but only part of the time. mostly just after installation, jvg_booking_setup() starts returning (asynchronous) error messages the way i intended, but after a while i only get…

<p class="restricted-area">Restricted area.</p>

…back from TXP. apparently i’m hitting a security tripwire, but i don’t understand why this doesn’t happen all || none of the time.

edit: explained some more.

  1. a this is not entirely true: i’ve found that the callback adds my script during the plugin_install step (first installation) and plugin_multi_edit step (deletion) of a plugin. but that is not enough for my purpose; i need it to always be present on the page that lists all plugins (event 'plugin', step '' OR event 'plugin', step 'plugin_install').

Last edited by jeroenvg (2017-06-11 17:19:25)

Offline

#5 2017-06-16 15:45:40

jeroenvg
Member
From: netherlands
Registered: 2010-04-21
Posts: 34

Re: raising errors during plugin setup

jeroenvg wrote #305913:

<p class="restricted-area">Restricted area.</p>

this happens because my script in custom.js (HEAD) calls a function from my plugin, while TXP’s switch_status() just disabled it from its own event handler.

it has nothing to do with ‘tripwire’ and does not happen ‘after a while’, as i thought i saw. this is how it’s supposed to work. my bad.

(tinkering with the same content block from two disjunct functions may not be the best way to go about this.)

Offline

Board footer

Powered by FluxBB