Browse Source

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
pull/64/head
Aaron Parecki 7 years ago
parent
commit
4aa06023f0
No known key found for this signature in database GPG Key ID: 276C2817346D6056
8 changed files with 397 additions and 123 deletions
  1. +3
    -2
      composer.json
  2. +101
    -59
      composer.lock
  3. +12
    -8
      controllers/auth.php
  4. +69
    -2
      controllers/controllers.php
  5. +43
    -0
      lib/helpers.php
  6. +28
    -1
      public/css/style.css
  7. +117
    -47
      views/new-post.php
  8. +24
    -4
      views/settings.php

+ 3
- 2
composer.json View File

@ -9,9 +9,10 @@
"indieauth/client": ">=0.1.11", "indieauth/client": ">=0.1.11",
"mpratt/relativetime": ">=1.0", "mpratt/relativetime": ">=1.0",
"firebase/php-jwt": "2.*", "firebase/php-jwt": "2.*",
"ruudk/twitter-oauth": "dev-master",
"abraham/twitteroauth": "*",
"andreyco/instagram": "3.*", "andreyco/instagram": "3.*",
"p3k/multipart": "*"
"p3k/multipart": "*",
"tantek/cassis": "*"
}, },
"autoload": { "autoload": {
"files": [ "files": [

+ 101
- 59
composer.lock View File

@ -4,20 +4,75 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "66741248756ed56d19ea2afd34809fe2",
"hash": "4756e7ef0035b8f768f07d252adbdc17",
"content-hash": "f4709cc6bd166e3759fbedbfbaa7752e",
"packages": [ "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", "name": "andreyco/instagram",
"version": "v3.2",
"version": "3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Andreyco/Instagram-for-PHP.git", "url": "https://github.com/Andreyco/Instagram-for-PHP.git",
"reference": "726e724c51301410873d9bae9c659a0597ca47e4"
"reference": "8c1b98f601a68142095461c0b8a9498375145e0d"
}, },
"dist": { "dist": {
"type": "zip", "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": "" "shasum": ""
}, },
"require": { "require": {
@ -42,12 +97,12 @@
} }
], ],
"description": "An easy-to-use PHP Class for accessing Instagram's API.", "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": [ "keywords": [
"api", "api",
"instagram" "instagram"
], ],
"time": "2014-07-14 19:53:19"
"time": "2016-07-17 23:42:10"
}, },
{ {
"name": "barnabywalters/mf-cleaner", "name": "barnabywalters/mf-cleaner",
@ -135,16 +190,16 @@
}, },
{ {
"name": "indieauth/client", "name": "indieauth/client",
"version": "0.1.11",
"version": "0.1.13",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/indieweb/indieauth-client-php.git", "url": "https://github.com/indieweb/indieauth-client-php.git",
"reference": "6504ed0d4714084e9955f639d6e5cf4e976f9038"
"reference": "d438bb03db15b4ccc6c63228be16de7870b6ab99"
}, },
"dist": { "dist": {
"type": "zip", "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": "" "shasum": ""
}, },
"require": { "require": {
@ -170,20 +225,20 @@
} }
], ],
"description": "IndieAuth Client Library", "description": "IndieAuth Client Library",
"time": "2015-08-30 22:29:40"
"time": "2016-02-08 23:56:31"
}, },
{ {
"name": "indieweb/date-formatter", "name": "indieweb/date-formatter",
"version": "0.1.5",
"version": "0.1.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/indieweb/date-formatter-php.git", "url": "https://github.com/indieweb/date-formatter-php.git",
"reference": "f0dc028ba53da4da2718d2a263300396b1c14203"
"reference": "9c12e0fda95f4b3119fcaf271d141305870c4350"
}, },
"dist": { "dist": {
"type": "zip", "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": "" "shasum": ""
}, },
"require": { "require": {
@ -213,7 +268,7 @@
"microformats", "microformats",
"microformats2" "microformats2"
], ],
"time": "2013-10-27 23:46:11"
"time": "2015-10-28 00:32:39"
}, },
{ {
"name": "indieweb/link-rel-parser", "name": "indieweb/link-rel-parser",
@ -413,16 +468,16 @@
}, },
{ {
"name": "mpratt/relativetime", "name": "mpratt/relativetime",
"version": "1.5.1",
"version": "1.5.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/mpratt/RelativeTime.git", "url": "https://github.com/mpratt/RelativeTime.git",
"reference": "219e6568fa3e7b181244f93be493fbab4c89c056"
"reference": "3dc1efd96c8edbd0fe9e5cdb423ca31428b9dbb7"
}, },
"dist": { "dist": {
"type": "zip", "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": "" "shasum": ""
}, },
"require": { "require": {
@ -457,7 +512,7 @@
"time", "time",
"time-ago" "time-ago"
], ],
"time": "2015-05-28 14:13:23"
"time": "2015-12-24 12:43:04"
}, },
{ {
"name": "p3k/multipart", "name": "p3k/multipart",
@ -495,41 +550,6 @@
"description": "Multipart Encoding Library", "description": "Multipart Encoding Library",
"time": "2015-07-16 19:28:02" "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", "name": "saltybeagle/savant3",
"version": "dev-master", "version": "dev-master",
@ -607,14 +627,36 @@
"router" "router"
], ],
"time": "2012-12-13 02:15:50" "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": [], "packages-dev": [],
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": { "stability-flags": {
"saltybeagle/savant3": 20,
"ruudk/twitter-oauth": 20
"saltybeagle/savant3": 20
}, },
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,

+ 12
- 8
controllers/auth.php View File

@ -1,4 +1,5 @@
<?php <?php
use Abraham\TwitterOAuth\TwitterOAuth;
function buildRedirectURI() { function buildRedirectURI() {
return Config::$base_url . 'auth/callback'; return Config::$base_url . 'auth/callback';
@ -260,9 +261,11 @@ $app->post('/auth/twitter', function() use($app) {
}); });
function getTwitterLoginURL(&$twitter) { 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; $_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) { $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 // If there is an existing Twitter token, check if it is valid
// Otherwise, generate a Twitter login link // Otherwise, generate a Twitter login link
$twitter_login_url = false; $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)) { 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); $twitter_login_url = getTwitterLoginURL($twitter);
} else { } else {
$twitter = new TwitterOAuth(Config::$twitterClientID, Config::$twitterClientSecret,
$user->twitter_access_token, $user->twitter_token_secret);
if($user->twitter_access_token) { 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()['Content-type'] = 'application/json';
$app->response()->body(json_encode(array( $app->response()->body(json_encode(array(
'result' => 'ok' 'result' => 'ok'
@ -312,9 +316,9 @@ $app->get('/auth/twitter/callback', function() use($app) {
if($user=require_login($app)) { if($user=require_login($app)) {
$params = $app->request()->params(); $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']); $_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_access_token = $credentials['oauth_token'];
$user->twitter_token_secret = $credentials['oauth_token_secret']; $user->twitter_token_secret = $credentials['oauth_token_secret'];

+ 69
- 2
controllers/controllers.php View File

@ -1,4 +1,5 @@
<?php <?php
use Abraham\TwitterOAuth\TwitterOAuth;
function require_login(&$app, $redirect=true) { function require_login(&$app, $redirect=true) {
$params = $app->request()->params(); $params = $app->request()->params();
@ -336,7 +337,7 @@ function create_favorite(&$user, $url) {
// POSSE favorites to Twitter // POSSE favorites to Twitter
if($user->twitter_access_token && preg_match('/https?:\/\/(?:www\.)?twitter\.com\/[^\/]+\/status(?:es)?\/(\d+)/', $url, $match)) { if($user->twitter_access_token && preg_match('/https?:\/\/(?:www\.)?twitter\.com\/[^\/]+\/status(?:es)?\/(\d+)/', $url, $match)) {
$tweet_id = $match[1]; $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); $user->twitter_access_token, $user->twitter_token_secret);
$result = $twitter->post('favorites/create', array( $result = $twitter->post('favorites/create', array(
'id' => $tweet_id '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)) { if($user->twitter_access_token && preg_match('/https?:\/\/(?:www\.)?twitter\.com\/[^\/]+\/status(?:es)?\/(\d+)/', $url, $match)) {
$tweet_id = $match[1]; $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); $user->twitter_access_token, $user->twitter_token_secret);
$result = $twitter->post('statuses/retweet/'.$tweet_id); $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) { $app->get('/micropub/syndications', function() use($app) {
if($user=require_login($app)) { if($user=require_login($app)) {
$data = get_micropub_config($user, ['q'=>'syndicate-to']); $data = get_micropub_config($user, ['q'=>'syndicate-to']);

+ 43
- 0
lib/helpers.php View File

@ -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;
}

+ 28
- 1
public/css/style.css View File

@ -200,4 +200,31 @@ body {
.notice-pad { .notice-pad {
margin-top: 20px; margin-top: 20px;
}
}
.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);
}
}

+ 117
- 47
views/new-post.php View File

@ -3,29 +3,45 @@
<form role="form" style="margin-top: 20px;" id="note_form"> <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>
<div class="form-group"> <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>
<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"> <input type="text" id="note_category" value="" class="form-control" placeholder="e.g. web, personal">
</div> </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"> <input type="text" id="note_slug" value="" class="form-control">
</div> </div>
<div class="form-group"> <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/*"> <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:switchToManualPhotoURL();" id="note_manual_photo">enter photo url</a>
<a href="javascript:addPhotoURL();" class="hidden" id="add_photo">add photo</a> <a href="javascript:addPhotoURL();" class="hidden" id="add_photo">add photo</a>
@ -39,7 +55,7 @@
</div> </div>
<div class="form-group"> <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"> <div id="syndication-container">
<?php <?php
if($this->syndication_targets) { if($this->syndication_targets) {
@ -62,7 +78,7 @@
</div> </div>
<div class="form-group"> <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=""> <input type="checkbox" id="note_location_chk" value="">
<img src="/images/spinner.gif" id="note_location_loading" style="display: none;"> <img src="/images/spinner.gif" id="note_location_loading" style="display: none;">
@ -93,36 +109,6 @@
<?php endif; ?> <?php endif; ?>
<pre id="test_response" class="<?= $this->test_response ? '' : 'hidden' ?>" style="width: 100%; min-height: 240px;"><?= htmlspecialchars($this->test_response) ?></pre> <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> <hr>
<div style="text-align: right;"> <div style="text-align: right;">
<a href="/add-to-home?start">Add to Home Screen</a> <a href="/add-to-home?start">Add to Home Screen</a>
@ -131,6 +117,10 @@
<style type="text/css"> <style type="text/css">
#reply {
margin-bottom: 1em;
}
#note_content_remaining { #note_content_remaining {
float: right; float: right;
font-size: 0.8em; font-size: 0.8em;
@ -142,6 +132,33 @@
.pcheck200,.pcheck208 { color: #59cb3a; } /* exactly fits 140 chars, both with or without RT */ .pcheck200,.pcheck208 { color: #59cb3a; } /* exactly fits 140 chars, both with or without RT */
.pcheck413 { color: #a73b3b; } /* over max tweet length */ .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> </style>
<script> <script>
@ -170,7 +187,9 @@ function restoreNoteState() {
if(note.photo) { if(note.photo) {
replacePhotoWithPhotoURL(note.photo); replacePhotoWithPhotoURL(note.photo);
} }
console.log(note.syndications)
if(note.inReplyTo) {
expandReplySection();
}
$("#syndication-container button").each(function(i,btn){ $("#syndication-container button").each(function(i,btn){
if($(btn).data('syndicate-to') in note.syndications) { if($(btn).data('syndicate-to') in note.syndications) {
$(btn).addClass('btn-info'); $(btn).addClass('btn-info');
@ -208,6 +227,11 @@ function addPhotoURL() {
} }
} }
function expandReplySection() {
$("#expand-reply").click();
$("#note_in_reply_to").change();
}
$(function(){ $(function(){
var userHasSetCategory = false; var userHasSetCategory = false;
@ -218,6 +242,12 @@ $(function(){
saveNoteState(); saveNoteState();
}) })
$("#expand-reply").click(function(){
$('.reply-section').removeClass('hidden');
$(this).addClass('hidden');
return false;
});
// Preview the photo when one is chosen // Preview the photo when one is chosen
$("#photo_preview_container").addClass("hidden"); $("#photo_preview_container").addClass("hidden");
$("#note_photo").on("change", function(e){ $("#note_photo").on("change", function(e){
@ -279,9 +309,43 @@ $(function(){
}); });
$("#note_in_reply_to").on('change', 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(){ $("#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(){ $("#btn_post").click(function(){
// Collect all the syndication buttons that are pressed // Collect all the syndication buttons that are pressed

+ 24
- 4
views/settings.php View File

@ -2,13 +2,33 @@
<?= partial('partials/header') ?> <?= partial('partials/header') ?>
<h2>Signed In As</h2> <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> <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"> <input type="button" id="twitter-button" value="Checking" class="btn">
</div> </div>

Loading…
Cancel
Save