Browse Source

add tags, slug and status field to quill editor

pull/82/head
Aaron Parecki 8 years ago
parent
commit
acafb9192a
No known key found for this signature in database GPG Key ID: 276C2817346D6056
  1. 54
      controllers/controllers.php
  2. 11
      controllers/editor.php
  3. 17
      controllers/static.php
  4. 29
      public/editor-files/editor.js
  5. 50
      public/editor-files/style.css
  6. 5
      schema/migrations/0002.sql
  7. 1
      schema/mysql.sql
  8. 2
      schema/sqlite.sql
  9. 29
      views/editor.php
  10. 2
      views/layout.php
  11. 2
      views/new-post.php
  12. 37
      views/settings.php

54
controllers/controllers.php

@ -44,11 +44,10 @@ function generate_login_token() {
$app->get('/dashboard', function() use($app) { $app->get('/dashboard', function() use($app) {
if($user=require_login($app)) { if($user=require_login($app)) {
$html = render('dashboard', array(
render('dashboard', array(
'title' => 'Dashboard', 'title' => 'Dashboard',
'authorizing' => false 'authorizing' => false
)); ));
$app->response()->body($html);
} }
}); });
@ -73,7 +72,7 @@ $app->get('/new', function() use($app) {
} }
} }
$html = render('new-post', array(
render('new-post', array(
'title' => 'New Post', 'title' => 'New Post',
'in_reply_to' => $in_reply_to, 'in_reply_to' => $in_reply_to,
'micropub_endpoint' => $user->micropub_endpoint, 'micropub_endpoint' => $user->micropub_endpoint,
@ -87,7 +86,6 @@ $app->get('/new', function() use($app) {
'user' => $user, 'user' => $user,
'authorizing' => false 'authorizing' => false
)); ));
$app->response()->body($html);
} }
}); });
@ -109,7 +107,7 @@ $app->get('/bookmark', function() use($app) {
if(array_key_exists('content', $params)) if(array_key_exists('content', $params))
$content = $params['content']; $content = $params['content'];
$html = render('new-bookmark', array(
render('new-bookmark', array(
'title' => 'New Bookmark', 'title' => 'New Bookmark',
'bookmark_url' => $url, 'bookmark_url' => $url,
'bookmark_name' => $name, 'bookmark_name' => $name,
@ -119,7 +117,6 @@ $app->get('/bookmark', function() use($app) {
'syndication_targets' => json_decode($user->syndication_targets, true), 'syndication_targets' => json_decode($user->syndication_targets, true),
'authorizing' => false 'authorizing' => false
)); ));
$app->response()->body($html);
} }
}); });
@ -132,13 +129,12 @@ $app->get('/favorite', function() use($app) {
if(array_key_exists('url', $params)) if(array_key_exists('url', $params))
$url = $params['url']; $url = $params['url'];
$html = render('new-favorite', array(
render('new-favorite', array(
'title' => 'New Favorite', 'title' => 'New Favorite',
'url' => $url, 'url' => $url,
'token' => generate_login_token(), 'token' => generate_login_token(),
'authorizing' => false 'authorizing' => false
)); ));
$app->response()->body($html);
} }
}); });
@ -146,11 +142,10 @@ $app->get('/event', function() use($app) {
if($user=require_login($app)) { if($user=require_login($app)) {
$params = $app->request()->params(); $params = $app->request()->params();
$html = render('event', array(
render('event', array(
'title' => 'Event', 'title' => 'Event',
'authorizing' => false 'authorizing' => false
)); ));
$app->response()->body($html);
} }
}); });
@ -158,11 +153,10 @@ $app->get('/itinerary', function() use($app) {
if($user=require_login($app)) { if($user=require_login($app)) {
$params = $app->request()->params(); $params = $app->request()->params();
$html = render('new-itinerary', array(
render('new-itinerary', array(
'title' => 'Itinerary', 'title' => 'Itinerary',
'authorizing' => false 'authorizing' => false
)); ));
$app->response()->body($html);
} }
}); });
@ -170,12 +164,11 @@ $app->get('/photo', function() use($app) {
if($user=require_login($app)) { if($user=require_login($app)) {
$params = $app->request()->params(); $params = $app->request()->params();
$html = render('photo', array(
render('photo', array(
'title' => 'New Photo', 'title' => 'New Photo',
'note_content' => '', 'note_content' => '',
'authorizing' => false 'authorizing' => false
)); ));
$app->response()->body($html);
} }
}); });
@ -183,11 +176,10 @@ $app->get('/review', function() use($app) {
if($user=require_login($app)) { if($user=require_login($app)) {
$params = $app->request()->params(); $params = $app->request()->params();
$html = render('review', array(
render('review', array(
'title' => 'Review', 'title' => 'Review',
'authorizing' => false 'authorizing' => false
)); ));
$app->response()->body($html);
} }
}); });
@ -200,13 +192,12 @@ $app->get('/repost', function() use($app) {
if(array_key_exists('url', $params)) if(array_key_exists('url', $params))
$url = $params['url']; $url = $params['url'];
$html = render('new-repost', array(
render('new-repost', array(
'title' => 'New Repost', 'title' => 'New Repost',
'url' => $url, 'url' => $url,
'token' => generate_login_token(), 'token' => generate_login_token(),
'authorizing' => false 'authorizing' => false
)); ));
$app->response()->body($html);
} }
}); });
@ -258,8 +249,7 @@ $app->get('/add-to-home', function() use($app) {
$app->redirect('/add-to-home?token='.$token, 301); $app->redirect('/add-to-home?token='.$token, 301);
} else { } else {
unset($_SESSION['add-to-home-started']); unset($_SESSION['add-to-home-started']);
$html = render('add-to-home', array('title' => 'Quill'));
$app->response()->body($html);
render('add-to-home', array('title' => 'Quill'));
} }
} }
} }
@ -285,24 +275,40 @@ $app->get('/email', function() use($app) {
$user->save(); $user->save();
} }
$html = render('email', array(
render('email', array(
'title' => 'Post-by-Email', 'title' => 'Post-by-Email',
'micropub_endpoint' => $user->micropub_endpoint, 'micropub_endpoint' => $user->micropub_endpoint,
'test_response' => $test_response, 'test_response' => $test_response,
'user' => $user 'user' => $user
)); ));
$app->response()->body($html);
} }
}); });
$app->get('/settings', function() use($app) { $app->get('/settings', function() use($app) {
if($user=require_login($app)) { if($user=require_login($app)) {
$html = render('settings', [
render('settings', [
'title' => 'Settings', 'title' => 'Settings',
'user' => $user, 'user' => $user,
'authorizing' => false 'authorizing' => false
]); ]);
$app->response()->body($html);
}
});
$app->post('/settings/save', function() use($app) {
if($user=require_login($app)) {
$params = $app->request()->params();
if(array_key_exists('html_content', $params))
$user->micropub_optin_html_content = $params['html_content'] ? 1 : 0;
if(array_key_exists('slug_field', $params) && $params['slug_field'])
$user->micropub_slug_field = $params['slug_field'];
$user->save();
$app->response()['Content-type'] = 'application/json';
$app->response()->body(json_encode(array(
'result' => 'ok'
)));
} }
}); });

11
controllers/editor.php

@ -25,6 +25,17 @@ $app->post('/editor/publish', function() use($app) {
'content' => $content 'content' => $content
); );
if(array_key_exists('category', $params) && $params['category'])
$micropub_request['category'] = $params['category'];
if(array_key_exists('slug', $params) && $params['slug'])
$micropub_request[$user->micropub_slug_field] = $params['slug'];
if(array_key_exists('status', $params) && $params['status']) {
if($params['status'] == 'draft')
$micropub_request['post-status'] = $params['status'];
}
$r = micropub_post_for_user($user, $micropub_request); $r = micropub_post_for_user($user, $micropub_request);
$app->response()['Content-type'] = 'application/json'; $app->response()['Content-type'] = 'application/json';

17
controllers/static.php

@ -7,14 +7,11 @@ $app->get('/', function($format='html') use($app) {
$app->redirect('/auth/start?'.http_build_query($params), 302); $app->redirect('/auth/start?'.http_build_query($params), 302);
} }
ob_start();
render('index', array( render('index', array(
'title' => 'Quill', 'title' => 'Quill',
'meta' => '', 'meta' => '',
'authorizing' => false 'authorizing' => false
)); ));
$html = ob_get_clean();
$res->body($html);
}); });
$app->get('/creating-a-token-endpoint', function() use($app) { $app->get('/creating-a-token-endpoint', function() use($app) {
@ -22,16 +19,18 @@ $app->get('/creating-a-token-endpoint', function() use($app) {
}); });
$app->get('/creating-a-micropub-endpoint', function() use($app) { $app->get('/creating-a-micropub-endpoint', function() use($app) {
$html = render('creating-a-micropub-endpoint', array('title' => 'Creating a Micropub Endpoint', 'authorizing' => false));
$app->response()->body($html);
render('creating-a-micropub-endpoint', array('title' => 'Creating a Micropub Endpoint', 'authorizing' => false));
}); });
$app->get('/docs', function() use($app) { $app->get('/docs', function() use($app) {
$html = render('docs', array('title' => 'Documentation', 'authorizing' => false));
$app->response()->body($html);
render('docs', array('title' => 'Documentation', 'authorizing' => false));
});
$app->get('/docs/post-status', function() use($app) {
render('docs/post-status', array('title' => 'Post Status Documentation', 'authorizing' => false));
}); });
$app->get('/privacy', function() use($app) { $app->get('/privacy', function() use($app) {
$html = render('privacy', array('title' => 'Quill Privacy Policy', 'authorizing' => false));
$app->response()->body($html);
render('privacy', array('title' => 'Quill Privacy Policy', 'authorizing' => false));
}); });

29
public/editor-files/editor.js

@ -47,6 +47,7 @@ $(function() {
$('#publish-success').addClass('hidden'); $('#publish-success').addClass('hidden');
$('#publish-error').addClass('hidden'); $('#publish-error').addClass('hidden');
$('#publish-help').removeClass('hidden'); $('#publish-help').removeClass('hidden');
$('#publish-fields').removeClass('hidden');
} else { } else {
$('.publish-dropdown').addClass('hidden'); $('.publish-dropdown').addClass('hidden');
} }
@ -69,10 +70,14 @@ $(function() {
$('#publish-confirm').click(function(){ $('#publish-confirm').click(function(){
$('#publish-help').addClass('hidden'); $('#publish-help').addClass('hidden');
$('#publish-in-progress').removeClass('hidden'); $('#publish-in-progress').removeClass('hidden');
$('#publish-fields').addClass('hidden');
$.post('/editor/publish', { $.post('/editor/publish', {
name: $("#post-name").val(), name: $("#post-name").val(),
body: editor.serialize().content.value
body: editor.serialize().content.value,
category: csv_to_array($("#post-tags").val()),
slug: $("#post-slug").val(),
status: $("#post-status").val()
}, function(response) { }, function(response) {
if(response.location) { if(response.location) {
reset_page().then(function(){ reset_page().then(function(){
@ -87,6 +92,7 @@ $(function() {
$('#publish-error-debug').html(response.response).removeClass('hidden'); $('#publish-error-debug').html(response.response).removeClass('hidden');
$('#publish-error').removeClass('hidden'); $('#publish-error').removeClass('hidden');
$('#publish-success').addClass('hidden'); $('#publish-success').addClass('hidden');
$('#publish-fields').removeClass('hidden');
} }
}); });
}); });
@ -99,6 +105,10 @@ $(function() {
}); });
}); });
$("#post-status").change(function(){
$("#published-status-warning").removeClass("hidden");
});
$.getJSON('/settings/html-content', function(data){ $.getJSON('/settings/html-content', function(data){
if(data.html == '0') { if(data.html == '0') {
$('.micropub-html-warning').show(); $('.micropub-html-warning').show();
@ -108,20 +118,21 @@ $(function() {
function reset_page() { function reset_page() {
$("#post-name").val(''); $("#post-name").val('');
$("#post-slug").val('');
$("#post-tags").val('');
$("#post-status").val('published');
$("#content").html(''); $("#content").html('');
$("#draft-status").text("New"); $("#draft-status").text("New");
$("#publish-confirm").hide(); $("#publish-confirm").hide();
return localforage.setItem('currentdraft', {}); return localforage.setItem('currentdraft', {});
} }
function onUpdateReady() {
// Show the notice that says there is a new version of the app
$("#new_version_available").show();
}
window.applicationCache.addEventListener('updateready', onUpdateReady);
if(window.applicationCache.status === window.applicationCache.UPDATEREADY) {
onUpdateReady();
function csv_to_array(val) {
if(val.length > 0) {
return val.split(/[, ]+/);
} else {
return [];
}
} }
/* ************************************************ */ /* ************************************************ */

50
public/editor-files/style.css

@ -22,6 +22,10 @@ h1, h2, h3, h4, h5, h6, th, td, caption { font-weight:normal; }
img { border: 0; } img { border: 0; }
/* ************************************** */
.micropub-html-warning { .micropub-html-warning {
max-width: 600px; max-width: 600px;
margin-left: auto; margin-left: auto;
@ -49,6 +53,8 @@ img { border: 0; }
float: right; float: right;
} }
/* ************************************** */ /* ************************************** */
/* Toolbar */ /* Toolbar */
@ -120,15 +126,23 @@ img { border: 0; }
input.form-field-small { input.form-field-small {
height: 24px; height: 24px;
margin-top: 1px;
margin-top: 2px;
font-size: 13px; font-size: 13px;
color: #51a1a8; color: #51a1a8;
padding: 0 10px; padding: 0 10px;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
border-radius: 6px;
border: 1px #93dee5 solid; border: 1px #93dee5 solid;
} }
select.form-select-small {
border-radius: 6px;
border: 1px #93dee5 solid;
height: 24px;
margin-top: 2px;
font-size: 13px;
color: #51a1a8;
}
.publish-dropdown { .publish-dropdown {
position: fixed; position: fixed;
@ -165,6 +179,10 @@ input.form-field-small {
.publish-dropdown .dropdown-content { .publish-dropdown .dropdown-content {
padding: 9px; padding: 9px;
} }
.publish-dropdown .dropdown-content,
.publish-dropdown .dropdown-content a {
color: #51a1a8;
}
.publish-dropdown input { .publish-dropdown input {
font-family: sans-serif; font-family: sans-serif;
} }
@ -182,30 +200,10 @@ pre#publish-error-debug {
display: none; display: none;
} }
/* ************************************** */
/* App Cache */
#new_version_available {
display: none;
position: fixed;
z-index: 1000;
bottom: 0;
left: 0;
right: 0;
background: rgba(246,206,217,0.3);
}
#new_version_available .inner {
padding: 10px;
width: 600px;
margin: 0 auto;
text-align: center;
font-weight: bold;
color: #cf224f;
font-size: 14px;
font-family: sans-serif;
.small {
font-size: 0.8em;
} }
/* ************************************** */ /* ************************************** */
/* Editor CSS */ /* Editor CSS */

5
schema/migrations/0002.sql

@ -0,0 +1,5 @@
ALTER TABLE users
ADD COLUMN `micropub_slug_field` VARCHAR(255) NOT NULL DEFAULT 'mp-slug' AFTER `micropub_response`;
UPDATE users
SET micropub_slug_field = 'slug';

1
schema/mysql.sql

@ -8,6 +8,7 @@ CREATE TABLE `users` (
`micropub_access_token` text, `micropub_access_token` text,
`micropub_scope` varchar(255) DEFAULT NULL, `micropub_scope` varchar(255) DEFAULT NULL,
`micropub_response` text, `micropub_response` text,
`micropub_slug_field` varchar(255) NOT NULL DEFAULT 'mp-slug',
`micropub_success` tinyint(4) DEFAULT '0', `micropub_success` tinyint(4) DEFAULT '0',
`date_created` datetime DEFAULT NULL, `date_created` datetime DEFAULT NULL,
`last_login` datetime DEFAULT NULL, `last_login` datetime DEFAULT NULL,

2
schema/sqlite.sql

@ -4,9 +4,11 @@ CREATE TABLE users (
authorization_endpoint TEXT, authorization_endpoint TEXT,
token_endpoint TEXT, token_endpoint TEXT,
micropub_endpoint TEXT, micropub_endpoint TEXT,
micropub_media_endpoint TEXT,
micropub_access_token TEXT, micropub_access_token TEXT,
micropub_scope TEXT, micropub_scope TEXT,
micropub_response TEXT, micropub_response TEXT,
micropub_slug_field TEXT default 'mp-slug',
micropub_success INTEGER default 0, micropub_success INTEGER default 0,
date_created datetime, date_created datetime,
last_login datetime, last_login datetime,

29
views/editor.php

@ -67,14 +67,29 @@
<div class="dropdown-content action-publish"> <div class="dropdown-content action-publish">
<div style="float:right"><button class="btn btn-medium" id="publish-confirm">Publish Now</button></div> <div style="float:right"><button class="btn btn-medium" id="publish-confirm">Publish Now</button></div>
<div style="clear:right;"></div>
<div style="clear:right; margin-bottom: 4px;"></div>
<table id="publish-fields">
<tr>
<td>Tags:</td>
<td><input type="text" class="form-field-small" placeholder="comma separated" id="post-tags"></td>
</tr>
<tr>
<td>Slug:</td>
<td><input type="text" class="form-field-small" id="post-slug"></td>
</tr>
<tr>
<td>Status:</td>
<td>
<select id="post-status" class="form-select-small">
<option value="published">Published</option>
<option value="draft">Draft</option>
</select>
<a href="/docs/post-status" class="small hidden" target="_blank" id="published-status-warning">read this first!</a>
</td>
</tr>
</table>
<div class="helptext" id="publish-help">
<div style="font-size:0.8em;">
Clicking "Publish Now" will send a request to your Micropub endpoint.<br><br>
The request will include two fields, "name" and "content", where the content will be the full HTML for this post.
</div>
</div>
<div class="helptext hidden" id="publish-in-progress"> <div class="helptext hidden" id="publish-in-progress">
Posting... <!-- TODO replace this with a CSS animated spinner --> Posting... <!-- TODO replace this with a CSS animated spinner -->

2
views/layout.php

@ -90,7 +90,7 @@
</ul> </ul>
</div> </div>
<p class="credits">&copy; <?=date('Y')?> by <a href="http://aaronparecki.com">Aaron Parecki</a>.
<p class="credits">&copy; <?=date('Y')?> by <a href="https://aaronparecki.com">Aaron Parecki</a>.
This code is <a href="https://github.com/aaronpk/Quill">open source</a>. This code is <a href="https://github.com/aaronpk/Quill">open source</a>.
Feel free to send a pull request, or <a href="https://github.com/aaronpk/Quill/issues">file an issue</a>.</p> Feel free to send a pull request, or <a href="https://github.com/aaronpk/Quill/issues">file an issue</a>.</p>
</div> </div>

2
views/new-post.php

@ -419,7 +419,7 @@ $(function(){
} }
} }
if(v=$("#note_slug").val()) { if(v=$("#note_slug").val()) {
formData.append("slug", v);
formData.append("<?= $this->user->micropub_slug_field ?>", v);
} }
// Add either the photo as a file, or the photo URL depending on whether the user has a media endpoint // Add either the photo as a file, or the photo URL depending on whether the user has a media endpoint

37
views/settings.php

@ -18,7 +18,7 @@
</tr> </tr>
<tr> <tr>
<td>media endpoint</td> <td>media endpoint</td>
<td><?= $this->user->media_endpoint ? '<code>'.$this->user->media_endpoint.'</code>' : '<a href="https://www.w3.org/TR/micropub/#media-endpoint">no media endpoint</a>' ?></td>
<td><?= $this->user->micropub_media_endpoint ? '<code>'.$this->user->micropub_media_endpoint.'</code>' : '<a href="https://www.w3.org/TR/micropub/#media-endpoint">no media endpoint</a>' ?></td>
</tr> </tr>
<tr> <tr>
<td width="140">access token</td> <td width="140">access token</td>
@ -31,6 +31,28 @@
<p>Connecting a Twitter account will automatically "favorite" and "retweet" tweets on Twitter when you favorite and retweet a Twitter URL in Quill.</p> <p>Connecting a Twitter account will automatically "favorite" and "retweet" tweets on Twitter when you favorite and retweet a Twitter URL in Quill.</p>
<input type="button" id="twitter-button" value="Checking" class="btn"> <input type="button" id="twitter-button" value="Checking" class="btn">
<h3>Backwards Compatibility</h3>
<p>You can customize some of the properties that are sent in the Micropub request to work with your specific endpoint.</p>
<table class="table table-condensed">
<tr>
<td>Slug</td>
<td>
<div style="margin-bottom:4px;"><input type="text" id="slug-field-name" value="<?= $this->user->micropub_slug_field ?>" placeholder="mp-slug" class="form-control"></div>
<div><input type="button" class="btn btn-primary" value="Save" id="save-slug-field"></div>
</td>
<td>Choose the name of the field that the slug will be sent in. This should be set to <code>mp-slug</code> unless your endpoint is using a custom property or the deprecated <code>slug</code> property.</td>
</tr>
<tr>
<td>Send HTML Content</td>
<td><input type="checkbox" id="send-html-content" <?= $this->user->micropub_optin_html_content ? 'checked="checked"' : '' ?>></td>
<td>When checked, content from Quill's HTML editor will be sent in a property called <code>content[html]</code> rather than just <code>content</code>. See the <a href="https://www.w3.org/TR/micropub/#new-article-with-html">Micropub specification</a> for more details.</td>
</tr>
</table>
</div> </div>
<script> <script>
$(function(){ $(function(){
@ -56,5 +78,18 @@ $(function(){
} }
}); });
$("#send-html-content").click(function(){
var enabled = $(this).attr("checked") == "checked";
$.post("/settings/save", {
html_content: (enabled ? 1 : 0)
});
});
$("#save-slug-field").click(function(){
$.post("/settings/save", {
slug_field: $("#slug-field-name").val()
});
});
}); });
</script> </script>
Loading…
Cancel
Save