diff options
author | Aaron Parecki <aaron@parecki.com> | 2016-12-19 10:39:23 -0800 |
---|---|---|
committer | Aaron Parecki <aaron@parecki.com> | 2016-12-19 10:39:23 -0800 |
commit | 4aa06023f0c25a10d5eaeafaeb30034e0a4f2e95 (patch) | |
tree | e4a694fad5254166d01934aed9f344fc2903a2df | |
parent | 53964f2622828bc5b67546dbc24bb455e4d165cb (diff) |
clean up note UI, show reply context
* shows reply context of the URL you're replying to
* autocomplete nicknames from the post when replying
* moved debug info to the settings screen to clean up the UI
-rw-r--r-- | composer.json | 5 | ||||
-rw-r--r-- | composer.lock | 160 | ||||
-rw-r--r-- | controllers/auth.php | 20 | ||||
-rw-r--r-- | controllers/controllers.php | 71 | ||||
-rw-r--r-- | lib/helpers.php | 43 | ||||
-rw-r--r-- | public/css/style.css | 29 | ||||
-rw-r--r-- | views/new-post.php | 164 | ||||
-rw-r--r-- | views/settings.php | 28 |
8 files changed, 397 insertions, 123 deletions
diff --git a/composer.json b/composer.json index 1a61c65..fc6ad33 100644 --- a/composer.json +++ b/composer.json @@ -9,9 +9,10 @@ "indieauth/client": ">=0.1.11", "mpratt/relativetime": ">=1.0", "firebase/php-jwt": "2.*", - "ruudk/twitter-oauth": "dev-master", + "abraham/twitteroauth": "*", "andreyco/instagram": "3.*", - "p3k/multipart": "*" + "p3k/multipart": "*", + "tantek/cassis": "*" }, "autoload": { "files": [ diff --git a/composer.lock b/composer.lock index fef94a8..169e3ff 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,75 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "66741248756ed56d19ea2afd34809fe2", + "hash": "4756e7ef0035b8f768f07d252adbdc17", + "content-hash": "f4709cc6bd166e3759fbedbfbaa7752e", "packages": [ { + "name": "abraham/twitteroauth", + "version": "0.7.2", + "source": { + "type": "git", + "url": "https://github.com/abraham/twitteroauth.git", + "reference": "119d5a83478a2d21c09cd27980ab67eba11c8fe1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/abraham/twitteroauth/zipball/119d5a83478a2d21c09cd27980ab67eba11c8fe1", + "reference": "119d5a83478a2d21c09cd27980ab67eba11c8fe1", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpmd/phpmd": "~2.4", + "phpunit/phpunit": "~5.6", + "squizlabs/php_codesniffer": "~2.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Abraham\\TwitterOAuth\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Abraham Williams", + "email": "abraham@abrah.am", + "homepage": "https://abrah.am", + "role": "Developer" + } + ], + "description": "The most popular PHP library for use with the Twitter OAuth REST API.", + "homepage": "https://twitteroauth.com", + "keywords": [ + "Twitter API", + "Twitter oAuth", + "api", + "oauth", + "rest", + "social", + "twitter" + ], + "time": "2016-12-12 17:42:13" + }, + { "name": "andreyco/instagram", - "version": "v3.2", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/Andreyco/Instagram-for-PHP.git", - "reference": "726e724c51301410873d9bae9c659a0597ca47e4" + "reference": "8c1b98f601a68142095461c0b8a9498375145e0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Andreyco/Instagram-for-PHP/zipball/726e724c51301410873d9bae9c659a0597ca47e4", - "reference": "726e724c51301410873d9bae9c659a0597ca47e4", + "url": "https://api.github.com/repos/Andreyco/Instagram-for-PHP/zipball/8c1b98f601a68142095461c0b8a9498375145e0d", + "reference": "8c1b98f601a68142095461c0b8a9498375145e0d", "shasum": "" }, "require": { @@ -42,12 +97,12 @@ } ], "description": "An easy-to-use PHP Class for accessing Instagram's API.", - "homepage": "https://github.com/Andreyco/Instagram", + "homepage": "https://github.com/Andreyco/Instagram-for-PHP", "keywords": [ "api", "instagram" ], - "time": "2014-07-14 19:53:19" + "time": "2016-07-17 23:42:10" }, { "name": "barnabywalters/mf-cleaner", @@ -135,16 +190,16 @@ }, { "name": "indieauth/client", - "version": "0.1.11", + "version": "0.1.13", "source": { "type": "git", "url": "https://github.com/indieweb/indieauth-client-php.git", - "reference": "6504ed0d4714084e9955f639d6e5cf4e976f9038" + "reference": "d438bb03db15b4ccc6c63228be16de7870b6ab99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/6504ed0d4714084e9955f639d6e5cf4e976f9038", - "reference": "6504ed0d4714084e9955f639d6e5cf4e976f9038", + "url": "https://api.github.com/repos/indieweb/indieauth-client-php/zipball/d438bb03db15b4ccc6c63228be16de7870b6ab99", + "reference": "d438bb03db15b4ccc6c63228be16de7870b6ab99", "shasum": "" }, "require": { @@ -170,20 +225,20 @@ } ], "description": "IndieAuth Client Library", - "time": "2015-08-30 22:29:40" + "time": "2016-02-08 23:56:31" }, { "name": "indieweb/date-formatter", - "version": "0.1.5", + "version": "0.1.6", "source": { "type": "git", "url": "https://github.com/indieweb/date-formatter-php.git", - "reference": "f0dc028ba53da4da2718d2a263300396b1c14203" + "reference": "9c12e0fda95f4b3119fcaf271d141305870c4350" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/indieweb/date-formatter-php/zipball/f0dc028ba53da4da2718d2a263300396b1c14203", - "reference": "f0dc028ba53da4da2718d2a263300396b1c14203", + "url": "https://api.github.com/repos/indieweb/date-formatter-php/zipball/9c12e0fda95f4b3119fcaf271d141305870c4350", + "reference": "9c12e0fda95f4b3119fcaf271d141305870c4350", "shasum": "" }, "require": { @@ -213,7 +268,7 @@ "microformats", "microformats2" ], - "time": "2013-10-27 23:46:11" + "time": "2015-10-28 00:32:39" }, { "name": "indieweb/link-rel-parser", @@ -413,16 +468,16 @@ }, { "name": "mpratt/relativetime", - "version": "1.5.1", + "version": "1.5.4", "source": { "type": "git", "url": "https://github.com/mpratt/RelativeTime.git", - "reference": "219e6568fa3e7b181244f93be493fbab4c89c056" + "reference": "3dc1efd96c8edbd0fe9e5cdb423ca31428b9dbb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mpratt/RelativeTime/zipball/219e6568fa3e7b181244f93be493fbab4c89c056", - "reference": "219e6568fa3e7b181244f93be493fbab4c89c056", + "url": "https://api.github.com/repos/mpratt/RelativeTime/zipball/3dc1efd96c8edbd0fe9e5cdb423ca31428b9dbb7", + "reference": "3dc1efd96c8edbd0fe9e5cdb423ca31428b9dbb7", "shasum": "" }, "require": { @@ -457,7 +512,7 @@ "time", "time-ago" ], - "time": "2015-05-28 14:13:23" + "time": "2015-12-24 12:43:04" }, { "name": "p3k/multipart", @@ -496,41 +551,6 @@ "time": "2015-07-16 19:28:02" }, { - "name": "ruudk/twitter-oauth", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/ruudk/twitteroauth.git", - "reference": "7f5a94eaa1572ddbc7f0a32ba3b865b8ac23712a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ruudk/twitteroauth/zipball/7f5a94eaa1572ddbc7f0a32ba3b865b8ac23712a", - "reference": "7f5a94eaa1572ddbc7f0a32ba3b865b8ac23712a", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "authors": [ - { - "name": "Ruud Kamphuis", - "email": "ruud@1plus1media.nl", - "role": "Developer" - } - ], - "description": "PHP 5.3 version of abraham/twitteroauth", - "homepage": "http://github.com/ruudk/twitteroauth", - "time": "2014-06-10 18:17:38" - }, - { "name": "saltybeagle/savant3", "version": "dev-master", "source": { @@ -607,14 +627,36 @@ "router" ], "time": "2012-12-13 02:15:50" + }, + { + "name": "tantek/cassis", + "version": "v0.2.16895", + "source": { + "type": "git", + "url": "https://github.com/tantek/cassis.git", + "reference": "357e30ad12017b4d67cac5f4400e8f371cd2f504" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tantek/cassis/zipball/357e30ad12017b4d67cac5f4400e8f371cd2f504", + "reference": "357e30ad12017b4d67cac5f4400e8f371cd2f504", + "shasum": "" + }, + "type": "library", + "autoload": { + "files": [ + "cassis.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "time": "2016-04-04 15:31:04" } ], "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": { - "saltybeagle/savant3": 20, - "ruudk/twitter-oauth": 20 + "saltybeagle/savant3": 20 }, "prefer-stable": false, "prefer-lowest": false, diff --git a/controllers/auth.php b/controllers/auth.php index fb8b6da..baf5c2f 100644 --- a/controllers/auth.php +++ b/controllers/auth.php @@ -1,4 +1,5 @@ <?php +use Abraham\TwitterOAuth\TwitterOAuth; function buildRedirectURI() { return Config::$base_url . 'auth/callback'; @@ -260,9 +261,11 @@ $app->post('/auth/twitter', function() use($app) { }); function getTwitterLoginURL(&$twitter) { - $request_token = $twitter->getRequestToken(Config::$base_url . 'auth/twitter/callback'); + $request_token = $twitter->oauth('oauth/request_token', [ + 'oauth_callback' => Config::$base_url . 'auth/twitter/callback' + ]); $_SESSION['twitter_auth'] = $request_token; - return $twitter->getAuthorizeURL($request_token['oauth_token']); + return $twitter->url('oauth/authorize', ['oauth_token' => $request_token['oauth_token']]); } $app->get('/auth/twitter', function() use($app) { @@ -272,15 +275,16 @@ $app->get('/auth/twitter', function() use($app) { // If there is an existing Twitter token, check if it is valid // Otherwise, generate a Twitter login link $twitter_login_url = false; - $twitter = new \TwitterOAuth\Api(Config::$twitterClientID, Config::$twitterClientSecret, - $user->twitter_access_token, $user->twitter_token_secret); if(array_key_exists('login', $params)) { - $twitter = new \TwitterOAuth\Api(Config::$twitterClientID, Config::$twitterClientSecret); + $twitter = new TwitterOAuth(Config::$twitterClientID, Config::$twitterClientSecret); $twitter_login_url = getTwitterLoginURL($twitter); } else { + $twitter = new TwitterOAuth(Config::$twitterClientID, Config::$twitterClientSecret, + $user->twitter_access_token, $user->twitter_token_secret); + if($user->twitter_access_token) { - if ($twitter->get('account/verify_credentials')) { + if($twitter->get('account/verify_credentials')) { $app->response()['Content-type'] = 'application/json'; $app->response()->body(json_encode(array( 'result' => 'ok' @@ -312,9 +316,9 @@ $app->get('/auth/twitter/callback', function() use($app) { if($user=require_login($app)) { $params = $app->request()->params(); - $twitter = new \TwitterOAuth\Api(Config::$twitterClientID, Config::$twitterClientSecret, + $twitter = new TwitterOAuth(Config::$twitterClientID, Config::$twitterClientSecret, $_SESSION['twitter_auth']['oauth_token'], $_SESSION['twitter_auth']['oauth_token_secret']); - $credentials = $twitter->getAccessToken($params['oauth_verifier']); + $credentials = $twitter->oauth('oauth/access_token', ['oauth_verifier' => $params['oauth_verifier']]); $user->twitter_access_token = $credentials['oauth_token']; $user->twitter_token_secret = $credentials['oauth_token_secret']; diff --git a/controllers/controllers.php b/controllers/controllers.php index 09133cf..a9bc0ab 100644 --- a/controllers/controllers.php +++ b/controllers/controllers.php @@ -1,4 +1,5 @@ <?php +use Abraham\TwitterOAuth\TwitterOAuth; function require_login(&$app, $redirect=true) { $params = $app->request()->params(); @@ -336,7 +337,7 @@ function create_favorite(&$user, $url) { // POSSE favorites to Twitter if($user->twitter_access_token && preg_match('/https?:\/\/(?:www\.)?twitter\.com\/[^\/]+\/status(?:es)?\/(\d+)/', $url, $match)) { $tweet_id = $match[1]; - $twitter = new \TwitterOAuth\Api(Config::$twitterClientID, Config::$twitterClientSecret, + $twitter = new TwitterOAuth(Config::$twitterClientID, Config::$twitterClientSecret, $user->twitter_access_token, $user->twitter_token_secret); $result = $twitter->post('favorites/create', array( 'id' => $tweet_id @@ -356,7 +357,7 @@ function create_repost(&$user, $url) { if($user->twitter_access_token && preg_match('/https?:\/\/(?:www\.)?twitter\.com\/[^\/]+\/status(?:es)?\/(\d+)/', $url, $match)) { $tweet_id = $match[1]; - $twitter = new \TwitterOAuth\Api(Config::$twitterClientID, Config::$twitterClientSecret, + $twitter = new TwitterOAuth(Config::$twitterClientID, Config::$twitterClientSecret, $user->twitter_access_token, $user->twitter_token_secret); $result = $twitter->post('statuses/retweet/'.$tweet_id); } @@ -392,6 +393,72 @@ $app->post('/repost', function() use($app) { } }); +$app->get('/reply/preview', function() use($app) { + if($user=require_login($app)) { + $params = $app->request()->params(); + + $reply_url = trim($params['url']); + + if(preg_match('/twtr\.io\/([0-9a-z]+)/i', $reply_url, $match)) { + $twtr = 'https://twitter.com/_/status/' . sxg_to_num($match[1]); + $ch = curl_init($twtr); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_exec($ch); + $expanded_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); + if($expanded_url) $reply_url = $expanded_url; + } + + $entry = false; + // Convert Tweets to h-entry + if(preg_match('/twitter\.com\/(?:[^\/]+)\/statuse?s?\/(.+)/', $reply_url, $match)) { + $tweet_id = $match[1]; + if($user->twitter_access_token) { + $twitter = new TwitterOAuth(Config::$twitterClientID, Config::$twitterClientSecret, + $user->twitter_access_token, $user->twitter_token_secret); + } else { + $twitter = new TwitterOAuth(Config::$twitterClientID, Config::$twitterClientSecret); + } + $tweet = $twitter->get('statuses/show/'.$tweet_id); + $entry = tweet_to_h_entry($tweet); + } else { + // Pass to X-Ray to see if it can expand the entry + $ch = curl_init('https://xray.p3k.io/parse?url='.urlencode($reply_url)); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $response = curl_exec($ch); + $data = @json_decode($response, true); + if($data && $data['data']['type'] == 'entry') { + $entry = $data['data']; + // Create a nickname based on the author URL + if($entry['author']['url']) { + $entry['author']['nickname'] = display_url($entry['author']['url']); + } + } + } + + $mentions = []; + if($entry) { + // Find all @-names in the post, as well as the author name + $mentions[] = $entry['author']['nickname']; + + if(preg_match_all('/(^|(?<=[\s\/]))@([a-z0-9_]+([a-z0-9_\.]*)?)/i', $entry['content']['text'], $matches)) { + foreach($matches[0] as $nick) { + if(trim($nick,'@') != $user->twitter_username && trim($nick,'@') != display_url($user->url)) + $mentions[] = trim($nick,'@'); + } + } + + } + + $app->response()['Content-type'] = 'application/json'; + $app->response()->body(json_encode([ + 'canonical_reply_url' => $reply_url, + 'entry' => $entry, + 'mentions' => $mentions + ])); + } +}); + $app->get('/micropub/syndications', function() use($app) { if($user=require_login($app)) { $data = get_micropub_config($user, ['q'=>'syndicate-to']); diff --git a/lib/helpers.php b/lib/helpers.php index 3a71d90..8948f92 100644 --- a/lib/helpers.php +++ b/lib/helpers.php @@ -396,3 +396,46 @@ function correct_photo_rotation($filename) { } } +function tweet_to_h_entry($tweet) { + // Converts to XRay's h-entry format + + $entry = [ + 'type' => 'entry', + 'url' => 'https://twitter.com/'.$tweet->user->screen_name.'/status/'.$tweet->id_str, + ]; + + $published = strtotime($tweet->created_at); + $entry['published'] = date('c', $published); + + $entry['content'] = [ + 'text' => $tweet->text + ]; + + if($tweet->entities->urls) { + foreach($tweet->entities->urls as $url) { + $entry['content']['text'] = str_replace($url->url, $url->expanded_url, $entry['content']['text']); + } + } + + $entry['author'] = [ + 'type' => 'card', + 'url' => 'https://twitter.com/'.$tweet->user->screen_name, + 'name' => $tweet->user->name, + 'nickname' => $tweet->user->screen_name, + 'photo' => $tweet->user->profile_image_url_https + ]; + + if($tweet->user->url) { + $entry['author']['url'] = $tweet->user->entities->url->urls[0]->expanded_url; + } + + if($tweet->entities->hashtags) { + $entry['category'] = []; + foreach($tweet->entities->hashtags as $tag) { + $entry['category'][] = $tag->text; + } + } + + return $entry; +} + diff --git a/public/css/style.css b/public/css/style.css index 5e6556c..7984fe5 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -200,4 +200,31 @@ body { .notice-pad { margin-top: 20px; - }
\ No newline at end of file + } + + + +.glyphicon-spin { + -webkit-animation: spin 1000ms infinite linear; + animation: spin 1000ms infinite linear; +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} diff --git a/views/new-post.php b/views/new-post.php index 21571ec..68460d0 100644 --- a/views/new-post.php +++ b/views/new-post.php @@ -3,29 +3,45 @@ <form role="form" style="margin-top: 20px;" id="note_form"> - <div class="form-group"> - <div id="note_content_remaining" class="pcheck206"><img src="/images/twitter.ico"> <span>140</span></div> - <label for="note_content"><code>content</code></label> - <textarea id="note_content" value="" class="form-control" style="height: 4em;"></textarea> + <div id="reply"> + <div class="reply-section hidden"> + <div class="form-group has-feedback"> + <label for="note_in_reply_to">Reply To (a URL you are replying to)</label> + <input type="text" id="note_in_reply_to" value="<?= $this->in_reply_to ?>" class="form-control"> + <span class="loading hidden glyphicon glyphicon-refresh glyphicon-spin form-control-feedback"></span> + </div> + <div class="reply-context hidden"> + <div> + <img src="" width="48" class="author-img"> + </div> + <div> + <img src="" class="post-img hidden"> + <div class="author"><span class="name"></span> <span class="url"></span></div> + <span class="content"></span> + </div> + </div> + </div> + <a href="" id="expand-reply" class="btn btn-xs btn-info">Reply</a> </div> <div class="form-group"> - <label for="note_in_reply_to"><code>in-reply-to</code> (a URL you are replying to)</label> - <input type="text" id="note_in_reply_to" value="<?= $this->in_reply_to ?>" class="form-control"> + <div id="note_content_remaining" class="pcheck206"><img src="/images/twitter.ico"> <span>140</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"> - <label for="note_category"><code>category</code> (comma-separated list of tags, will be posted as an array)</label> + <div class="form-group" id="form_tags"> + <label for="note_category">Tags (comma-separated list)</label> <input type="text" id="note_category" value="" class="form-control" placeholder="e.g. web, personal"> </div> - <div class="form-group"> - <label for="note_slug"><code>slug</code></label> + <div class="form-group" id="form_slug"> + <label for="note_slug">Slug</label> <input type="text" id="note_slug" value="" class="form-control"> </div> <div class="form-group"> - <label for="note_photo"><code>photo</code></label> + <label for="note_photo">Photo</label> <input type="file" name="note_photo" id="note_photo" accept="image/*"> <a href="javascript:switchToManualPhotoURL();" id="note_manual_photo">enter photo url</a> <a href="javascript:addPhotoURL();" class="hidden" id="add_photo">add photo</a> @@ -39,7 +55,7 @@ </div> <div class="form-group"> - <label for="note_syndicate-to"><code>syndicate-to</code> <a href="javascript:reload_syndications()">(refresh)</a></label> + <label for="note_syndicate-to">Syndicate <a href="javascript:reload_syndications()">(refresh list)</a></label> <div id="syndication-container"> <?php if($this->syndication_targets) { @@ -62,7 +78,7 @@ </div> <div class="form-group"> - <label for="note_location"><code>location</code></label> + <label for="note_location">Location</label> <input type="checkbox" id="note_location_chk" value=""> <img src="/images/spinner.gif" id="note_location_loading" style="display: none;"> @@ -93,36 +109,6 @@ <?php endif; ?> <pre id="test_response" class="<?= $this->test_response ? '' : 'hidden' ?>" style="width: 100%; min-height: 240px;"><?= htmlspecialchars($this->test_response) ?></pre> - - <div class="callout"> - <p>Clicking "Post" will post this note to your Micropub endpoint. Below is some information about the request that will be made.</p> - - <table class="table table-condensed"> - <tr> - <td>me</td> - <td><code><?= session('me') ?></code> (should be your URL)</td> - </tr> - <tr> - <td>scope</td> - <td><code><?= $this->micropub_scope ?></code> (should be a space-separated list of permissions including "post")</td> - </tr> - <tr> - <td>micropub endpoint</td> - <td><code><?= $this->micropub_endpoint ?></code> (should be a URL)</td> - </tr> - <?php if($this->media_endpoint): ?> - <tr> - <td>media endpoint</td> - <td><code><?= $this->media_endpoint ?></code> (should be a URL)</td> - </tr> - <?php endif; ?> - <tr> - <td>access token</td> - <td>String of length <b><?= strlen($this->micropub_access_token) ?></b><?= (strlen($this->micropub_access_token) > 0) ? (', ending in <code>' . substr($this->micropub_access_token, -7) . '</code>') : '' ?> (should be greater than length 0)</td> - </tr> - </table> - </div> - <hr> <div style="text-align: right;"> <a href="/add-to-home?start">Add to Home Screen</a> @@ -131,6 +117,10 @@ <style type="text/css"> +#reply { + margin-bottom: 1em; +} + #note_content_remaining { float: right; font-size: 0.8em; @@ -142,6 +132,33 @@ .pcheck200,.pcheck208 { color: #59cb3a; } /* exactly fits 140 chars, both with or without RT */ .pcheck413 { color: #a73b3b; } /* over max tweet length */ +.reply-context { + display: flex; + flex-direction: row; + padding: 4px; + margin: 0 3em; + border: 1px #ccc solid; + border-radius: 4px; + background: #f4f4f4; +} +.reply-context img.author-img { + border-radius: 4px; + width: 48px; + margin-right: 4px; +} +.reply-context .author { + color: #777; + font-weight: bold; + font-size: 0.9em; +} +.reply-context .author .url { + color: #aaa; +} +.reply-context img.post-img { + float: right; + width: 200px; +} + </style> <script> @@ -170,7 +187,9 @@ function restoreNoteState() { if(note.photo) { replacePhotoWithPhotoURL(note.photo); } - console.log(note.syndications) + if(note.inReplyTo) { + expandReplySection(); + } $("#syndication-container button").each(function(i,btn){ if($(btn).data('syndicate-to') in note.syndications) { $(btn).addClass('btn-info'); @@ -208,6 +227,11 @@ function addPhotoURL() { } } +function expandReplySection() { + $("#expand-reply").click(); + $("#note_in_reply_to").change(); +} + $(function(){ var userHasSetCategory = false; @@ -218,6 +242,12 @@ $(function(){ saveNoteState(); }) + $("#expand-reply").click(function(){ + $('.reply-section').removeClass('hidden'); + $(this).addClass('hidden'); + return false; + }); + // Preview the photo when one is chosen $("#photo_preview_container").addClass("hidden"); $("#note_photo").on("change", function(e){ @@ -279,9 +309,43 @@ $(function(){ }); $("#note_in_reply_to").on('change', function(){ - if(match=$("#note_in_reply_to").val().match(/twitter\.com\/([^\/]+)\/status/)) { - $("#note_content").val( "@"+match[1]+" "+$("#note_content").val() ); - } + var reply_to = $("#note_in_reply_to").val(); + $(".reply-section .loading").removeClass("hidden"); + $.get("/reply/preview", {url:reply_to}, function(data){ + + if(data.canonical_reply_url != reply_to) { + $("#note_in_reply_to").val(data.canonical_reply_url); + } + var category = csv_to_array($("#note_category").val()); + for(var i in data.entry.category) { + if($.inArray(data.entry.category[i], category) == -1) { + category.push(data.entry.category[i]); + } + } + $("#note_category").val(category.join(", ")); + + if($("#note_content").val() == "" && data.mentions) { + var mentions = ''; + for(var i in data.mentions) { + mentions += '@'+data.mentions[i]+' '; + } + console.log(mentions); + $("#note_content").val(mentions); + } + + $(".reply-context .content").text(data.entry.content.text); + $(".reply-context .name").text(data.entry.author.name); + $(".reply-context .url").text(data.entry.author.url); + $(".reply-context img.author-img").attr('src', data.entry.author.photo); + if(data.entry.photo) { + $(".reply-context img.post-img").attr('src', data.entry.photo[0]).removeClass('hidden'); + } else { + $(".reply-context img.post-img").addClass('hidden'); + } + + $(".reply-section .loading").addClass("hidden"); + $(".reply-context").removeClass("hidden"); + }); }); $("#note_category").on('keydown keyup', function(){ @@ -293,6 +357,12 @@ $(function(){ } }); + // When the reply URL is in the query string, or loads from localstorage, make sure + // to run the event handlers to expand the reply section + if($("#note_in_reply_to").val() != "") { + expandReplySection(); + } + $("#btn_post").click(function(){ // Collect all the syndication buttons that are pressed diff --git a/views/settings.php b/views/settings.php index 46df0bf..5acc7dd 100644 --- a/views/settings.php +++ b/views/settings.php @@ -2,13 +2,33 @@ <?= partial('partials/header') ?> <h2>Signed In As</h2> - <code><?= session('me') ?></code> - <h3>Access Token</h3> - <input type="text" class="form-control" readonly="readonly" value="<?= $this->user->micropub_access_token ?>"> + <table class="table table-condensed"> + <tr> + <td>me</td> + <td><code><?= $this->user->url; ?></code> (should be your URL)</td> + </tr> + <tr> + <td>scope</td> + <td><code><?= $this->user->micropub_scope ?></code> (should be a space-separated list of permissions including "create")</td> + </tr> + <tr> + <td>micropub endpoint</td> + <td><code><?= $this->user->micropub_endpoint ?></code> (should be a URL)</td> + </tr> + <tr> + <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> + </tr> + <tr> + <td width="140">access token</td> + <td><code style="word-break: break-word; white-space: pre-wrap;"><?= $this->user->micropub_access_token ?></code></td> + </tr> + </table> + <h3>Twitter</h3> - <p>Connecting a Twitter account will automatically "favorite" tweets on Twitter when you favorite 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"> </div> |