Categories
Code How-To Web Design

Create a Checklist Plugin for TinyMCE

The TinyMCE editor is a very useful and easy to implement add-on to your web app. For the most part it is free to use and develop with and is licensed with the LGPL license, but some plugins for different editor functions are only available under their Premium Features offering.

If you think the premium plugins give you what you want and you are going to make money from your work, it’d probably make you feel good to buy one of their plans.

Anyway, if you do want to have a play around with TinyMCE plugins and create your own, it’s not that hard.

Firstly, you need to have a basic HTML web page created with an element to use as your editor. This can be a <div> or a <textarea>. Here’s an example HTML page with a simple form and a Textarea element we want to target. We have also included our script tag to load the TinyMCE Javascript library.

<!doctype html>
<html lang='en'>
<head></head>
<body>
<form>
<textarea id='myEditor'></textarea>
<input type='submit' name='submitForm' value='Send'>
</form>
</body>
<script type='text/javascript' src="./tinymce/tinymce.min.js"></script>
</html>

If you load that page in a browser you should see your basic web form, but not much else. We need to define the JS code to tell TinyMCE to attach itself to that Textarea element and provide a configuration.

Add the following to the bottom of your HTML (you could also put it in a separate file and include that script again) above the closing </html> tag.

<script type='text/javascript'>
tinymce.init({
    selector: '#myEditor',
    menubar: false,
    statusbar: false,
    toolbar: 'bold italic underline bullist numlist mychecklist link image code',
    plugins: 'mychecklist code link lists advlist image'
});
</script>

This JS code will define the HTML page element (the one with id=’myEditor’) that TinyMCE will use as the editor. It will also disable the menu bar and the status bar and add some buttons to the toolbar. We have plugins defined that match our buttons. Not all plugins need to have buttons, but in this case they do.

For the checklists plugin to work, it actually uses some of the features from the Lists plugin so we need to ensure we have that.

If you load your web page now, you should see it with the Textarea behaving as an editor panel with the buttons showing above it. Something like this.

So far, so good, you have a functional TinyMCE editor. Now we need to create the plugin to be able to use the checklists feature.

Create a new folder and file in the TinyMCE folder structure under <your_folder>/tinymce/plugins/mychecklist/plugin.min.js

Copy and paste the following code into that new file called plugin.min.js. If you have the developer version of TinyMCE you may need to rename that file to plugin.js. By default the behaviour of TinyMCE changes with the dev version loading unminised files and the production version loading the minified versions.

(function () {
    var mychecklist = (function () {
        'use strict';
        tinymce.PluginManager.add("mychecklist", function (editor, url) {

            /**
             * Plugin behaviour for when the Toolbar or Menu item is selected
             *
             * @private
             */
            function _onAction()
            {
                var content = `<ul class="tox-checklist">
                    <li class="tox-checklist--checked">Task</li>
                    </ul>`;

                editor.insertContent(content);
            }

            // Define the Toolbar button
            editor.ui.registry.addButton('mychecklist', {
                icon: 'checklist',
                tooltip: 'Insert check list',
                onAction: _onAction
            });

            editor.on( 'NodeChange', function ( event ) {
                var node = editor.selection.getNode();
                var parent = node.parentElement;
                if (parent.className === "tox-checklist") {
                    if ((node.nodeName === "LI") && (node.className === "tox-checklist--checked")) {
                        node.className = "";
                    } else if ((node.nodeName === "LI") && (node.className === "")) {
                        node.className = "tox-checklist--checked";
                    }
                }
            });

        });
    }());
})();

That’s a lot to take on in one go so lets break it down a bit.

We define a new TinyMCE plugin and give it a name “mychecklist”. We also pass in “editor” which is an object representing the editor component and content in the page.

The function _onAction is what gets called after we click on the toolbar button. In our example code it’s very simple and only creates a small snippet of HTML that defines a list with one item. Both the <ul> and the <li> have custom CSS classes applied and these are the TinyMCE assets that we’re really leveraging here.

We also create define the toolbar button which has a name that matches what we used in our editor definition at the bottom of the HTML file. It links the button to the _onAction function.

Then we have an editor.on() code block which helps us make the checkboxes toggle between empty and ticked. You may have noticed by now that this checkbox display is a bit of TinyMCE and CSS trickery. They aren’t actually HTML checkbox input elements, they’re just styled list items.

The NodeChange event being used is triggered whenever the user moves their input cursor around in the editor panel. It effectively makes the element it lands in the active element and allows this code block to carry out actions. In our case it is trying to identify that we’re active in one of our check list items. We do this by confirming the parent element is an <ul> with class of tox-checklist, then that the <li> is either showing the checked style or it’s empty and then toggles the class to the other value.

If you reload your web page now you should see the checklist icon in the toolbar of the editor and when you click on it, there will be a chunk of new text added into the editor. If you click on the list item check box or the text label the status of the checkbox will toggle.

Excellent we have a new UI item and function in our TinyMCE toolbar that’ll insert a list item that behaves like a checkbox.

If you want to save this editor content to a database, you’ll need to use the following CSS to render it as normal output in elements outside the TinyMCE editor. The check boxes are SVG images.

This CSS and toolbox icon for a checklist are included in the TinyMCE library by default even though it is obviously used in their premium plugin. We use the JS above to toggle that CSS on or off.

.tox-checklist>li:not(.tox-checklist--hidden) {
    list-style: none;
    margin: .25em 0;
}
.tox-checklist>li:not(.tox-checklist--hidden)::before {
    background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");
    background-size:100%;
    content:'';
    cursor:pointer;
    height:1em;
    margin-left:-1.5em;
    margin-top:.125em;
    position:absolute;
    width:1em;
}
.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before {
    background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")
}

To take this a few steps further there are some tidy up actions needed. Consider these optional extras that I may write up at a later time.

  • Notice when the checklist item is selected, the wrong toolbar item is highlighted in the editor.
  • If you’re displaying the editor content as HTML outside the editor (i.e. you’ve saved it for display), you won’t be able to toggle the checkbox status.
Categories
Code Web Apps

Doc5 Wiki Available for Download

Slightly behind with this post but I finally have a new release of Doc5 available for download.

New features include,

  • Full WYSIWYG editing and no more trying to get used to the markup. (Not that it was difficult but people are used to risch editors these days)
  • Complete redesign of the UI.
    Bootstrap makes for an easy to use, clean interface and I really like the design anyway.
  • Easier to use more finely grained permissions.
    Per user permissions for categories and pages and inheritance for pages.
  • Much better file management and easier to link files into pages.
  • Bug fixes and support for different databases with faster access.
  • HTML email templates.
    This will make it easier to extend and handle language translations in the future.
Categories
Code Security Sys Admin

Permissions Problems with git pull

I’ve started working on Doc5 from a laptop in the last few months and have begun the pull/push process to get my Bitbucket repo and desktop machine all in sync. But when trying to get these sorted I found permissions problems on one of the local repos. When I tried to do a pull I had about eight files that either couldn’t be unlinked or couldn’t be created.

If I looked at the permissions on the files I was the owner, www-data (Apache in Ubuntu) was the group and the permissions where 644 on the files and 755 on the directories in my project folder. So that all seemed fine.

But what you need to watch for is the extra permissions that a process needs in order to unlink. What git is doing is taking these files away and then replacing them in the folder. i.e. it’s not just a modification through a write action to the file.

Categories
Code Web Apps Web Design

Doc5 Beta Now in Testing

After many years I have got a version of Doc5 up and available to use. It’s a vastly different wiki app than the previous version and most of the changes have been made in the last 9 months. The last version released for download was a different name and appeared before my son was born. He starts school in two weeks.

My 9-5 job takes up enough time that for a couple of years I left this project¬†alone and considered dropping any¬†thoughts of pushing it out. But writing web apps is my hobby, so it’s been good to dig through all the old code and clean it up.

So a list of the major changes:

  • WYSIWYG editing has arrived and the previous wiki engine is gone
  • Permissions have been simplified but also extended to categories
  • Full UI make over, although I have gone with a pretty basic Bootstrap view of things.
  • Better file uploads and management.
  • Templates for email notifications

I think a full release should be available for download in the next two months. Testing on the web will help tune spam catching and there’s some bug fixing to roll out as well as plenty of test cases to run.

Categories
Code Web Apps

Git Hosting and Issue Tracking

I’ve been looking about for some free Git hosting and found that most options like Github require you to make the code available to everyone. So I was pleasantly surprised to find Bitbucket from those ingenious Aussies at Atlassian.

There’s some excellent documentation, the system is easy to use and your first push from your local repository can be done with a few minutes after you’ve signed up.

An issue tracker is available for each of your projects and can be made public while your code is still private. So for a small team or individual it’s a valuable tool even just to use as a backup for your local code repos and keeping track of the odd bug.

Categories
Code

Easy, Beautiful Charts with Flot

I’ve been looking for a free, open source chart library for a while and was struggling to find something that was good enough (and handled time series and missing data points well). For a long time I’ve been using Fusion Charts (FC) and Open Flash Chart (OFC) in any in-house work and those products are very good. But they’re Flash, a little slow and not supported by some popular mobile devices. I’ve also used pChart for some testing but it was fairly stale in development and being images, had no interaction.

The Flot JS library was something I’d seen a while back, but before I became comfortable with JS and jQuery. It does almost exactly what I want, is farily light-weight, extensible and easy to use. In a few hours last week I swapped out the FC code I had written for Overview and put in something almost half the size with Flot that created (in my view) a better product.

So I thought I might let others know what a nice, easy option Flot is with a little example. Beware this is not a fully working, copy and paste sort of example, it’s really just a chunk of generic code I pulled out.

Categories
Code

Debug PHP Function Calls

Logging errors can be very helpful as your code base becomes huge. But sometime it’s still difficult to find out what’s calling the function that’s giving the error. Wouldn’t it be nice if there was a way to see how you’d got to that function?

Well of course there’s a way in PHPdebug_backtrace. Just add something similar in a suitable place in your code and you’ll be able to find what functions were called.

$trace=debug_backtrace();
$caller = $trace[1]['function'];
// or just dump all the info
var_dump($trace);
Categories
Code

Beware the leading zero in Javascript parseInt()!

Exhibit A,

parseInt('01'); //equals 1
parseInt('02'); //equals 2
parseInt('03'); //equals 3
parseInt('04'); //equals 4
parseInt('05'); //equals 5
parseInt('06'); //equals 6
parseInt('07'); //equals 7
parseInt('08'); //equals 0 !!
parseInt('09'); //equals 0 !!

When Javascript encounters a leading zero it assumes an octal number. So when it sees 08 or 09 then there are problems.

The fix is to add the radix to the function call,

myInt = parseInt('08',10); //equals 8
Categories
Code Sys Admin

Using PHP exec() with IIS6

There are a few work arounds I’ve found since having to use PHP under IIS6 and Windows 2003. Every now and again I come across something that just doesn’t work the same way with this variation of web server, OS and PHP.

I needed to double-check the DNS hostname being reported from users on an internal website. Our DNS is a little scratchy when it comes to scavenging and keeping itself tidy, so often a DNS lookup of the client IP will give an incorrect name. This happens especially for laptops that hop off and on wireless APs.

So to compare against DNS (and because it’s an internal site) I thought to query the machines NetBIOS name with,

exec("nbtstat.exe -A 123.123.123.123",$r);

and that quickly fails with an error about “failing to fork”. Essentially this means, PHP can’t do what you want.

It boils down to file permissions. you need to run cmd.exe and nbtstat.exe with that single command. Both those files are secured against non-system users – probably rightly so too.

To resolve, just allow your IUSR_SERVER user to have read and execute permissions on both those files. Your exec() command should now be working.

REMEMBER: You are responsible for the security of your server. If you really don’t need to let programs run on your web server, then don’t.

Categories
Blogging Code How-To Sys Admin

Running WordPress & PHP Behind ISA Proxy

Some things work well on their own but when mixed make your life hard. Things like Linux and PHP work very well. Microsoft ISA proxy also does a good job in a corporate MS environment. But making the two work together in a controlled environment can be an exercise in frustration.

In this post I’ll pass on the methods I found to get PHP and your Linux boxes talking out through a corporate ISA proxy server. You can then bring in RSS feeds, updates and other things in WordPress and use apt-get to update Ubuntu.