diff options
Diffstat (limited to 'views')
-rw-r--r-- | views/auth_start.php | 4 | ||||
-rw-r--r-- | views/creating-a-micropub-endpoint.php | 10 | ||||
-rw-r--r-- | views/dashboard.php | 1 | ||||
-rw-r--r-- | views/docs/editor.php | 17 | ||||
-rw-r--r-- | views/email.php | 18 | ||||
-rw-r--r-- | views/event.php | 114 | ||||
-rw-r--r-- | views/new-itinerary.php | 17 | ||||
-rw-r--r-- | views/new-post.php | 50 | ||||
-rw-r--r-- | views/partials/syndication-js.php | 18 | ||||
-rw-r--r-- | views/settings.php | 43 | ||||
-rw-r--r-- | views/twitter.php | 83 |
11 files changed, 323 insertions, 52 deletions
diff --git a/views/auth_start.php b/views/auth_start.php index a6df0da..856caec 100644 --- a/views/auth_start.php +++ b/views/auth_start.php @@ -48,8 +48,8 @@ <form action="/auth/redirect" method="get"> <p>Choose the scope to request:</p> <ul style="list-style-type: none;"> - <li><input type="radio" name="scope" value="create update media" checked="checked"> create update media (default)</li> - <li><input type="radio" name="scope" value="create"> create</li> + <li><input type="radio" name="scope" value="profile create update media" checked="checked"> profile create update media (default)</li> + <li><input type="radio" name="scope" value="create"> profile create</li> <li><input type="radio" name="scope" value="post"> post (legacy)</li> </ul> diff --git a/views/creating-a-micropub-endpoint.php b/views/creating-a-micropub-endpoint.php index 4da9510..68ca8ff 100644 --- a/views/creating-a-micropub-endpoint.php +++ b/views/creating-a-micropub-endpoint.php @@ -9,7 +9,7 @@ it is ready to make requests to create posts. ### The Request -This is not intended to be a comprehensive guide to Micropub, and only includes the +This is not intended to be a comprehensive guide to Micropub, and only includes the fields that this client sends. The request to create a post will be sent with as a standard HTTP form-encoded request @@ -49,7 +49,7 @@ at hand that can be used to check: * `issued_at` - The date the token was issued. Keep in mind that it may be possible for another user besides yourself to have created -an access token at your token endpoint, so the first thing you'll do when verifying +an access token at your token endpoint, so the first thing you'll do when verifying is making sure the "me" parameter matches your own domain. This way you are the only one that can create posts on your website. @@ -57,7 +57,7 @@ one that can create posts on your website. ### Validating the Request Parameters A valid request to create a post will contain the parameters listed above. For now, -you can verify the presence of everything in the list, or you can try to genericize your +you can verify the presence of everything in the list, or you can try to genericize your micropub endpoint so that it can also create <a href="http://ownyourgram.com/creating-a-micropub-endpoint">photo posts</a>. At a bare minimum, a Micropub request will contain the following: @@ -81,7 +81,7 @@ HTTP/1.1 201 Created Location: http://example.com/post/100 </pre> -If there was an error, the response should include an HTTP error code as appropriate, +If there was an error, the response should include an HTTP error code as appropriate, and optionally an HTML or other body with more information. Below is a list of possible errors. * `HTTP 401 Unauthorized` - No access token was provided in the request. @@ -90,5 +90,5 @@ and optionally an HTML or other body with more information. Below is a list of p -<?= Markdown(ob_get_clean()) ?> +<?= \Michelf\Markdown::defaultTransform(ob_get_clean()) ?> </div> diff --git a/views/dashboard.php b/views/dashboard.php index e2b5963..51c13f1 100644 --- a/views/dashboard.php +++ b/views/dashboard.php @@ -30,7 +30,6 @@ <?php if(supports_post_type($this->user, 'review')): ?> <li><a href="/review">⭐️</a></li> <?php endif; ?> - <li><a href="/email">✉️</a></li> <li><a href="/settings">⚙</a></li> </ul> <div style="clear:both;"></div> diff --git a/views/docs/editor.php b/views/docs/editor.php index 9cac51a..30606da 100644 --- a/views/docs/editor.php +++ b/views/docs/editor.php @@ -43,12 +43,21 @@ Authorization: Bearer XXXXXXXXXXX { "type": "h-entry", "properties": { - "name": ["Post Title"], + "name": [ + "Post Title" + ], "content": [ - "html": "<p>The HTML contents of your post from the editor</p>" + { + "html": "<p>The HTML contents of your post from the editor</p>" + } + ], + "mp-slug": [ + "slug" ], - "mp-slug": ["slug"], - "category": ["foo","bar"] + "category": [ + "foo", + "bar" + ] } } </pre> diff --git a/views/email.php b/views/email.php index e3464f6..4781c7a 100644 --- a/views/email.php +++ b/views/email.php @@ -1,22 +1,6 @@ <div class="narrow"> <?= partial('partials/header') ?> - <div class="jumbotron" style="margin-top: 20px;"> - <p> - Send email or MMS to<br> - <a href="mailto:<?= $this->user->email_username . '@' . Config::$hostname ?>"><?= $this->user->email_username . '@' . Config::$hostname ?></a> - </p> - </div> - - <div style="width: 80%; margin: 0 auto;"> - <h3>Email Subject</h3> - <p>If you add a subject line to your email, it will be sent as the "name" property which indicates to your Micropub endpoint that this is a blog post.</p> - - <h3>Email and MMS body</h3> - <p>The text of your email or MMS will be send as the "content" property, which is the main contents of your post. Plaintext only for now.</p> - - <h3>Photo</h3> - <p>If you attach a photo to your email or MMS, it will be sent to your Micropub endpoint. (Only one photo is currently supported.)</p> - </div> + <p>This feature is not available.</p> </div> diff --git a/views/event.php b/views/event.php index 81742d8..cf86747 100644 --- a/views/event.php +++ b/views/event.php @@ -39,11 +39,75 @@ </div> </div> + <div id="presentation-fields" class="hidden"> + + <div class="form-group" style="margin-top: 18px;"> + <label>Link to Slides</label> + <input type="url" class="form-control" id="slides"> + </div> + + <div class="form-group"> + <label for="slides-embed">Slides Embed Code</label> + <textarea id="slides-embed" class="form-control" style="height: 4em;"></textarea> + </div> + + <div class="form-group" style="margin-top: 18px;"> + <label>Link to Video</label> + <input type="url" class="form-control" id="video-link"> + </div> + + <div class="form-group"> + <label for="video-embed">Video Embed Code</label> + <textarea id="video-embed" class="form-control" style="height: 4em;"></textarea> + </div> + + <div class="form-group" style="margin-top: 18px;"> + <label>Conference</label> + <div class="form-group"> + <input type="text" id="conference-name" class="form-control" style="max-width: 48%; margin-right: 4px; float: left;" placeholder="Conference Name"> + <input type="url" id="conference-url" class="form-control" style="max-width: 48%; margin-right: 4px; float: left;" placeholder="https://example.com"> + </div> + <div style="clear:both;"></div> + </div> + + </div> + + <div class="form-group"> + <label for="note_content">Content</label> + <textarea id="note_content" value="" class="form-control" rows="6"></textarea> + </div> + + <div class="form-group hidden" id="content-type-selection"> + <label for="note_content_type">Content Type</label> + <select class="form-control" id="note_content_type"> + <option value="text/plain">Text</option> + <option value="text/markdown">Markdown</option> + </select> + </div> + <div class="form-group" style="margin-top: 18px;"> <label for="note_category">Tags</label> <input type="text" id="note_category" value="" class="form-control"> </div> + <?php if($this->channels): ?> + <div class="form-group"> + <label for="note_channel">Channel</label> + <div id="channel-container"> + <?php + echo '<select class="form-control" id="note_channel">'; + echo '<option value="none"></option>'; + foreach($this->channels as $ch) { + echo '<option value="'.htmlspecialchars($ch).'" '.($ch == 'events' ? 'selected' : '').'>' + . htmlspecialchars($ch) + . '</option>'; + } + echo '</select>'; + ?> + </div> + </div> + <?php endif; ?> + <div style="float: right; margin-top: 6px;"> <button class="btn btn-success" id="btn_post">Post</button> </div> @@ -77,6 +141,30 @@ var selectedPlacePin; } + $(document).bind('keydown', function(e){ + // Easter egg: press ctrl+shift+c to reveal a content type selection + if(e.keyCode == 67 && e.ctrlKey && e.shiftKey) { + $("#content-type-selection").removeClass("hidden"); + } + // Easter egg: press ctrl+shift+m to switch to markdown + if(e.keyCode == 77 && e.ctrlKey && e.shiftKey) { + switchToMarkdown(); + } + // Enable "presentation mode" which adds a few fields + if(e.keyCode == 80 && e.ctrlKey && e.shiftKey) { + enablePresentationMode(); + } + }); + + function switchToMarkdown() { + $("#content-type-selection select").val("text/markdown"); + $("#content-type-selection").removeClass("hidden"); + } + + function enablePresentationMode() { + $("#presentation-fields").removeClass("hidden"); + } + $(function(){ // Start the event timezone offset in the browser's timezone $("#start_date .timezone").attr("placeholder", tzOffset); @@ -222,13 +310,37 @@ name: [$("#event_name").val()], start: [event_start], location: (selectedPlace ? selectedPlace : $("#event_location").val()), - category: tokenfieldToArray("#note_category") + category: tokenfieldToArray("#note_category"), + content: $("#note_content").val() }; if(event_end) { properties.end = event_end; } + if($("#note_channel").val()) { + properties['p3k-channel'] = $("#note_channel").val(); + } + + if(!$("#content-type-selection").hasClass("hidden")) { + properties['p3k-content-type'] = $("#note_content_type").val(); + } + + if(!$("#presentation-fields").hasClass("hidden")) { + properties['slides'] = $("#slides").val(); + properties['slides-embed'] = $("#slides-embed").val(); + properties['video-link'] = $("#video-link").val(); + properties['video-embed'] = $("#video-embed").val(); + if($("#conference-name").val()) { + properties['conference'] = { + type: 'h-event', + properties: { + name: $("#conference-name").val(), + url: $("#conference-url").val() + } + }; + } + } $.post("/micropub/postjson", { data: JSON.stringify({ diff --git a/views/new-itinerary.php b/views/new-itinerary.php index e40ec2a..f0661e9 100644 --- a/views/new-itinerary.php +++ b/views/new-itinerary.php @@ -146,17 +146,30 @@ $(function(){ $(el.target).parents(".itinerary-leg").find(".leg-arrival-tz").parent().addClass("has-success"); }); }); + $(".leg-departure-date").unbind("change").change(function(el){ + $(el.target).parents(".itinerary-leg").find(".leg-arrival-date").val($(el.target).val()); + }); } function add_leg() { + var last_date = $(".itinerary-leg:last .date").val(); + var last_airport = $(".itinerary-leg:last .leg-destination").val(); + var last_operator = $(".itinerary-leg:last .leg-operator").val(); + $("#itinerary-legs-container").append($("#leg-template").html()); $(".itinerary-leg:last .template").val(0); var d = new Date(); - $(".itinerary-leg:last .date").val(d.getFullYear()+"-"+zero_pad(d.getMonth()+1)+"-"+zero_pad(d.getDate())); + if(last_date) { + $(".itinerary-leg:last .date").val(last_date); + } else { + $(".itinerary-leg:last .date").val(d.getFullYear()+"-"+zero_pad(d.getMonth()+1)+"-"+zero_pad(d.getDate())); + } $(".itinerary-leg:last .time").val(zero_pad(d.getHours())+":"+zero_pad(d.getMinutes())+":00"); $(".itinerary-leg:last .tz").val(tz_seconds_to_offset(d.getTimezoneOffset() * 60 * -1)); - + $(".itinerary-leg:last .leg-origin").val(last_airport); + $(".itinerary-leg:last .leg-operator").val(last_operator); + /* $('.itinerary-leg:last .date').datepicker({ 'format': 'yyyy-mm-dd', diff --git a/views/new-post.php b/views/new-post.php index dad9427..ea8eb78 100644 --- a/views/new-post.php +++ b/views/new-post.php @@ -46,11 +46,18 @@ </div> <div class="form-group"> + <div id="mastodon_content_remaining" class="mcheck500"><img src="/images/mastodon.ico" width="16"> <span>500</span></div> <div id="note_content_remaining" class="pcheck206"><img src="/images/twitter.ico"> <span>280</span></div> + <div id="bluesky_content_remaining" class="bcheck256"><img src="/images/bluesky.png" width="16"> <span>256</span></div> <label for="note_content">Content</label> <textarea id="note_content" value="" class="form-control" style="height: 4em;"></textarea> </div> + <div class="form-group hidden" id="published-field"> + <label for="note_published_date">Published</label> + <input type="text" placeholder="YYYY-MM-DD hh:mm:ss +zz:zz" pattern="\d{4}-\d{2}-\d{2}[ T]\d\d:\d\d:\d\d[ ]?[+\-]\d\d:?\d\d" class="form-control" id="note_published_date"> + </div> + <div class="form-group hidden" id="content-type-selection"> <label for="note_content_type">Content Type</label> <select class="form-control" id="note_content_type"> @@ -84,7 +91,7 @@ <label for="visibility">Visibility</label> <select class="form-control" id="visibility"> <?php - foreach(['Public','Unlisted','Private'] as $v): + foreach(['Public','Unlisted','Protected','Private'] as $v): if(in_array(strtolower($v), $this->supported_visibility)): echo '<option value="'.strtolower($v).'">'.$v.'</option>'; endif; @@ -215,10 +222,11 @@ margin-bottom: 1em; } -#note_content_remaining { +#note_content_remaining, #mastodon_content_remaining, #bluesky_content_remaining { float: right; font-size: 0.8em; font-weight: bold; + margin-left: 10px; } #modal_photo_preview { @@ -260,6 +268,10 @@ .pcheck200,.pcheck208 { color: #59cb3a; } /* exactly fits 280 chars, both with or without RT */ .pcheck413 { color: #a73b3b; } /* over max tweet length */ +.lengthOK { color: #6ba15c; } +.lengthWARN { color: #c4b404; } +.lengthOVER { color: #a73b3b; } + .reply-context { display: flex; flex-direction: row; @@ -470,12 +482,25 @@ $(function(){ refreshPhotoPreviews(); saveNoteState(); }); + + $("#note_published_date").bind('keyup', function(e) { + const valid = document.getElementById("note_published_date").validity; + if(valid.patternMismatch) { + $("#published-field").addClass("has-error"); + } else { + $("#published-field").removeClass("has-error"); + } + }); $(document).bind('keydown', function(e){ // Easter egg: press ctrl+shift+c to reveal a content type selection if(e.keyCode == 67 && e.ctrlKey && e.shiftKey) { $("#content-type-selection").removeClass("hidden"); } + // Easter egg: press ctrl+shift+d to reveal a datetime field + if(e.keyCode == 68 && e.ctrlKey && e.shiftKey) { + $("#published-field").removeClass("hidden"); + } // Easter egg: press ctrl+shift+m to switch to markdown if(e.keyCode == 77 && e.ctrlKey && e.shiftKey) { switchToMarkdown(); @@ -599,10 +624,24 @@ $(function(){ var tweet_length = tw_text_proxy(text).length; var tweet_check = tw_length_check(text, 280, "<?= $this->user->twitter_username ?>"); var remaining = 280 - tweet_length; - $("#note_content_remaining span").html(remaining); + $("#note_content_remaining span").text(remaining); $("#note_content_remaining").removeClass("pcheck200 pcheck206 pcheck207 pcheck208 pcheck413"); $("#note_content_remaining").addClass("pcheck"+tweet_check); + $("#mastodon_content_remaining span").text(500 - text.length); + $("#mastodon_content_remaining").removeClass("lengthOK lengthWARN lengthOVER"); + mastodonLengthCheck = "lengthOK"; + if(text.length > 490) { mastodonLengthCheck = "lengthWARN"; } + if(text.length > 500) { mastodonLengthCheck = "lengthOVER"; } + $("#mastodon_content_remaining").addClass(mastodonLengthCheck); + + $("#bluesky_content_remaining span").text(256 - text.length); + $("#bluesky_content_remaining").removeClass("lengthOK lengthWARN lengthOVER"); + blueskyLengthCheck = "lengthOK"; + if(text.length > 240) { blueskyLengthCheck = "lengthWARN"; } + if(text.length > 256) { blueskyLengthCheck = "lengthOVER"; } + $("#bluesky_content_remaining").addClass(blueskyLengthCheck); + // If the user didn't enter any categories, add them from the post // if(!userHasSetCategory) { // var tags = $("#note_content").val().match(/#[a-z][a-z0-9]+/ig); @@ -803,6 +842,11 @@ $(function(){ formData.append('p3k-content-type', $("#note_content_type").val()); } + if(!$("#published-field").hasClass("hidden")) { + entry['published'] = $("#note_published_date").val(); + formData.append('published', $("#note_published_date").val()); + } + // Need to append a placeholder field because if the file size max is hit, $_POST will // be empty, so the server needs to be able to recognize a post with only a file vs a failed one. // This will be stripped by Quill before it's sent to the Micropub endpoint diff --git a/views/partials/syndication-js.php b/views/partials/syndication-js.php index 90331ba..ead1889 100644 --- a/views/partials/syndication-js.php +++ b/views/partials/syndication-js.php @@ -26,3 +26,21 @@ function bind_syndication_buttons() { return false; }); } + + +function reload_channels() { + $.getJSON("/micropub/channels", function(data){ + console.log(data); + if(data.channels) { + $("#channel-container").html('<select class="form-control" name="channel"></select>'); + for(var i in data.channels) { + var channel = data.channels[i]; + $("#channel-container select").append('<option value="'+htmlspecialchars(channel)+'">'+htmlspecialchars(channel)+'</option>'); + } + } else { + + } + console.log(data); + }); +} + diff --git a/views/settings.php b/views/settings.php index 72028c1..f51e69c 100644 --- a/views/settings.php +++ b/views/settings.php @@ -92,13 +92,37 @@ echo '</ul>'; } else { ?><div class="bs-callout bs-callout-warning">No syndication targets were found on your site. - Your server can provide a <a href="/docs#syndication">list of supported syndication targets</a> that will appear as checkboxes here.</div><?php + Your server can provide a <a href="/docs/syndication">list of supported syndication targets</a> that will appear as buttons here.</div><?php } ?> </div> </div> + <h3>Channels</h3> + + <div class="form-group"> + <label for="note_channels"><a href="javascript:reload_channels()">Reload</a></label> + <div id="channel-container"> + <?php + if($this->channels) { + echo '<select class="form-control" name="channel">'; + foreach($this->channels as $ch) { + echo '<option value="'.htmlspecialchars($ch).'">' + . htmlspecialchars($ch) + . '</option>'; + } + echo '</select>'; + } else { + ?><div class="bs-callout bs-callout-warning">No channels were found on your site. + Your server can provide a <a href="/docs/channels">list of channels</a> that will appear as buttons here.</div><?php + } + ?> + </div> + </div> + + + <?php if(!Config::$twitterClientID): ?> <h3>Twitter</h3> <p>Connecting a Twitter account will automatically "favorite" and "retweet" tweets on Twitter when you favorite and retweet a Twitter URL in Quill.</p> @@ -201,21 +225,6 @@ $(function(){ }); -function reload_syndications() { - $.getJSON("/micropub/syndications", function(data){ - if(data.targets) { - $("#syndication-container").html('<ul></ul>'); - for(var i in data.targets) { - var target = data.targets[i].target; - var uid = data.targets[i].uid; - var favicon = data.targets[i].favicon; - $("#syndication-container ul").append('<li><button data-syndicate-to="'+htmlspecialchars(uid ? uid : target)+'" class="btn btn-default btn-block">'+(favicon ? '<img src="'+htmlspecialchars(favicon)+'" width="16" height="16"> ':'')+htmlspecialchars(target)+'</button></li>'); - } - bind_syndication_buttons(); - } else { +<?= partial('partials/syndication-js') ?> - } - console.log(data); - }); -} </script> diff --git a/views/twitter.php b/views/twitter.php new file mode 100644 index 0000000..d9682e8 --- /dev/null +++ b/views/twitter.php @@ -0,0 +1,83 @@ + <div class="narrow"> + <?= partial('partials/header') ?> + + <div style="clear: both;" class="notice-pad"> + <div class="alert alert-success hidden" id="test_success"><strong>Success! </strong><a href="" id="post_href">View your post</a></div> + <div class="alert alert-danger hidden" id="test_error"><strong>Something went wrong!</strong><br>Your Micropub endpoint indicated that something went wrong creating the post.</div> + </div> + + <form role="form" style="margin-top: 20px;" id="note_form"> + + <div class="form-group"> + <label for="tweet_url">Tweet to Import</label> + <input type="text" id="tweet_url" value="<?= $this->tweet_url ?>" class="form-control"> + </div> + + + <div style="float: right; margin-top: 6px;"> + <button class="btn btn-success" id="btn_post">Import</button> + </div> + + <div style="float: right; margin-top: 6px; margin-right: 6px;"> + <button class="btn btn-default" id="btn_preview">Preview</button> + </div> + + </form> + + <div style="clear: both;"></div> + + <div id="preview_data" class="hidden"> + <pre></pre> + </div> + + </div> + +<script> +$(function(){ + + $("#btn_preview").click(function(e){ + + $("#btn_preview").addClass("loading disabled"); + + $.post("/twitter/preview", { + tweet_url: $("#tweet_url").val(), + }, function(response){ + $("#preview_data pre").text(response.json); + $("#preview_data").removeClass("hidden"); + $("#btn_preview").removeClass("loading disabled"); + }); + + return false; + }); + + $("#btn_post").click(function(){ + $("#btn_post").addClass("loading disabled"); + + $.post("/twitter", { + tweet_url: $("#tweet_url").val(), + }, function(response){ + + if(response.location != false) { + + $("#test_success").removeClass('hidden'); + $("#test_error").addClass('hidden'); + $("#post_href").attr("href", response.location); + $("#note_form").addClass('hidden'); + + window.location = response.location; + } else { + $("#test_success").addClass('hidden'); + $("#test_error").removeClass('hidden'); + if(response.error_details) { + $("#test_error").text(response.error_details); + } + $("#btn_post").removeClass("loading disabled"); + } + + }); + return false; + }); + +}); + +</script> |