PHP (NextCloud) events/listeners best practices

To give a bit on context, I am building an app in nextcloud and I am going to shoot & listen to a lot for events. I have got 2 options to tackle this problem.

1. Creating a lot of events & listeners;

For every single action within a service, I can shoot out an event which will have a listener attached. This means that I will get a lot of events and listeners within the system. Example;

$dispatcher->dispatchTyped(new reorderEvent());
$dispatcher->dispatchTyped(new assignEvent());

2. Creating 1 event for a model with actions;

I can also create just 1 event that will pass through just an action string/enum. This will reduce the amount of event files within the application. Example;

class ActionEnum: string 
{
    case REORDER;
    case ASSIGN;
}

$dispatcher->dispatchTyped(new updatedEvent(ActionEnum::REORDER));
$dispatcher->dispatchTyped(new updatedEvent(ActionEnum::ASSIGN));

Now the multi-million dollar question is, which would be considered best-practice in the long run? Or is there another solution that is even better to use?

Showing dynamic or different menus on wordpress not working in my theme

On my WordPress page, there’s a primary menu that shows up at the header of all pages, but I want to show a different set of menus for pages in the route /tech-products.

Based on my research on this site, adding the following to my function.php and then setting up the menu in Appearance → Menus → Manage Locations is expected to work, but it doesn’t work.

function register_custom_menus() {
    register_nav_menus(array(
        'primary' => 'Primary Menu',
        'tech_products_menu' => 'Tech Products Menu',
    ));
}
add_action('init', 'register_custom_menus');

Why is my XCLASSes action for the EXT:sf_event_mgt EventController ignored?

I’m trying to add a button that allows users to subscribe to my event calender via a webcall:// link. I use type=9819 to trigger the function.

I can‘t get my icalAction to work, it just gets ignored and typo3 uses the listAction from the extension instead.

Im using typo3 13.4 and sitepackage. I would like to manage the output in a fluid template

My folder structure is:

/packages
└── studilife
    ├── Classes
    │    └── Controller
    │        └── EventController.php
    ├── Configuration
    │   └── Sets
    │       └── Studilife
    │           └── TyposScript
    │               └── setup.typoscript
    ├── Resources
    │   └── Private
    │       └── Extensions
    │           └── SfEventMgt
    │               └── Templates
    │                   └── Event
    │                       └── Ical.html
    └── ext_localconf.php

This is my code so far:

ext_localconf.php:

$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][DERHANSENSfEventMgtControllerEventController::class] = [
    'className' => StudentStudilifeControllerEventController::class,
];

TYPO3CMSExtbaseUtilityExtensionUtility::configurePlugin(
    'SfEventMgt',
    'Event',
    [
        DERHANSENSfEventMgtControllerEventController::class => 'list,detail,register,ical'
    ],
    []
);

setup.typoscript:

plugin.tx_sfeventmgt {
    view {
        templateRootPaths {
            100 = EXT:studilife/Resources/Private/Extensions/SfEventMgt/Templates/
        }
        partialRootPaths {
            100 = EXT:studilife/Resources/Private/Extensions/SfEventMgt/Partials/
        }
        layoutRootPaths {
            100 = EXT:studilife/Resources/Private/Extensions/SfEventMgt/Layouts/
        }
    }
    settings {
        calendar{
            showWeekNumber = 0
        }
    }
}

pageEventICalendar = PAGE
pageEventICalendar {
    typeNum = 9819
    settings.format = txt
    config {
        disableAllHeaderCode = 1
        xhtml_cleaning = none
        admPanel = 0
        metaCharset = utf-8
        locale_all = en_EN
        additionalHeaders.10.header = Content-Type:text/calendar;charset=utf-8
        disablePrefixComment = 1
        linkVars >

    }

    10 = USER
    10 {
        userFunc = TYPO3CMSExtbaseCoreBootstrap->run
        extensionName = SfEventMgt
        pluginName = Event
        vendorName = DERHANSEN
        controller = Event
        action = ical
    }
}

eventController.php:

<?php
namespace StudentStudilifeController;

class EventController extends DERHANSENSfEventMgtControllerEventController
{
    public function icalAction()
    {
        $events = $this->eventRepository->findAll();
        $this->view->assign('events', $events);

        $this->view->setFormat('txt');
        header('Content-Type: text/calendar; charset=utf-8');
        header('Content-Disposition: attachment; filename="events.ics"');
    }
}

Im trying to get my Action to be recognized by typo3. The typoscript works fine so far, but the eventController.php is just ignored. Its my first time trying to change the behaviour of an extension, so i probably miss something very basic. I tryed to use this official typo3 documentation: https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Xclasses/Index.html.

Thanks for your help

How to properly display form data using shortcode in a custom WordPress plugin?

I’m creating a custom WordPress plugin that includes a contact form rendered using a shortcode.

Here’s my current code:

function custom_contact_form() {
  ob_start();
  ?>
  <form method="post" action="">
    <input type="text" name="name" required>
    <input type="email" name="email" required>
    <input type="submit" name="submit" value="Send">
  </form>
  <?php
  return ob_get_clean();
}
add_shortcode('contact_form', 'custom_contact_form');

I tried:

  • Using $_POST to capture form data inside the function
  • Adding action="<?php echo esc_url($_SERVER['REQUEST_URI']); ?>" to the form
  • Checking if the shortcode runs correctly in a page

But I’m not sure how to process the form submission inside the shortcode, or how to show the submitted data.

Filament filter on another table column

I’ve searched for this answer but didn’t find any, so I’m here to ask. I’m using Filament 3.2 on Laravel 12. I have a RelationManager based on a table tournament_players that has a relation on players table. I have to show and filter the results of tournament_players based on the column sex in players table that has only 2 possible values: M and F. In the columns i’ve defined the relationship and everything works

TablesColumnsTextColumn::make('player.sex')
                    ->label(__('Sex'))
                    ->sortable()
                    ->searchable(),

But when i get to filters I cannot make it work. That’s the basic

TablesFiltersSelectFilter::make('player.sex')
                    ->label(__('Sex'))
                    ->options([
                        'M' => __('Male'),
                        'F' => __('Female'),
                    ])
                    ->default(null),

Using it like this it’s not working because the query to list results doesn’t load the relation as expected. Adding the relationship like this:

->relationship('player', 'sex')

is not working also because the result is to overwrite my options with a list of M and F taken from all the players in the tournament_players table. Methods like modifyQueryUsing or getSearchResultUsing don’t give better results. What I’m doing wrong?

cdn.datatables.net connection refused, datatable won’t load

While navigating a page that include DataTable, I am getting the following errors on the browser’s console:

GET https://cdn.datatables.net/1.10.22/css/jquery.dataTables.min.css
net::ERR_CONNECTION_REFUSED

GET https://cdn.datatables.net/1.10.22/js/jquery.dataTables.min.js
net::ERR_CONNECTION_REFUSED

GET
https://cdn.datatables.net/fixedheader/3.1.7/js/dataTables.fixedHeader.min.js
net::ERR_CONNECTION_REFUSED

Consequently the DataTable is missing required resources

$(…).DataTable is not a function

What is the solution? Is there an alternative way to load the resources and make the datatable work?

I have a report in HTML and I need to highlight some data when the use inputs some text

<!DOCTYPE html>
<html>
<head>
  <title>Text Highlighter</title>
  <style>
    .highlight {
      background-color: yellow;
    }
  </style>
</head>
<body id="text">
  <input type="text" id="searchInput" placeholder="Enter text to highlight" oninput="highlightMatches()">
  <button onclick="highlightMatches()">Highlight</button>

  <div>
    <p>
      paragreaaf 1 sadasdas
    </p>
    <table>
  <caption>
    Front-end web developer course 2021
  </caption>
  <thead>
    <tr>
      <th scope="col">Person</th>
      <th scope="col">Most interest in</th>
      <th scope="col">Age</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Chris</th>
      <td>HTML tables</td>
      <td>22</td>
    </tr>
    <tr>
      <th scope="row">Dennis</th>
      <td>Web accessibility</td>
      <td>45</td>
    </tr>
    <tr>
      <th scope="row">Sarah</th>
      <td>JavaScript frameworks</td>
      <td>29</td>
    </tr>
    <tr>
      <th scope="row">Karen</th>
      <td>Web performance</td>
      <td>36</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <th scope="row" colspan="2">Average age</th>
      <td>33</td>
    </tr>
  </tfoot>
</table>
    This is an example paragraph. Feel free to search any text in this paragraph and it will be highlighted.
  </div>

  <script>
    function highlightMatches() {
      const searchTerm = document.getElementById('searchInput').value.trim();
      const body = document.body;

      removeHighlights(body);

      if (!searchTerm) return;

      const regex = new RegExp(searchTerm.replace(/[-/\^$*+?.()|[]{}]/g, '\$&'), 'gi');

      const walker = document.createTreeWalker(
        body,
        NodeFilter.SHOW_TEXT,
        {
          acceptNode: function (node) {
            if (
              node.parentNode &&
              ['SCRIPT', 'STYLE'].includes(node.parentNode.nodeName)
            ) return NodeFilter.FILTER_REJECT;
            return NodeFilter.FILTER_ACCEPT;
          }
        },
        false
      );

      const nodes = [];
      while (walker.nextNode()) {
        if (regex.test(walker.currentNode.nodeValue)) {
          nodes.push(walker.currentNode);
        }
      }

      nodes.forEach(node => {
        const frag = document.createDocumentFragment();
        const parts = node.nodeValue.split(regex);
        const matches = node.nodeValue.match(regex);

        parts.forEach((part, i) => {
          frag.appendChild(document.createTextNode(part));
          if (matches && i < matches.length) {
            const span = document.createElement('span');
            span.className = 'highlight';
            span.textContent = matches[i];
            frag.appendChild(span);
          }
        });

        node.parentNode.replaceChild(frag, node);
      });
    }

    function removeHighlights(root) {
      const spans = root.querySelectorAll('span.highlight');
      spans.forEach(span => {
        span.replaceWith(document.createTextNode(span.textContent));
      });
    }
  </script>
</body>
</html>

The first iteration was highlighting the letters from the tags which resulted in corrupting the HTML file. Because of this I need to parse the DOM. It only works when I use a single letter. If I add more, then it stops working. JavaScript is not my main language to use and I need a little help so I can resolve this. Thanks

How to track cursor position and get the current key in vanilla-jsoneditor

I am using json-editor-vue + [email protected] to implement a JSON editor. I want to add some additional functionality, for which I need to get information about which key’s value the user is currently editing.

For example:

{
  "k1": "v1",
  "k2": {
    "k3": "user's cursor is here"
  }
}

In this case, I should get the value k3. (I don’t need the full path, just the closest key.)

My requirements are:

  1. Regardless of whether the user has edited the content or not, as long as the cursor moves to a position, I want to be able to get the key corresponding to the value where the cursor is located (or return the key when the cursor is on the key itself)
  2. Receive a notification when the user moves the cursor (optional – if not possible, periodically checking the cursor position would be an acceptable alternative)

Is there a way to implement this? I’ve looked through the vanilla-jsoneditor readme, but it doesn’t seem to cover this functionality.

Changing the default Print Option for Margin in Chrome

Is there any way to change the “Margins” to None in Print Option ( CTRL + p )? using css or javascript.

I have tried @page { margin:0; } but it does not work. Also referred to multiple solutions on stackoverflow but noting seems to work. Basically I want the Print Screen option for Margins to default to “None” instead of “Default.

enter image description here

I tried change chrome print preview default options but did not help.

CSS selector computed aria name

Is it possible to select via a CSS selector (or xpath) an element based on its computed aria name (=accessible name)? For instance for buttons it is computed like

The button has an accessible label. By default, the accessible name is computed from any text content inside the button element. However, it can also be provided with aria-labelledby or aria-label.

I tried to use [aria-label=Foo] that is supposed to be global (edit: hence automatically defined for button based on their content), but it fails…

Motivation: robotframework-browser only allows text, css or xpath selectors in locators (and get by role is quite impractical to use as it involves an extra variable), and chrome recorder extension gives me aria-based selectors.

MWE: you can run it in here:

<script>
    let clickme = () => {
        console.log('foo', document.querySelectorAll('[aria-label=Hello]').length)
    };
</script>

<div class="preference">
  <label for="cheese">Do you like cheese?</label>
  <input name="cheese" id="cheese" />
</div>

<button>Hello</button>

<button onclick={clickme}>Click</button>

In a diagram, relations are always deleted from last to first instead of selected

I have a basic diagram in D3JS, containing objects and relations between objects initialized in these arrays :

      let objectsData = [
        { id: 1, x: 150, y: 150, type: "circle", color: "#ff6b6b" },
        { id: 2, x: 300, y: 200, type: "rect", color: "#4ecdc4" },
        { id: 3, x: 500, y: 150, type: "circle", color: "#45b7d1" },
        { id: 4, x: 400, y: 350, type: "rect", color: "#96ceb4" },
        { id: 5, x: 200, y: 400, type: "circle", color: "#feca57" },
      ];

      let relationsData = [
        { source: 1, target: 2 },
        { source: 2, target: 3 },
        { source: 3, target: 4 },
        { source: 4, target: 5 },
      ];

When my updateRelations() method is first called, everything is displayed correctly, but as I click relations to remove them, they are always removed from last to first in the relationsData table, it’s never the one that’s been clicked that is removed :

const relations = svg.append("g").attr("class", "relations");

  function updateRelations() {

    const relationGroups = relations.selectAll(".relation-group").data(relationsData);

    const enterGroups = relationGroups
    .enter()
    .append("g")
    .attr("class", "relation-group")
    .style("cursor", "pointer")
    .on("click", function (event, d) {
      event.stopPropagation();
      const index = relationsData.indexOf(d);
      if (index > -1) {
        relationsData.splice(index, 1);
        updateRelations();
      }
    });

    // Add visible line
    enterGroups
      .append("line")
      .attr("class", "relation");

    const allGroups = enterGroups.merge(relationGroups);

    allGroups.selectAll(".relation")
    .attr("x1", (d) => getObjectById(d.source).x)
    .attr("y1", (d) => getObjectById(d.source).y)
    .attr("x2", (d) => getObjectById(d.target).x)
    .attr("y2", (d) => getObjectById(d.target).y);

    relationGroups.exit().remove();
  }

  function getObjectById(id) {
    return objectsData.find((obj) => obj.id === id);
  }

At first I thought it was my index variable that was miscalculated (like : it would always be -1), but its value seems correct.

Postman Exchange Data Between Platform (Bitrix-Jotform)

I want to transfer my list of data from Bitrix to Jotform. I already made this flow in Postman, it show no error and seems fine, but it still not posted to my Jotform. Can someone tell me where did I go wrong?

enter image description here

My question:

  1. Is it possible to connect GET Request Bitrix output directly to POST Request Jotform without ‘storing’ it?

  2. Jotfrom input need to be new line for each data, I tried to parse my JSON post response using this code, but as for the input of the POST Request were empty. As shown.

function formatJsonNewLinesCompact(jsonResponse) {
    try {
        const jsonData = typeof jsonResponse === 'string' 
            ? JSON.parse(jsonResponse) 
            : jsonResponse;
            
        return Object.entries(jsonData)
            .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
            .join('n');
    } catch (error) {
        console.error('Error formatting JSON:', error);
        return jsonResponse;
    }
}

How to obtain the handle of the input box in Electron

When we use a barcode scanner or type things in manually, if the input method is set to Simplified Chinese, a Chinese suggestion box pops up. The first time you hit Enter, it actually selects a word from the suggestion box instead of submitting your input, which is really inconvenient for quick scanning. What I’m doing now is using im-select to switch the input method, but my product manager told me not to change the user’s own input method settings. He wants me to keep the user’s input method as it is, but still let the input box accept English directly, without showing the Chinese suggestion box. Later, I showed him a small program written in C, and he said that would work and users wouldn’t have to change anything. So now I’m learning C++ and planning to package this approach into an exe file, so it’s easy for my Electron app to call.

Why does Wikipedia claim UTF-16 is obsolete when Javascript uses it?

The Wikipedia page for UTF-16 claims that it is obsolete, saying:

UTF-16 is the only encoding (still) allowed on the web that is incompatible with 8-bit ASCII. However it has never gained popularity on the web, where it is declared by under 0.004% of public web pages (and even then, the web pages are most likely also using UTF-8). UTF-8, by comparison, gained dominance years ago and accounted for 99% of all web pages by 2025. The Web Hypertext Application Technology Working Group (WHATWG) considers UTF-8 “the mandatory encoding for all [text]” and that for security reasons browser applications should not use UTF-16.

But browsers support Javascript natively, nearly every interactive webpage uses it, and Javascript strings are UTF-16. What’s going on here?

JavaScript Django default scaling using extends index

I’m using Django’s template inheritance (extends) in every page of the app. The current design looks too zoomed out, and I want to adjust the default scaling through my index.html, but it didn’t work. I also tried using custom CSS, but it still doesn’t fix the issue. Does anyone have an idea how I can adjust the default scaling properly?

I have this in my index.html

<meta name="viewport" content="width=450, initial-scale=0.6, user-scalable=yes, minimum-scale=0.6, maximum-scale=0.6" />