Anchor Modifications

There are a bunch of changes that I made to Anchor to fix or implement features. Here are some of the changes:

/anchor/routes/posts.php

if(is_null($input['comments'])) {
    $input['comments'] = 0;
}
if(is_null($input['comments'])) {
    $input['comments'] = (Config::meta('auto_published_comments') == 1) ? 1 : 0;
}

This actually implements the 'Auto enable comments' in the site_meta. This wasn't in 0.9.2.

/anchor/routes/pages.php

$input = Input::get(array('parent', 'name', 'title', 'slug', 'content',
        'status', 'redirect', 'show_in_menu'));
$input = Input::get(array('parent', 'name', 'title', 'slug', 'content',
        'status', 'redirect', 'show_in_menu', 'menu_order'));
⋮
$input['menu_order'] = is_null($input['menu_order']) ? 0 : $input['menu_order'];

This makes it so you can actually add pages.

/anchor/functions/search.php

function search_string ($term) {
    $term = str_replace('\'', '\\\'', htmlspecialchars_decode($term, ENT_QUOTES));
    $rawMatches = array_merge(Post::where('title', 'like', '%' . $term . '%')->get(),Post::where('html', 'like', '%' . $term . '%')->get());
    $page = Registry::get('posts_page');
    $matches = array();
    foreach ($rawMatches as $match) {
        $temp = array(
            "title" => $match->title,
            "url" => base_url($page->slug . '/' . $match->slug)
        );
        $matches[] = $temp;
    }

    return $matches;
}

This creates an alternative search function that searches both title and text. It returns an array of arrays, where each array contains the title of the article and its link.

/anchor/views/comments/edit.php

<p>
    <label>Post:</label>
    <?php echo "<input disabled value=\"" . Post::id($comment->post)->title . "\"><br>"; ?>
</p>

When reviewing comments, this displays the name of the post the comment was on.

/anchor/routes/site.php

Route::post('search', function() {
    // search and save search ID
    $term = filter_var(Input::get('term', ''), FILTER_SANITIZE_STRING);

    // replace spaces with double-dash to pass through url
    $term = str_replace(' ', '--', $term);

    Session::put(slug($term), $term);

    return Response::redirect('search/' . slug($term));
});
Route::post('search', function() {
    // search and save search ID
    $term = str_replace(' ', '--', Input::get('term', ''));
    $term = filter_var($term, FILTER_SANITIZE_URL);

    Session::put(slug($term), $term);

    return Response::redirect('search/' . urlencode($term));
});

This fixes the search bug where it doesn't urlencode the characters, making much of the search string cut off. Now the search string can include apostrophes.

/anchor/routes/site.php

/** Sitemap */ 
Route::get('sitemap.xml', function() { 
    $sitemap = ''; $sitemap .= ' ';

    // Main page
    $sitemap .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"><url>';
    $sitemap .= '<loc>' . Uri::full(Registry::get('posts_page')->slug . '/', true) . '</loc>';
    $sitemap .= '<priority>0.9</priority>';
    $sitemap .= '<changefreq>weekly</changefreq>';
    $sitemap .= '</url>'; 

    $query = Post::where('status', '=', 'published')->sort(Base::table('posts.created'), 'desc');
    foreach($query->get() as $article) {
            $sitemap .= '<url>';
            $sitemap .= '<loc>' . Uri::full(Registry::get('posts_page')->slug . '/' . $article->slug, true) . '</loc>';
        $sitemap .= '<lastmod>' . date("Y-m-d", strtotime($article->created)) .'</lastmod>';
        $sitemap .= '<changefreq>monthly</changefreq>';
        $sitemap .= '<priority>0.8</priority>';
        $sitemap .= '</url>';
    }
    $sitemap .= '</urlset>';

    return Response::create($sitemap, 200, array('content-type' => 'application/xml'));
});

Add in a sitemap at https://blog.alexbeals.com/sitemap.xml.

/anchor/views/assets/js/editor.js

var ready = 1;

textarea.on('keydown', function(event) {
    if ((event.which == '115' || event.which == '83' ) && (event.ctrlKey || event.metaKey)) {               
        if (ready) {
            var newData = new FormData(document.forms[0]);
            var oReq = new XMLHttpRequest();
            ready = 0;
            oReq.onreadystatechange = function() {
                if (oReq.readyState == 4 && oReq.status == 200) {
                    $("input[name='token']").val(/name="token" type="hidden" value="(.*?)"/g.exec(oReq.responseText)[1]);
                    ready = 1;
                }
            }; 
            oReq.open("POST", $("form").attr("action"));
            oReq.send(newData);
        }
        event.preventDefault();
    }
});

This took way too long to implement. I was an idiot, and didn't realize the lack of reload meant it wasn't updating the 'token' variable. Luckily, I caught it. This change makes it so that pressing 'Ctrl+S' instead of attempting to save the webpage will instead save the edit if you're editing the file. Most importantly though, it does this without reloading the page, so it saves your place! A minor thing but it was incredibly annoying.

/php/upload.php

Code to take posted image and upload it to the server.

/anchor/views/assets/js/dragdrop.js

var allowed = ['text/css', 'text/javascript', 'application/javascript', 'text/x-markdown'];
var allowed = ['text/css', 'text/javascript', 'application/javascript', 'text/x-markdown', 'image/png', 'image/jpeg', 'image/gif'];
⋮
var complete = function() {
    if (['image/png', 'image/jpeg', 'image/gif'].indexOf(this.file.type) !== -1) {
        upload(this.file);
    }
}

var upload = function(file) {
    var formData = new FormData();

    formData.append("image-file", file);
    formData.append("post-name", /input type="text" name="slug" value="(.*?)"/g.exec(document.getElementsByTagName('html')[0].innerHTML)[1]);
    var oReq = new XMLHttpRequest();

    oReq.onreadystatechange = function() {
        if (oReq.readyState == 4 && oReq.status == 200) {
            var cursorPos = $('textarea').prop('selectionStart'),
            v = $('textarea').val(),
            textBefore = v.substring(0, cursorPos),
            textAfter  = v.substring(cursorPos, v.length);
            $('textarea').val(textBefore + oReq.responseText + textAfter);

            var ctrl = $('textarea')[0];
            if(ctrl.setSelectionRange) {
                ctrl.focus();
                ctrl.setSelectionRange(cursorPos+2,cursorPos+2);
            }
        }
    };
    oReq.open("POST", "/php/upload.php");
    oReq.send(formData);
};

This adds in drag and drop support for images (specifically .jpeg and .png) to post editing. This means I don't have to manually upload the images via WinSCP, and it will all take care of it for you. It will paste in the image link code at your cursor position and move the cursor so you're set up to type in the alt title. Note that the article has to be saved at least once before this can be done.