So my Wordpress site got hacked rather badly recently and 000webhost canceled my free hosting:

Site Down

Realising the amount of effort I put into writing templates, uploading huge amounts of files and using crappy FTP connections, I looked for a better way to post stuff.

Jekyll is a static website generator written in Ruby, is very light and didn’t take nearly as much time to install, even though I had to set up DNS records again.

  1. Take a look at the source branch of this website.

  2. Fork the repo and checkout both the source and master branches.

  3. Make some changes to the site in the source branch and push them.

  4. Run publish.sh, which will build the site in the master branch and push it.

If you’re hosting a Project Page instead of a User Page, you need to push to a gh-pages branch instead, so edit publish.sh to your needs. See the GitHub Pages guide.

This has some setbacks – even though I installed the Wordpress importer like so:

sudo gem install jekyll-import --pre

And followed their importing guide, my old posts are more or less broken. But I think cleaning them up will be a more long term solution, and I don’t need a PHP server anymore :)

I plan to port Crayon eventually, but that’s another story.

In the latest version of Crayon, you can choose to hide the code until the user expands it. This doesn’t apply to inline code. You can enable/disable it for individual Crayons using the Tag Editor. If a title is set in the Tag Editor it is used in place of “Click To Expand Code”.
Here’s a Wordpress widget base class which reduces the amount of code needed to create a simple widget with fields. Allows overriding a method adding more complex fields. This code should be placed in your theme’s function.php file. You can then subclass Field_Widget whenever you like by following the example given. Thanks to http://frobert.com/en/2010/12/10/wordpress-widget-tutorial/ for sharing tips on how to use WP_Widget.

 
Here’s my adapted version of sending an email attachment and allowing HTML and plain encodings.
emailFile(array(
    'to' => 'your@email.com',
    'from' => 'my@email.com',
    'subject' => 'Some Subject',
    'message' => '<b>Hello!</b>',
    'plain ' => 'Get a new email client!',
    'file' => '/path/to/file'
));
/**
 * Sends an email in html and plain encodings with a file attachment.
 *
 * @param array $args Arguments associative array
 *      'to' (string)
 *      'from' (string)
 *      'subject' (optional string)
 *      'message' (HTML string)
 *      'plain' (optional plain string)
 *      'file' (optional file path of the attachment)
 * @see http://webcheatsheet.com/php/send_email_text_html_attachment.php
 */
function emailFile($args) {
    $to = set_default($args['to']);
    $from = set_default($args['from']);
    $subject = set_default($args['subject'], '');
    $message = set_default($args['message'], '');
    $plain = set_default($args['plain'], '');
    $file = set_default($args['file']);

    // MIME
    $random_hash = md5(date('r', time()));
    $boundaryMixed = 'PHP-mixed-' . $random_hash;
    $boundaryAlt = 'PHP-alt-' . $random_hash;
    $charset = 'UTF-8';
    $bits = '8bit';

    // Headers
    $headers = "MIME-Version: 1.0";
    $headers .= "Reply-To: $to\r\n";
    if ($from !== NULL) {
        $headers .= "From: $from\r\n";
    }
    $headers .= "Content-Type: multipart/mixed; boundary=$boundaryMixed";
    if ($file !== NULL) {
        $info = pathinfo($file);
        $filename = $info['filename'];
        $extension = $info['extension'];
        $contents = @file_get_contents($file);
        if ($contents === FALSE) {
            throw new Exception("File contents of '$file' could not be read");
        }
        $chunks = chunk_split(base64_encode($contents));
        $attachment = <<<EOT
--$boundaryMixed
Content-Type: application/$extension; name=$filename.$extension
Content-Transfer-Encoding: base64
Content-Disposition: attachment

$chunks
EOT;
    } else {
        $attachment = '';
    }

    $body = <<<EOT
--$boundaryMixed
Content-Type: multipart/alternative; boundary=$boundaryAlt

--$boundaryAlt
Content-Type: text/plain; charset="$charset"
Content-Transfer-Encoding: $bits

$plain

--$boundaryAlt
Content-Type: text/html; charset="$charset"
Content-Transfer-Encoding: $bits

$message
--$boundaryAlt--

$attachment

--$boundaryMixed--
EOT;

    $result = @mail($to, $subject, $body, $headers);
    return $result;
}

function set_default(&$var, $default = NULL) {
    return isset($var) ? $var : $default;
}
 
This is a method that will return an array of file paths from a directory. It’s contained within CrayonUtil and calls other utility methods in that class, but can be ripped out if needed.
/**
 * @param $path A directory
 * @param array $args Argument array:
 *      hidden: If true, hidden files beginning with a dot will be included
 *      ignoreRef: If true, . and .. are ignored
 *      recursive: If true, this function is recursive
 *      ignore: An array of paths to ignore
 * @return array Files in the directory
 */
public static function getFiles($path, $args = array()) {
    $hidden = self::set_default($args['hidden'], TRUE);
    $ignoreRef = self::set_default($args['ignoreRef'], TRUE);
    $recursive = self::set_default($args['recursive'], FALSE);
    $ignore = self::set_default($args['ignore'], NULL);

    $ignore_map = array();
    if ($ignore) {
        foreach ($ignore as $i) {
            if (is_dir($i)) {
                $i = CrayonUtil::path_slash($i);
            }
            $ignore_map[$i] = TRUE;
        }
    }

    $files = glob($path . '*', GLOB_MARK);
    if ($hidden) {
        $files = array_merge($files, glob($path . '.*', GLOB_MARK));
    }
    if ($ignoreRef || $ignore) {
        $result = array();
        for ($i = 0; $i < count($files); $i++) {
            $file = $files[$i];
            if (!isset($ignore_map[$file]) && (!$ignoreRef || (basename($file) != '.' && basename($file) != '..'))) {
                $result[] = $file;
                if ($recursive && is_dir($file)) {
                    $result = array_merge($result, self::getFiles($file, $args));
                }
            }
        }
    } else {
        $result = $files;
    }
    return $result;
}
 
This issue had been rolling around in my mind in the past but I never had to implement something like it before. I had a text box where I set the background colour based on a colour picker but that meant that the text value would remain black - which wouldn’t be visible if the selected colour was also black, or even dark.
My solution was to pick a colour that differed as much as possible from black - white - and apply this methodology with all colours. If our background was white, then I would use black as the foreground. For colours in between I used a threshold - as soon as the background colour passed it (as it became darker), I would change the foreground from black to white (making it lighter). I believe the best foreground should be either white or black, since it should differ from the background as much as possible - so linear interpolation between black and white wouldn’t help here. My method was to calculate a distance from white, which is the origin at (0,0). The x-axis is saturation and the y-axis is (1 - value) in the HSV model. Using a threshold amount of 0.5, I created a radius around white where my foreground is black. Any position outside this radius means my foreground is white. By using multipliers I was able to create an ellipse shape to my liking. I ran into another issue - for colours that appear light - yellow, green, light blue - I needed to allow more black. So I stretched the radius in the x-axis for these colours. This methodology is generic enough to be applied anywhere this problem comes up, but for my implementation I used jQuery and TinyColor. See an online demo here: http://aramkocharyan.github.com/readable-color/index.html Grab the source: https://github.com/aramkocharyan/readable-color/
I had the following:
$attributeTypes = array(
    'color' => array('background', 'border-color'),
    'size' => array('border-width')
);
$attributeTypesInverse = array_flip($attributeTypes);
But I got this warning: Warning: array_flip() [function.array-flip]: Can only flip STRING and INTEGER values! So I wrote a new function to support arrays as values, not just integers or strings. Keep in mind though that the values of the arrays in values must be integers or strings in order to be valid keys for the resulting array.
function array_flip_r($array) {
    $result = array();
    foreach ($array as $k=>$v) {
        if (is_array($v)) {
            foreach ($v as $u) {
                _array_flip_r($result, $k, $u);
            }
        } else {
            _array_flip_r($result, $k, $v);
        }
    }
    return $result;
}

function _array_flip_r(&$array, $k, $v) {
    if (is_string($v) || is_int($v)) {
        $array[$v] = $k;
    } else {
        trigger_error("Values must be STRING or INTEGER", E_USER_WARNING);
    }
}
 
The Theme Editor allows you to duplicate and modify custom themes compatible with Crayon using an integrated user interface and no CSS knowledge whatsoever. Of course, make changes to your theme by editing the CSS is also possible before and after using the theme editor. You can access the theme editor in Wordpress admin under Settings > Crayon: The Theme section displays the information about the current theme, a toolbar for performing theme editor actions and the Live Preview. Modifying any settings automatically refreshes this preview before submitting the settings page.

Theme Types

Crayon stores the Stock Themes which come with the plugin under this path: wp-content/plugins/crayon-syntax-highlighter/themes To allow modifying these themes and preserving changes, Crayon stores User Themes under this path: wp-content/uploads/crayon-syntax-highlighter/themes This avoids any changes being overwritten during updates to the plugin. Stock themes can’t be deleted or modified for this reason - unless you enable CRAYON_DEBUG in globals.php. Of course, modifying the theme CSS is independent of the Theme Editor, but keep in mind that your changes will be lost when updating the plugin.

Creating Themes

Start by selecting an existing theme which is the closest appearance you’re trying to create. To play it safe, start with the Classic theme. Click Duplicate and type in a new name. The theme is duplicated as a User Theme. Now click Edit to load the Theme Editor. One handy feature of the editor is that modifications take place live just like in the regular settings page - so changing the language or settings will also change them in the theme editor, allowing you to see how your changes will look like for different settings. On the right side you’ll see the editor controls. The first tab allows you to change information about the theme. Saving the theme is possible at any time and doesn’t require a reload unless you change the name of the theme. You can also look at the CSS with a link below the name. Next, I might want to change the appearance of the frame and line colours. Next, I can change the line numbers. And then the toolbar. Finally, we can take a look at the highlighting! I’ve left this till last since I wanted to make sure I have the overall look of the new theme first. And there we have it, a new theme! Tinker with the settings until you have the right look. This theme is obviously a 5 minute demonstration and the some of the stock themes that people have put together look amazing comparatively - but the important thing to take away from this post is that creating themes is now super quick and very much integrated into Crayon!

Submitting a Theme

Remember, if you happen to create a theme you’re especially proud of, please use the Submit button - it will zip up your theme and email it to me and I’ll include it as a Stock Theme for others to enjoy!
Crayon 1.17 beta adds retina support for the buttons in the toolbar on high resolution devices. [caption id=”attachment_1081” align=”aligncenter” width=”556”] Before[/caption] [caption id=”attachment_1082” align=”aligncenter” width=”556”] After[/caption]
I’ve made Crayon with modularity in mind to allow reuse of any components if needed. Here are the Javascript components:
  • js/util.js
  • js/crayon.js
  • js/jquery.popup.js
  • js/fancybox/jquery.fancybox.init.pack.js
  • js/fancybox/fancybox_init.js
  • util/tag-editor/crayon_te.js
`util.js` has several JavaScript methods that are shared across the admin settings, tag editor, theme editor (coming soon) and of course the front end which displays the Crayons. `crayon.js` is the main script which defines the toolbar button events and other settings, like toggling etc. `jquery.popup.js` is adapted jquery plugin I use to open a code popup. As of the latest beta commit, disabling the popup now removes this resource. `jquery.fancybox.init.pack.js` is a custom version of Fancybox I modified to allow passing in my own fancybox instance without disrupting other fancybox plugins that may be running - otherwise errors occur. `fancybox_init.js` serves only the purpose of kickstarting Fancybox with my custom objects, and I agree this is somewhat wasteful of a single request. Although it’ll take less time to transfer than a larger file, I imagine there’s a fixed cost in the latency required to make the request. Mostly for the reason of reducing the number of modules needed, I’ve removed it in the latest beta commit and placed it in util.js. `crayon_te.js` is the tag editor. This appears in the front end only if you check “Display the Tag Editor in any TinyMCE instances on the frontend (e.g. bbPress)” - which is off since 1.15 on fresh installs. Having “Attempt to load Crayon’s CSS and JavaScript only when needed” still needs TinyMCE to be disabled on the front end as I’ve now mentioned here. For CSS:
  • css/crayon_style.css
  • css/global_style.css
  • js/fancybox/jquery.fancybox.css
  • themes/classic/classic.css
  • fonts/monaco.css
`crayon_style.css` is a the foundation style. `global_style.css` are styles shared across the admin and front end (such as the tag editor, which can appear anywhere TinyMCE appears). `jquery.fancybox.css` is once again for Fancybox and only loads if the Tag Editor is enabled on the front end. `classic.css` is the classic theme. `monaco.css` is the default font. Since there can be any combination of the last two, mixing them is not practical. By far the best technique to reduce the number of requests is to use WP Total Cache, which I have ensured Crayon is compatible with since 1.16. This will reduce the JS and CSS to a single file for the entire site. This allows the developer (me) to create modular and reusable components while allowing the client (you) and end users to experience better efficiency. Hope that helps!