OptimusCrime

Boy. Programmer. Freelancer. Student.

Born and raised in Hønefoss, Norway. Earily developed an interest in computers and programming. Currently studying Artificial Intelligence at Norwegian University of Science and Technology in Trondheim. Read more in the About section.

Output filters for code highlighting

posted on September 5th, 2016 with comments

Thought I'd share the code I wrote to add code highlighting to text from the content field in MODX

My blog contains some code, and most of us programmers are used to read code with some sort of highlighting, either in our IDE, or in the manager interface via the Ace editor or something similar.

I wanted to have a simple syntax that I could write in the content field that would result in highlighted code. I had earlier attempted to paste code and set the format as pre, however, this turned out to be difficult when I was editing the code back and forth. Instead I decided to use an output modifier and some simple regex to do what I wanted.

highlight.js

Of course I did not write the highlighter myself. What I did was process the content from the content field and add the classes and markup that an existing library expected. I did some research, and the most promessing alternative (by far) was highlight.js. I suggest you check out their website, it is really a nice piece of code! highlight.js is very simple. It just requires one line of code, like so:

hljs.initHighlightingOnLoad();

The markup highlight.js expected was also self explanatory. It looks like this:

<pre><code class="html">...</code></pre>

Where html can be any of the 166 languages it has highlight support for.

Output modifiers + regex = true

In my template I have the output from the content field. It looks like this:

[‌[*content:parse_content]‌]

The parse_content code looks like this:

// For highlight.js
return preg_replace_callback("/<p>```(?P<type>[a-zA-Z]+)?(?P<content>.*)```<\\/p>/m", function($match) {
    // Here we check if the optional type was supplied
    $code = '<pre>';
    if (isset($match['type']) and strlen($match['type']) > 0) {
       $code .= '<code class="' . $match['type'] . '">';
    }
    else {
       $code .= '<code>';
    }
    
    // Replace first <br> with nothing to avoid that the first line break
    // creates a blank line at the top of our code block
    $match['content'] = preg_replace("/^<br\W*?\/>/", "", $match['content']);
    
    // Replace <br> with newlines for <pre>
    $code .= preg_replace("/<br\W*?\/>/", "\n", $match['content']);
    
    // Close the wrapper
    $code .= '</code></pre>';
    
    // Return the final markup
    return $code;
    }, $input);

To create a code block in TinyMCE, my regex pattern recognizes the pattern:

`‌`‌`language
code
goes
here`‌`‌`

For example:

`‌`‌`php
<?php
echo "Hello world";
?>`‌`‌`

Would produce:

<?php
echo "Hello world";
?>

The important thing is that the content can not be separated by a full line break. The newlines needs to be <br />. You get this by holding down Shift while pressing Enter. "Regular" newlines you get when you just press Enter actually creates a new paragraph block within TinyMCE, and this breaks my regex expression. I guess I could adjust it to support this, but simply having the entire code as a single paragraph block worked very well.

You can see just how the end result looks by looking at this page and inspecting the source code.

Inline code

The code blocks explained so far is designed for multilevel code that is separated from the rest of the text. I also wanted support for some sort of highlighting that I could have for inline text. I knew StackOverflow had support for this, and I shamelessly copied the CSS they use for their inline code:

main code {
    color: #333333;
    background-color: #EEEEEE;
    font-family: Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;
    padding: 1px 5px;
}

I also expanded the code in parse_content with the following line:

$input = str_replace(['{‌{', '}‌}'], ['<code>', '</code>'], $input);

This code simply replaces curly brackets with code tags that are allowed to be inlined. The result looks like this and that. It works great for making code or keywords stand out in the middle of a sentence.

Easy as that

I just wanted to share these few couple of lines because I was very satisfied with the outcome myself. I originally tried using pre tags in my markup directly in TinyMCE, but I found it too clumsy to work with. My solution does not need any toggling of formats in the editor. The only thing you need to remember is to not create newlines while expanding or pasting the code.

Easy as that!

Feel free to comment or share.

Read more

Using Ext JS to create neat manager pages in no time

posted on August 29th, 2016 with comments

I might have oversold this with my Tweet, but I felt that I should share how I worked with Ext JS to create a manager interface for a project I worked on this summer.

Here goes my article, presentation, showcase, tutorial, or whatever you'd like to call it. Presented in seven chapters (hello Tarantino).

Chapter 1 - Introducton

The background for writing this is that I feel like Ext JS gets a lot of undeserved hate. Sure, it is a complex framework, there is a LOT of magic going on, and it does not help that MODX Revolution is currently on version 3.4 when their latest major release is 6. Despite all this, I truly belive that Ext JS has in some ways benefited MODX and the manager panel. I think that the code powering the manager would be much more confusing in a lot of other technologies.

Short introduction to Ext JS

If you are not too familiar with Ext JS and how it is used in the manager, let me give you a quick introduction. Ext JS is a framework that focuses on components. Once a component is defined, this component can extended further and new functionality can be built on top of existing ones. This way we can reuse a lot of functionality which results in less code.

Ext JS is written by basically defining a HUGE JavaScript object that more or less draws the entire DOM for you. Ext JS translates this nested object that consists of components inside other components inside other components and draws everything out during rendering. The downside of this is that much of the work you usually do in Ext JS feels very abstract as you are not interacting with any DOM objects directly, you are assuming that Ext JS does its job and there is something in the mess of a DOM tree that matches what you expect. Another downside is that just a single error, like a forgotten comma, will lead to the entire tree of components crashing and not rendering.

Below is a very simple introduction code:

// Define our object with a config
My.object = function(config) {
    config = config || {};
    
    // We can add attributes to our config here
    Ext.apply(config, {
        foo: 'bar'
    };
    
    // Calling the constructor for our superclass
    My.object.superclass.constructor.call(this, config);
};

// Here we tell Ext JS that My.object is extending the component MODx.Panel
Ext.extend(My.object, MODx.Panel, {
    // Optional things can go here, like methods or special behavior
});

// Finally let us register our object in a unique ID that can be embedded later
Ext.reg('my-code', My.object);

Chapter 2 - The task at hand

I worked on a project this summer. In this project I was asked to create a system for categories. This system needed support for two levels of categories, primary and secondary ones. Primary categories are the "root" categories, while secondary categories have primary categories as their parents. To supplement this, it was also requested functionality to drag and drop the categories to reorder and restructure the hierarchy. Functionality to expand and collapse the primary categories would also be a plus, as we would work with many categories. Other functionality such as possibility to add, edit and remove categories was also needed and had to be implemented.

Creating something like this could be pretty easily done in jQuery or other libraries or frameworks, but we wanted to integrate it in the manager panel with the rest of our custom manager pages. This meant that the most logical thing to do was to implement it in Ext JS.

Following this blog post, you can see the exact code I wrote and used in my GitHub repository. It has different branches for the various stages throughout this post. You can find the entire repository at OptimusCrime/modx-category-cmp.

Chapter 3 - Getting started with the component

With the task defined and fleshed out, I started looking at what type of components could be used to create functionality like the one we needed. Drag and drop? Expand and collapse? Hm, this does indeed sound a lot like menus and trees! Menus and trees are found many places in the manager and is extended from a central Ext JS component.

The trees and menus I found in the Manager includes:

  • Resource menu
  • Elements menu
  • Files menu
  • Top menu administration
  • Access controll list administration
  • Property set administration
  • The file browser

If you look at how these trees and menus behave and how they look, it is clear the MODX reuses the same base functionality in many of these components. I wanted to base my component on one of these and extend my code further to implement the features I needed.

Browsing the MODX source code for leads

The next step was to go through the MODX source and look at how each of these components were implement and extended in the original Ext JS code. The idea was to find a components that was not too complex and did not have too many features that we had to remove or override.

The relevant MODX source for the MODX Ext JS implementations lives in the manager/assets/modext directory. From here the directories are divided between:

core - The core MODX components that overrides and extends the Ext JS components. Holds the most central components that are reused multiple times in the manager.
sections - The base sections for the various views in the Manager.
util - Various utilities and reusable snippets of Ext JS code.
widgets - The widgets that are included in the base sections. This can be grids, windows, trees, panels and more.
workspace - I really don't know what this directory is used for, but it contains more Ext JS code for various parts of the Manager.

I browsed the various locations where this tree/menu behavior is found in the Manager, and inspected the corresponding Ext JS code that it used. I found out which files this was by inspecting the source code and looking at which JavaScript files were included in the various sections. One of the simplest of these tree components turned out to be modx.tree.menu.js. While the entire implementation is more than 300 lines long, it is relatively simple in nature. 

At this point I had basically two choices: either extending the tree used for the menus, or copy the content of this file and trim it more and more until I got the functionality I needed. Extending the menu tree would create a hierarchy like this:

Ext.tree.TreePanel -> MODx.tree.Tree -> MODx.tree.Menu -> Category.Tree

But the MODx.tree.Menu had too many features that I had to deal with. I instead decided to not extend the menu tree, resulting in this hierarchy:

Ext.tree.TreePanel -> MODx.tree.Tree -> Category.Tree

Where Category.Tree initially was a 100% duplicate of the MODx.tree.Menu source code.

Cutting and trimming

Below is the current Category.Tree at this stage. As you can see, it is exactly the same menu as you find in the manager interface under Menus. You can browse the exact and complete code I used for creating this component at OptimusCrime/modx-category-cmp/stage1.

The next task was to remove the parts of the component from the source code that I did not want and that was not relevant in my case. I made the following changes in home.tree.js:

[...]
,rootVisible: false
[...]
,useDefaultToolbar: false
[...]

Okey, cool. We got rid of some of the stuff we did not need. 

Chapter 4 - Creating processor endpoints

The next step was to change the content of the component. Right now it uses the processors for the menu which fetches the menus we have defined for the manager interface. I would like to swap these for our own endpoints that provide the category data.

Before we swap the endpoints I needed to know what format the tree expects the data to come in. I had to figure out how Ext JS takes the JSON response and draws the tree nodes. I inspected this by using the Chrome inspector and looked at the various ajax calls that were fired upon refreshing the page containing the menu. There were multiple requests running after each other, each fetching a part of the tree. The first request fetched the root menus (the ones without any parents). The form data was:

  • action: system/menu/getNodes
  • node: n_

And the response was:

[
    {
        "text": "Top Navigation",
        "id": "n_topnav",
        "cls": "icon-menu",
        "iconCls": "icon icon-navicon",
        "type": "menu",
        "pk": "topnav",
        "leaf": false,
        "data": {
        "text": "topnav",
        "parent": "",
        "action": "",
        "description": "topnav_desc",
        "icon": "",
        "menuindex": 0,
        "params": "",
        "handler": "",
        "permissions": "",
        "namespace": "core",
        "childrenCount": "5"
        },
        "qtip": ""
    }, [...]
]

Similarly, the request for the children of the menu item "Top Navigation" had the following form data:

  • action: system/menu/getNodes
  • node: n_topnav

Ad response was:

[  
    {  
        "text": "Content",
        "id": "n_site",
        "cls": "icon-menu",
        "iconCls": "icon icon-folder",
        "type": "menu",
        "pk": "site",
        "leaf": false,
        "data": {  
            "text": "site",
            "parent": "",
            "action": "",
            "description": "",
            "icon": "",
            "menuindex": 0,
            "params": "",
            "handler": "",
            "permissions": "menu_site",
            "namespace": "core",
            "childrenCount": "6"
        },
        "qtip": ""
    }, [...]
]

We can easily see the pattern and how we should recreate the response to build our own processor for the categories. Ext JS first asks for the root elements, then assigns each of them an id. This id is used to fetch the children (if any) by sending the id as the value for the node data. If the node data was n_ it meant we were fetching the root elements.

You can see how I adjusted the Ext JS and wrote my own processor in OptimusCrime/modx-category-cmp/stage2, specifically the file getnodes.class.php under processors.

With a similar approach I also created a processor that deals with the sorting of the elements. You can see this code in sort.class.php, also under processors. With the sort processor in place, we also have functionality to drag and drop categories onto, below, and above each other. This greatly illustrates the power of Ext JS. We'll get back to some minor tweaks we'll have to do regarding the sorting later.

You can browse the entire difference between the stage1...stage2 to see what changes were done to create this functionality. As you can see, it is not a whole lot of code.

Note: I know that this part of the article is a lot of "magic", but there is not too much to comment really. You'll need to look at the original processors and understand how they work. Look at how the processors extends their parent classes and what "magically" happens behind the scenes. A good starting point is looking at the get og getList processors for a endpoint in the manager. Look at the code and which methods are overridden. It will make a whole lot of sense after some debugging.

Chapter 5 - New, edit and remove

The next step was to add functionality to create a new category, edit an existing category or remove a category. This section illustrates the power of Ext JS and you'll see just how much we can rely on the magic of the processors and their shorthand classes.

Create new category

Creating a new category is done via a popup box. This box was already in place for the menu functionality. Implementing the same for categories was pretty easy. You can see the steps taking in the difference between stage2...stage3. However, we are not yet finished. The combobox for parents still lists manager menu entries from the original code.

I wrote a new processor for the combobox that fetches the primary categories and wrote a processor that creates our new category. The latter contains some logic to keep track of menuindexes, but should not be too complex. You can see the code for these steps in stage3...stage4. You can browse the entire code up to this point at OptimusCrime/modx-category-cmp/stage4.

Editing an existing category

I already have functionality to create a new category at this point. The operation for editing is more or less identical to creating. The next code block is the only thing we needed to write in Ext JS to add edit functionality. Of course I still needed to hook the code on right click action and write the processor, but the window that pops up when you are updating is no more than these lines of code:

/**
 * This code overrides the window used to create a new category.
 */
Testing.window.UpdateCategory = function(config) {
    config = config || {};
    Ext.applyIf(config, {
        title: _('testing.category_update')
        ,baseParams: {
            action: 'mgr/update'
            ,id: config.record.id
        }
    });
    Testing.window.UpdateCategory.superclass.constructor.call(this, config);
};

// Note that we extend Testing.window.CreateCategory here!
Ext.extend(Testing.window.UpdateCategory, Testing.window.CreateCategory);
Ext.reg('testing-window-category-update', Testing.window.UpdateCategory);

I belive that this greatly illustrates how you can use Ext JS code more than once with only minor adjustments. Fuctionality like this is also very common. If you need to create something you'll most likely need to edit it somehow too. You can see the rest of the changes done to fully implement functionality to edit a category in stage4...stage5 or browse the entire code at OptimusCrime/modx-category-cmp/stage5.

Remove a category

The final piece of the puzzle is to add support for removing a category from the system. This code for removing menu elements is already present, and only slight modifications were needed. In the processor I also took care of deleting children of primary categories,. This leads to some additional code, but it is mostly a straight forward removal processor. You can see the difference at stage5...stage6.

Chapter 6 - Cleanup and final adjustments

During development this was, we have ignored a few things that might results in problems or bugs. The component should only support two levels of categories, and disable creating categories deeper in the tree. Right now it had support to create child categories of secondary categories. It also allowed dropping a primary category onto a secondary category, which would produce three levels of categories if allowed. It would, in addition, be nice to be able to add a secondary category if we right clicked on a primary category.

Right click to directly create a secondary category

The method getMenu is the one that draws the context menu when you right click something in our tree. This method decides which options to display to the user. I rewrote it a bit to add support for our new functionality.

The new method looks like this:

,getMenu: function(n, e) {
    var m = [];
    
    // If the node we right click on has no parent, allow to create a category here
    if (n.attributes.data.parent == null) {
        m.push({
            text: _('testing.category_create')
            ,handler: this.createCategory
        });
    }
    
    // We're always going to allow updating a category
    m.push({
        text: _('testing.category_update')
        ,handler: this.updateCategory
    });
    
    // This is simply a separator in the menu
    m.push('-');
    
    // At the bottom we'll have the "dangerous" stuff
    m.push({
        text: _('testing.category_remove')
        ,handler: this.removeCategory
    });
    
    return m;
}

In the method createCategory I needed to make sure it pass the parent value if sat. There was already some code trying to take care of that, but because our data is slightly different from the original code, I needed to adjust it like so:

var r = {
    parent: null
};
if (this.cm && this.cm.activeNode && this.cm.activeNode.attributes && this.cm.activeNode.attributes.data) {
    r['parent'] = this.cm.activeNode.attributes.data.id;
}

People may ask, "how the hell do you know which attributes exists and which ones to compare?". Well, truth is that stuff like this is mostly done by trial and error. I cosole.log out all the variables I have available and try to navigate myself though the Ext JS object mess to the correct attributes I need to extract in order to make something useful happen. After a while you'll get the hang of this and you'll know what to look for. I did the same in the next section there I had no code to base my functionality on. In the picture below, I have console.log'ed out the content of this.cm to see what it contains. Simply traversing it is not very difficult.

Disallow dropping primary categories onto secondary categories

This was a bigger problem. I had no code to go from to solve this, but fear not. I already knew that there had to be a ton of functionality tied to dragging and droppig nodes in the trees we were extending. As I found no code that could help me in the source code for MODx.tree.Menu, I tried to go one level up to MODx.tree.Tree. The code for this component resides in modx.tree.js. Around the lines modx.tree.js#L538-L548 I hit jackpot. Worth noting that I was unsure if the correct method to override was _handleDrop or _handleDrag. I did some testing before I found out which one was fired and which attributes and data I could access in each of them.

The code says it all. This is again a result of trial and error. I logged the output of the event and tried dropping categories onto each other, below each other and so forth. After that I inspected the output from the logs and tried to make sense in how I could differentiate between the various states. The following code disables dropping a category onto another if it has children and the target is a secondary category.

,_handleDrop: function(dropEvent) {
    // Let's shortcut things
    var drop_node = dropEvent.dropNode;
    var traget_node = dropEvent.target;
    
    // If the event is "append" we are just adding a new child in a list, not ON a parent, hence we can ignore it
    if (dropEvent.point == 'append') {
        return false;
    }
    
    // If our drop node has children AND the target node's parent is not the "root" we are attempting to drop at
    // another node, which results in too many levels of categories. Simply returning false here will disable dropping
    // in this position
    if (traget_node.parentNode.id != 'root' && drop_node.childNodes.length > 0) {
        return false;
    }
    
    // This is just the code from modx.tree.js to implement some basic functionality
    if (!Ext.isEmpty(drop_node.attributes.treeHandler)) {
        var h = Ext.getCmp(drop_node.attributes.treeHandler);
        if (h) {
            return h.handleDrop(this, dropEvent);
        }
    }
}

And that is it, really. You can see all the changes from the previous stage at stage6...stage7 or browse the entire code at OptimusCrime/modx-category-cmp/stage7.

At this point we're done with out component. Sure we can add more functionality, but for the sake of illustrating the process from start to finish, I think this will do. If you want to see more, download the GitHub code from the stage7 branch and install it yourself. Instructions are in the README.md file.

Chapter 7 - Final thoughts

It might not have been the easies article, presentation, showcase, tutorial or whatever to follow, but I hope someone learned a thing or two. I did not target people that have developed tons of custom manager pages before. I hope they already are aware of how powerful Ext JS is alread. I wrote this for people that has only been watching Ext JS from the outside with fear and anger. I do understand why many dislike Ext JS and would like to get rid of it, but while it is an integrated part of the manager you might as well learn it and use it for what it's worth.

I've spent many hours debugging stupid blank manager pages because of some dumb syntex error, or gotten so deep in the Ext JS source code that I was afraid I would never get out again. Ext JS is difficult, too difficult perhaps, but I honestly think you can learn it if you decide to do so. I for one am glad I can provide customers with integrated and friendly components directly in the MODX manager as a part of our solutions.

I'd like to thank Catch Media for allowing me to reuse some of the code I wrote in their project for this article.

Feel free to comment or share!

Read more

MODX needs to stay relevant

posted on April 6th, 2016 with comments

We need some changes or some updates to MODX right about now.

I've been wanting to write this blog post for a while, but have been putting it off for far too long. I've had these thought for a while and I'd like to share them with you.

Before I begin to rant I should (once again) express my love for MODX. I've been using MODX for some years now (about 5 actually), and I love it just as much as I did when I first began learning it. Please keep this in mind.

Lack of progress on Revo

Revo is a great piece of software. It is so powerful and has endless possibilities. For such a great open source project it hurts me that not more progress is made.

Progress on GitHub

The GitHub repo more or less a giant dump of old and outdated issues and no one seems to be interested in untangling all this mess and sort things out. Several attempts have been made, but they always come short. After a great effort has been put down, new tickets just pour in and we are back to square one.

In order to truly sort things out we need help from the team members to systematically to through everything. Decisions needs to be made. Some features are not wanted, some features are not important and some features does not fit the Revo core. Someone (with authority) has to decide this and make it possible to us to go forward with things. Too many ideas (many good, many bad) have just been left because discussion went nowhere and no one that had anything to say ever did anything.

In addition to issues, open and pending pull requests are just left there every once in a while. Noo ne wants to reject or step in and take over a dead contribution. This makes contributing to Revo less tempting for open source enthusiasts.

Progress on development

In addition to ignoring issues, no new leaps have been made in quite some time. The pull requests mentioned in the previous sections are almost all from non-core members. I though MODX had dedicated developers that were focusing on structuring and laying the path for the rest of the open source people?

No roadmap, no goals

Despite the downsides mentioned in the previous sections, there is still a bigger problem with MODX today. This is the lack of a defined and structured roadmap. There are some milestones sat up at GitHub, but these still lack an overarching goal and there is no depth to the issues that has been assigned a milestone either.

This makes it very difficult for the community to know what is going on in the MODX world these days. What are they planning for? Is there anything we can test, research, look into? I'd love to do some of that, but that is impossible with no direction to go in.

Why does not MODX have anything like this:

I would also love to see something like the apple/swift-evolution repo, which is used for:

This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.

Revo and PHP in 2016

Another problem I'd like to mention is that fact that Revo is right now an aging technology. If you go 5 years back it was amazing how well structured Revo was and how new-thinking it was in many ways. However, things have changed in the PHP community over the last years. Autoloading, Composer, various technologies like dependency injection are used all over the place now. As mentioned earlier, Revo 3.0.0 will introduce autoloading, which will make things a little bit better, but there is still a long way to go.

Another huge problem with Revo is how difficult it is to develop with a sensible version control system like Git. Because almost everything is stored in the database, you need to use tools like Gitify or some other component to dump or sync files to your project. This is not optimal at all, and in a world where so much is version controlled this has to change. While this might be difficult, or even impossible for Revo, I suggest looking towards the new MODX product.

Where is MODX Next?

MODX Next was relieved by Jason in a three part medium.com series, which this post is named up after.

These posts were posted over a year ago, in February of 2015. Still we have yet to see any sign of this new software. As far as I know, work has yet to begin on MODX Next too. I can not say this for sure, but no community members (that I know of) have seen any sign of MODX Next.

Like I said, Revo is a great product, but it it too defined now to be structured into something completely new by now. Instead we must love it for what it is and keep it that way. MODX Next can be the new technology that MODX can live on for year to come. If they manage to keep things to customizable as Revo is while introducing autoloading, a simpler ORM system, easier integrating with components and a more loosely coupled manager, MODX can hopefully take its throne as the best open source CMS/CMF there is. I also think this can lead to a far more popular product for MODX. Right now people look at Revo as an aging product, and this is a turn off for many (serious) developers.

In the mean time, other modern CMS are developed. For example:

Not to mention (micro) frameworks like SlimSymphony and Laravel are getting increasinly popular by the day.

If MODX wants to stay relevant for the years to come, something needs to happen, and it needs to happen soon. At the current rate things are going, we will all be over on something else pretty soon, and I'd hate that.

Again, I love MODX. I want to keep using the brilliant freedom I can not find anywhere but MODX, but it is hard when so many other things are negative.

But MODX needs to earn money too!

I know this post is very negative and I more or less attack MODX head on. I'd like to conclude this post by saying that I love all you are doing, and I know you need to generate income by doing work for customers or continue to develop your cloud solution, but I'd like to see more action on the open source front.

I think, and I really mean this, that if you release a modern product that is as fantastic as Revo, with the power of all the new and neat PHP tricks, I think you will earn your money back tenfolds. Just look at the popularity the product I've listed above.

I'd also like to mention and I'd love to help you guy out any way possible. I've offered my help with MODX Next several times before. If there is ever a time you need a new set of eyes, or you need some people to test something, count me in. I really, really look forward to this product. I just hope it comes before it is too late.

- OptimusCrime

Read more

Hello world

posted on December 31st, 2015 with comments

I am finally working on putting my new website together

Still a lot of work left...

Read more

Help Modx! Take care of some issues at Github!

posted on November 5th, 2015 with comments

The last couple of weeks we have been working hard trying to make issues at Github useful again. You should join the fun!

After the migration from Redmine to Github, all the issues were transferred. The difference between Redmine and Github is that Redmine offers a lot more filters and custom searches. Because of this, Github ended up being a total mess with over 1600 open tickets assignet to Modx Revo. Many of which was over 2-3 years old.

Some fellow Modxers from irc and I decided to start clean up the mess. If we could close off incorrect issues, issues which lacked information, duplicates, outdated stuff etc, we could make issues useful again.

I urge you all to contribute to this movement! All you need is a Github-account. Head over to modxcms/revolution/issues and comment/share your thoughts!

Read more