├── LICENSE ├── QuitimPlugin.php ├── README.md ├── actions ├── apinewnotifications.php ├── quitimall.php ├── quitimfavorited.php ├── quitimfollowers.php ├── quitimfollowing.php ├── quitimlikers.php ├── quitimnewnotice.php ├── quitimnotifications.php ├── quitimpopular.php ├── quitimshownotice.php ├── quitimsubscribe.php ├── quitimunsubscribe.php └── quitimuserstream.php ├── classes ├── ChronologicalInboxStream.php ├── NotificationStream.php ├── QuitimFooter.php ├── QuitimFullThreadedNoticeList.php ├── QuitimNoticeListItem.php ├── QuitimNotification.php ├── QuitimProfileListItem.php ├── QuitimSubscribeForm.php ├── QuitimThreadedNoticeList.php └── QuitimUnsubscribeForm.php ├── css └── quitim.css ├── fonts └── font-awesome-4.3.0 │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── img ├── cc-by-nc-80x15.png ├── ekan4.jpg ├── quitim-sprite-preview.ai ├── quitim-sprite.ai ├── refresh.ai ├── refresh.png ├── smallogo.png ├── sprite-preview.jpg └── sprite.png ├── js ├── bowser.min.js ├── filtrr2-0.6.3.min.js ├── jpeg_encoder_basic.js ├── jquery.mobile-events.min.js ├── jquery.vintage.min.js ├── load-image.min.js ├── masonry.pkgd.min.js └── quitim.js └── plugins └── Bourgeois ├── BourgeoisPlugin.php ├── EVENTS.txt ├── actions ├── bourgeois.php ├── bourgeoisrss.php └── showbourgeois.php ├── classes └── Bourgeois.php ├── forms ├── markbourgeois.php └── unmarkbourgeois.php ├── lib ├── allbourgeoisnoticestream.php ├── bourgeoisnoticestream.php ├── threadednoticelistbourgeoisitem.php └── threadednoticelistinlinebourgeoisitem.php └── locale └── sv └── LC_MESSAGES └── Bourgeois.po /README.md: -------------------------------------------------------------------------------- 1 | Quitim 2 | ========================================== 3 | 4 | * Author: Hannes Mannerheim () 5 | * Last mod.: July, 2015 6 | * Version: 0.2-alpha 7 | * GitHub: 8 | 9 | Quitim is free software: you can redistribute it and / or modify it 10 | under the terms of the GNU Affero General Public License as published by 11 | the Free Software Foundation, either version three of the License or (at 12 | your option) any later version. 13 | 14 | Quitim is distributed in hope that it will be useful but WITHOUT ANY 15 | WARRANTY; without even the implied warranty of MERCHANTABILTY or FITNESS 16 | FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for 17 | more details. 18 | 19 | You should have received a copy of the GNU Affero General Public License 20 | along with Quitim. If not, see . 21 | 22 | About 23 | ----- 24 | 25 | Quitim makes GNU Social look and work a little like Instagram. 26 | 27 | THIS IS NOT FINISHED SOFTWARE!! Some important things still remain, such as 28 | user settings, commenting design etc etc etc. Only install this if you are curious 29 | or want to help develop it. I mostly uploaded it here now as a backup. 30 | 31 | 32 | Setup 33 | ----- 34 | 35 | 1. Install GNU Social 36 | 37 | 2. It's probably best to disable all plugins except EmailAuthentication, Ostatus, OpportunisticQM, RegisterThrottle and WebFinger in your 38 | ://{instance}/panel/plugins panel 39 | 40 | 3. Put all files in local/plugins/Quitim 41 | 42 | 4. Move local/plugins/Quitim/Bourgoeis to local/plugins/Bourgoeis 43 | 44 | 4. Add this to your /config.php file. 45 | ```` 46 | addPlugin('Quitim'); 47 | addPlugin('ActivityVerb'); 48 | addPlugin('Bourgeois'); 49 | addPlugin('InfiniteScroll'); 50 | ```` 51 | 52 | 5. In lib/framework.php, set these constants like this: 53 | ```` 54 | define('AVATAR_PROFILE_SIZE', 192); 55 | define('AVATAR_STREAM_SIZE', 96); 56 | define('AVATAR_MINI_SIZE', 48); 57 | ```` 58 | 6. In lib/default.php, change the thumbnail maxsize to something high, like 4000 59 | 60 | -------------------------------------------------------------------------------- /actions/apinewnotifications.php: -------------------------------------------------------------------------------- 1 | . 20 | * 21 | * @category API 22 | * @package GNUsocial 23 | * @author Hannes Mannerheim 24 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 25 | * @link http://www.gnu.org/software/social/ 26 | */ 27 | 28 | if (!defined('GNUSOCIAL')) { exit(1); } 29 | 30 | class ApiNewNotificationsAction extends ApiAction 31 | { 32 | 33 | /** 34 | * Take arguments for running 35 | * 36 | * @param array $args $_REQUEST args 37 | * 38 | * @return boolean success flag 39 | */ 40 | protected function prepare(array $args=array()) 41 | { 42 | parent::prepare($args); 43 | 44 | return true; 45 | } 46 | 47 | /** 48 | * Handle the request 49 | * 50 | * @param array $args $_REQUEST data (unused) 51 | * 52 | * @return void 53 | */ 54 | protected function handle() 55 | { 56 | parent::handle(); 57 | 58 | $user_id = Profile::current()->id; 59 | $new_notifications = array(); 60 | if($user_id) { 61 | $notification = new QuitimNotification(); 62 | 63 | $notification->selectAdd(); 64 | $notification->selectAdd('ntype'); 65 | $notification->selectAdd('count(id) as count'); 66 | $notification->whereAdd("(to_profile_id = '".$user_id."')"); 67 | $notification->groupBy('ntype'); 68 | $notification->whereAdd("(is_seen = '0')"); 69 | $notification->find(); 70 | 71 | while ($notification->fetch()) { 72 | $new_notifications[$notification->ntype] = $notification->count; 73 | } 74 | } 75 | else { 76 | $new_notifications = 'You must be logged in.'; 77 | } 78 | 79 | 80 | $this->initDocument('json'); 81 | $this->showJsonObjects($new_notifications); 82 | $this->endDocument('json'); 83 | } 84 | 85 | /** 86 | * Return true if read only. 87 | * 88 | * MAY override 89 | * 90 | * @param array $args other arguments 91 | * 92 | * @return boolean is read only action? 93 | */ 94 | 95 | function isReadOnly($args) 96 | { 97 | return true; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /actions/quitimall.php: -------------------------------------------------------------------------------- 1 | cssLink($path.'css/quitim.css?changed='.date('YmdHis',filemtime(QUITIMDIR.'/css/quitim.css'))); 27 | 28 | } 29 | 30 | function showBody() 31 | { 32 | 33 | $stream = new ChronologicalInboxStream($this->target, $this->scoped); 34 | 35 | $this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE, 36 | NOTICES_PER_PAGE + 1); 37 | 38 | $current_user = common_current_user(); 39 | 40 | $bodyclasses = 'quitim'; 41 | if ($this->scoped instanceof Profile) { 42 | $bodyclasses .= ' user_in'; 43 | if ($this->scoped->id === $this->target->id) { 44 | $bodyclasses .= ' me'; 45 | } 46 | } 47 | $this->elementStart('body', array('id' => strtolower($this->trimmed('action')), 'class' => $bodyclasses, 'ontouchstart' => '')); 48 | $this->element('div', array('id' => 'spinner-overlay')); 49 | 50 | 51 | $this->elementStart('div', array('id' => 'wrap')); 52 | QuitimFooter::showQuitimFooter(); 53 | 54 | $this->elementStart('div', array('id' => 'header')); 55 | $this->showLogo(); 56 | $this->elementStart('div', array('id' => 'topright')); 57 | $this->element('img', array('id' => 'refresh', 'height' => '30', 'width' => '30', 'src' => Plugin::staticPath('Quitim', 'img/refresh.png'))); 58 | $this->elementEnd('div'); 59 | $this->elementEnd('div'); 60 | 61 | $this->elementStart('div', array('id' => 'core')); 62 | $this->elementStart('div', array('id' => 'aside_primary_wrapper')); 63 | $this->elementStart('div', array('id' => 'content_wrapper')); 64 | $this->elementStart('div', array('id' => 'site_nav_local_views_wrapper')); 65 | 66 | $this->elementStart('div', array('id' => 'content')); 67 | if (common_logged_in()) { 68 | if (Event::handle('StartShowNoticeForm', array($this))) { 69 | $this->showNoticeForm(); 70 | Event::handle('EndShowNoticeForm', array($this)); 71 | } 72 | } 73 | 74 | $this->elementStart('div', array('id' => 'content_inner')); 75 | 76 | $this->elementStart('div', array('id' => 'usernotices', 'class' => 'noticestream threaded-view')); 77 | if($this->notice->N>0) { 78 | $this->showNoticesWithCommentsAndFavs(); 79 | } 80 | else { 81 | // show welcome 82 | } 83 | $this->elementEnd('div'); 84 | 85 | $this->elementEnd('div'); 86 | $this->elementEnd('div'); 87 | 88 | 89 | $this->elementEnd('div'); 90 | $this->elementEnd('div'); 91 | $this->elementEnd('div'); 92 | $this->elementEnd('div'); 93 | 94 | 95 | $this->elementEnd('div'); 96 | $this->showScripts(); 97 | $this->elementEnd('body'); 98 | } 99 | 100 | 101 | function showProfileBlock() 102 | { 103 | $block = new QuitimAccountProfileBlock($this, $this->target); 104 | $block->show(); 105 | } 106 | 107 | 108 | function showNoticesWithCommentsAndFavs() 109 | { 110 | $nl = new QuitimThreadedNoticeList($this->notice, $this, $this->target); 111 | $cnt = $nl->show(); 112 | if (0 == $cnt) { 113 | $this->showEmptyListMessage(); 114 | } 115 | $this->pagination( 116 | $this->page > 1, $cnt > NOTICES_PER_PAGE, 117 | $this->page, 'quitimall', array('nickname' => $this->target->getNickname()) 118 | ); 119 | } 120 | 121 | 122 | 123 | } 124 | -------------------------------------------------------------------------------- /actions/quitimfavorited.php: -------------------------------------------------------------------------------- 1 | page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; 26 | 27 | $stream = new PopularNoticeStream(Profile::current()); 28 | $this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE+1); 29 | 30 | return true; 31 | } 32 | 33 | function isReadOnly($args) 34 | { 35 | return true; 36 | } 37 | 38 | function title() 39 | { 40 | $current_user = common_current_user(); 41 | if(!$current_user) { 42 | return _('Welcome!'); 43 | } else { 44 | return _('Quitim moments'); 45 | } 46 | 47 | 48 | } 49 | 50 | protected function handle() 51 | { 52 | 53 | parent::handle(); 54 | 55 | } 56 | 57 | protected function doPost() 58 | { 59 | // XXX: login throttle 60 | 61 | $nickname = $this->trimmed('nickname'); 62 | $password = $this->arg('password'); 63 | 64 | $user = common_check_user($nickname, $password); 65 | 66 | 67 | if (!$user instanceof User) { 68 | // TRANS: Form validation error displayed when trying to log in with incorrect credentials. 69 | throw new ServerException(_('Incorrect username or password.')); 70 | } 71 | 72 | // success! 73 | if (!common_set_user($user)) { 74 | // TRANS: Server error displayed when during login a server error occurs. 75 | throw new ServerException(_('Error setting user. You are probably not authorized.')); 76 | } 77 | 78 | common_real_login(true); 79 | $this->updateScopedProfile(); 80 | 81 | if ($this->boolean('rememberme')) { 82 | common_rememberme($user); 83 | } 84 | 85 | $url = common_local_url('all', array('nickname' => $this->scoped->nickname)); 86 | 87 | common_redirect($url, 303); 88 | } 89 | 90 | public function showPageNotice() 91 | { 92 | 93 | } 94 | 95 | public function showInstructions() 96 | { 97 | 98 | } 99 | 100 | 101 | public function showForm($msg=null, $success=false) 102 | { 103 | 104 | } 105 | 106 | 107 | function showSections() 108 | { 109 | 110 | } 111 | 112 | function showStylesheets() 113 | { 114 | 115 | // We only want quitim stylesheet 116 | $path = Plugin::staticPath('Quitim', ''); 117 | $this->cssLink($path.'css/quitim.css?changed='.date('YmdHis',filemtime(QUITIMDIR.'/css/quitim.css'))); 118 | 119 | 120 | } 121 | 122 | function showBody() 123 | { 124 | 125 | $current_user = common_current_user(); 126 | 127 | $bodyclasses = 'quitim'; 128 | if($current_user) { 129 | $bodyclasses .= ' user_in'; 130 | } else { 131 | $bodyclasses .= ' logged-out'; 132 | } 133 | $this->elementStart('body', array('id' => strtolower($this->trimmed('action')), 'class' => $bodyclasses, 'ontouchstart' => '')); 134 | $this->element('div', array('id' => 'spinner-overlay')); 135 | $this->element('div', array('id' => 'popup-register')); 136 | 137 | $this->elementStart('div', array('id' => 'wrap')); 138 | QuitimFooter::showQuitimFooter(); 139 | 140 | $this->elementStart('div', array('id' => 'header')); 141 | $this->elementStart('a', array('href' => '#top')); 142 | $this->elementStart('h1'); 143 | $this->raw(_('Quitim moments')); 144 | $this->elementEnd('h1'); 145 | $this->elementEnd('a'); 146 | 147 | $this->elementStart('div', array('id' => 'topright')); 148 | $this->elementEnd('div'); 149 | 150 | $this->elementEnd('div'); 151 | 152 | $this->elementStart('div', array('id' => 'core')); 153 | $this->elementStart('div', array('id' => 'aside_primary_wrapper')); 154 | $this->elementStart('div', array('id' => 'content_wrapper')); 155 | $this->elementStart('div', array('id' => 'site_nav_local_views_wrapper')); 156 | 157 | $this->elementStart('div', array('id' => 'content')); 158 | if (common_logged_in()) { 159 | if (Event::handle('StartShowNoticeForm', array($this))) { 160 | $this->showNoticeForm(); 161 | Event::handle('EndShowNoticeForm', array($this)); 162 | } 163 | } 164 | 165 | $this->elementStart('div', array('id' => 'content_inner')); 166 | 167 | $this->elementStart('div', array('id' => 'thumb-thread')); 168 | $this->elementStart('div', array('id' => 'set-thumbnail-view')); 169 | $this->elementEnd('div'); 170 | $this->elementStart('div', array('id' => 'set-threaded-view')); 171 | $this->elementEnd('div'); 172 | $this->elementEnd('div'); 173 | 174 | 175 | $this->elementStart('div', array('id' => 'usernotices', 'class' => 'noticestream thumbnail-view')); 176 | $this->showNoticesWithCommentsAndFavs(); 177 | $this->elementEnd('div'); 178 | 179 | $this->elementEnd('div'); 180 | $this->elementEnd('div'); 181 | 182 | 183 | $this->elementEnd('div'); 184 | $this->elementEnd('div'); 185 | $this->elementEnd('div'); 186 | $this->elementEnd('div'); 187 | 188 | 189 | 190 | $this->elementEnd('div'); 191 | 192 | // login overlay if logged out 193 | $current_user = common_current_user(); 194 | if(!$current_user) { 195 | 196 | $this->elementStart('div', array('id' => 'login-overlay')); 197 | $this->element('div', array('id' => 'loginlogo')); 198 | 199 | $this->elementStart('div', array('id' => 'login-content_inner')); 200 | 201 | if ($msg = $this->getError()) { 202 | $this->element('div', 'error', $msg); 203 | } 204 | 205 | $this->elementStart('form', array('method' => 'post', 206 | 'id' => 'form_login', 207 | 'class' => 'form_settings', 208 | 'action' => common_local_url('login'))); 209 | $this->elementStart('fieldset'); 210 | // TRANS: Form legend on login page. 211 | $this->elementStart('ul', 'form_data'); 212 | $this->elementStart('li'); 213 | // TRANS: Field label on login page. 214 | $this->element('input', array('id'=>'nickname', 'type'=>'text', 'name'=>'nickname', 'autocomplete'=>'off', 'placeholder'=>_('Username or email'))); 215 | $this->elementEnd('li'); 216 | $this->elementStart('li'); 217 | // TRANS: Field label on login page. 218 | $this->element('input', array('id'=>'password', 'class'=>'password', 'type'=>'password', 'name'=>'password', 'placeholder'=>_('Password'))); 219 | // $this->password('password', _('Password')); 220 | $this->elementEnd('li'); 221 | $this->elementStart('li'); 222 | // TRANS: Checkbox label label on login page. 223 | $this->checkbox('rememberme', _('Remember me'), 'checked'); 224 | $this->elementEnd('li'); 225 | $this->elementEnd('ul'); 226 | // TRANS: Button text for log in on login page. 227 | $this->submit('submit', _m('BUTTON','Login')); 228 | $this->hidden('token', common_session_token()); 229 | $this->elementEnd('fieldset'); 230 | $this->elementEnd('form'); 231 | $this->elementStart('p', array('id'=>'lostpassword')); 232 | $this->element('a', array('href' => common_local_url('recoverpassword')), 233 | // TRANS: Link text for link to "reset password" on login page. 234 | _('Lost or forgotten password?')); 235 | $this->elementEnd('p'); 236 | 237 | 238 | 239 | $this->elementEnd('div'); 240 | 241 | $this->elementStart('div',array('id'=>'what-is-quitim')); 242 | $this->raw('

Welcome to Quitim!

We are a federated, open source, non-profit, non-commercial, mobile image sharing community. Confused? Check out the recent popular images.

When you sign up here you become an activist in the online anti-capitalist struggle, a part in building an open and non-commercial space where we can interact and organize without profit driven corporations interfering and sabotaging our communications.

★ Quitim is not a service and you are not a customer here – we\'re doing this together.

★ For-profit businesses are not allowed to register. Users who harass others or propagate discriminatory political views – such as racism, sexism, ableism, homo- and transphobia – will be removed. Quitim users are expected to participate in making the network a respectful and kind place where everyone feels safe.

★ Quitim is part of the GNU social network, which means that you don\'t have to sign up to Quitim to talk to your Quitim friends – you can join any GNU social server and follow them from there.

★ All your images on Quitim are licensed under Creative Commons BY-NC, which means no one can use your content for advertising.'); 243 | $this->elementStart('a',array('id'=>'quitim-sign-up', 'href'=>common_local_url('register'), 'class'=>'register-link')); 244 | $this->raw('Sign up!'); 245 | $this->elementEnd('a'); 246 | $this->elementEnd('div'); 247 | 248 | 249 | $this->elementEnd('div'); 250 | 251 | $this->elementEnd('div'); 252 | 253 | $this->elementStart('script'); 254 | 255 | $checknicknameurl = common_local_url('ApiCheckNickname',array('format'=>'json')); 256 | $registerapiurl = common_local_url('ApiAccountRegister',array('format'=>'json')); 257 | $this->raw('window.registerNickname = \''._('Nickname').'\';'. 258 | 'window.signUpEmail = \''._('Email address').'\';'. 259 | 'window.registerHomepage = \''._('Homepage').'\';'. 260 | 'window.registerBio = \''._('Bio').'\';'. 261 | 'window.loginPassword = \''._('Password').'\';'. 262 | 'window.registerRepeatPassword = \''._('Repeat password').'\';'. 263 | 'window.signUpButtonText = \''._('Sign up!').'\';'. 264 | 'window.licenseText = '.json_encode('By signing up I confirm that all my posted images and texts are available under '.htmlspecialchars(common_config('license', 'title')).'. I understand that I should keep my own backups and that I can be suspended from using '.common_config('site', 'name').' at any time for any reason. The administrators of '.common_config('site', 'name').' take no responsability whatsoever. We can\'t even spell responsability. If you do not like this – start your own GNU social instance. You can follow Quitim users on any server.').';'. 265 | 'window.checkNicknameUrl = \''.$checknicknameurl.'\';'. 266 | 'window.registerApiUrl = \''.$registerapiurl.'\';'); 267 | $this->elementEnd('script'); 268 | } 269 | $this->showScripts(); 270 | $this->elementEnd('body'); 271 | } 272 | 273 | 274 | 275 | function showNoticesWithCommentsAndFavs() 276 | { 277 | 278 | $nl = new QuitimThreadedNoticeList($this->notice, $this); 279 | $cnt = $nl->show(); 280 | $this->pagination( 281 | $this->page > 1, $cnt > NOTICES_PER_PAGE, 282 | $this->page, 'quitimfavorited'); 283 | } 284 | 285 | } 286 | -------------------------------------------------------------------------------- /actions/quitimfollowers.php: -------------------------------------------------------------------------------- 1 | arg('nickname'); 24 | $this->user = User::getKV('nickname', $user_nickname); 25 | $this->profile = $this->user->getProfile(); 26 | $this->scoped = Profile::current(); 27 | 28 | return true; 29 | } 30 | 31 | /** 32 | * Handle a request 33 | * 34 | * Just show the page. All args already handled. 35 | * 36 | * @param array $args $_REQUEST data 37 | * 38 | * @return void 39 | */ 40 | function handle($args) 41 | { 42 | parent::handle($args); 43 | $this->showPage(); 44 | } 45 | 46 | 47 | // get all profiles that likes this notice 48 | function getFollowersProfiles() 49 | { 50 | $profile = array(); 51 | try { 52 | $subs = Subscription::bySubscribed($this->profile->id,0,10000); 53 | while($subs->fetch()) { 54 | $profiles[$subs->subscriber] = $subs->subscriber; 55 | } 56 | } catch (NoResultException $e) { 57 | // 58 | } 59 | return $profiles; 60 | } 61 | 62 | /** 63 | * Title of the page 64 | * 65 | * Includes name of user and page number. 66 | * 67 | * @return string title of page 68 | */ 69 | function title() 70 | { 71 | if(substr($this->profile->nickname,-1) == 's') { 72 | return sprintf(_("%s' followers"), $this->profile->nickname); 73 | } else { 74 | return sprintf(_("%s's followers"), $this->profile->nickname); 75 | } 76 | 77 | } 78 | 79 | 80 | function showBody() 81 | { 82 | 83 | $current_user = common_current_user(); 84 | 85 | $bodyclasses = 'quitim'; 86 | if($current_user) { 87 | $bodyclasses .= ' user_in'; 88 | } 89 | $this->elementStart('body', array('id' => strtolower($this->trimmed('action')), 'class' => $bodyclasses, 'ontouchstart' => '')); 90 | $this->element('div', array('id' => 'spinner-overlay')); 91 | 92 | $this->elementStart('div', array('id' => 'wrap')); 93 | QuitimFooter::showQuitimFooter(); 94 | 95 | $this->elementStart('div', array('id' => 'header')); 96 | $this->elementStart('a', array('href' => '#top')); 97 | $this->elementStart('h1'); 98 | if(substr($this->profile->nickname,-1) == 's') { 99 | $this->raw(sprintf(_("%s' followers"), $this->profile->nickname)); 100 | } else { 101 | $this->raw(sprintf(_("%s's followers"), $this->profile->nickname)); 102 | } 103 | $this->elementEnd('h1'); 104 | $this->elementEnd('a'); 105 | $this->elementStart('div', array('id' => 'topright')); 106 | $this->element('img', array('id' => 'refresh', 'height' => '30', 'width' => '30', 'src' => Plugin::staticPath('Quitim', 'img/refresh.png'))); 107 | $this->elementEnd('div'); 108 | $this->elementEnd('div'); 109 | 110 | $this->elementStart('div', array('id' => 'core')); 111 | $this->elementStart('div', array('id' => 'aside_primary_wrapper')); 112 | $this->elementStart('div', array('id' => 'content_wrapper')); 113 | $this->elementStart('div', array('id' => 'site_nav_local_views_wrapper')); 114 | 115 | $this->elementStart('div', array('id' => 'content')); 116 | if (common_logged_in()) { 117 | if (Event::handle('StartShowNoticeForm', array($this))) { 118 | $this->showNoticeForm(); 119 | Event::handle('EndShowNoticeForm', array($this)); 120 | } 121 | } 122 | 123 | $this->elementStart('div', array('id' => 'content_inner')); 124 | $this->elementStart('div', array('id' => 'quitimprofilelist', 'class' => 'quitimprofilestream')); 125 | $this->elementStart('div', array('id' => 'profiles_primary')); 126 | $this->elementStart('ol', array('class' => 'profiles')); 127 | 128 | 129 | $profiles = $this->getFollowersProfiles(); 130 | if(count($profiles) > 0) { 131 | foreach ($profiles as $id) { 132 | 133 | $profile = Profile::getKV('id', $id); 134 | if ($profile) { 135 | $profile_list_item = new QuitimProfileListItem($profile, $this); 136 | $profile_list_item->show(); 137 | } 138 | } 139 | } else { 140 | $this->raw(_("No followers")); 141 | } 142 | 143 | $this->elementEnd('ol'); 144 | $this->elementEnd('div'); 145 | 146 | $this->elementEnd('div'); 147 | 148 | $this->elementEnd('div'); 149 | $this->elementEnd('div'); 150 | 151 | 152 | $this->elementEnd('div'); 153 | $this->elementEnd('div'); 154 | $this->elementEnd('div'); 155 | $this->elementEnd('div'); 156 | 157 | $this->elementEnd('div'); 158 | $this->showScripts(); 159 | $this->elementEnd('body'); 160 | } 161 | 162 | /** 163 | * Show the content 164 | * 165 | * A list of notices that are replies to the user, plus pagination. 166 | * 167 | * @return void 168 | */ 169 | function showContent() 170 | { 171 | // 172 | } 173 | 174 | 175 | 176 | function isReadOnly($args) 177 | { 178 | return true; 179 | } 180 | 181 | function showStylesheets() 182 | { 183 | 184 | $this->cssLink(Plugin::staticPath('Quitim', 'css/quitim.css')); 185 | 186 | } 187 | 188 | } 189 | -------------------------------------------------------------------------------- /actions/quitimfollowing.php: -------------------------------------------------------------------------------- 1 | arg('nickname'); 24 | $this->user = User::getKV('nickname', $user_nickname); 25 | $this->profile = $this->user->getProfile(); 26 | $this->scoped = Profile::current(); 27 | 28 | return true; 29 | } 30 | 31 | /** 32 | * Handle a request 33 | * 34 | * Just show the page. All args already handled. 35 | * 36 | * @param array $args $_REQUEST data 37 | * 38 | * @return void 39 | */ 40 | function handle($args) 41 | { 42 | parent::handle($args); 43 | $this->showPage(); 44 | } 45 | 46 | 47 | // get all profiles that likes this notice 48 | function getFollowersProfiles() 49 | { 50 | $profile = array(); 51 | try { 52 | $subs = Subscription::bySubscriber($this->profile->id,0,10000); 53 | while($subs->fetch()) { 54 | $profiles[$subs->subscribed] = $subs->subscribed; 55 | } 56 | } catch (NoResultException $e) { 57 | // 58 | } 59 | return $profiles; 60 | } 61 | 62 | /** 63 | * Title of the page 64 | * 65 | * Includes name of user and page number. 66 | * 67 | * @return string title of page 68 | */ 69 | function title() 70 | { 71 | return sprintf(_("users %s follows"), $this->profile->nickname); 72 | } 73 | 74 | 75 | function showBody() 76 | { 77 | 78 | $current_user = common_current_user(); 79 | 80 | $bodyclasses = 'quitim'; 81 | if($current_user) { 82 | $bodyclasses .= ' user_in'; 83 | } 84 | $this->elementStart('body', array('id' => strtolower($this->trimmed('action')), 'class' => $bodyclasses, 'ontouchstart' => '')); 85 | $this->element('div', array('id' => 'spinner-overlay')); 86 | 87 | $this->elementStart('div', array('id' => 'wrap')); 88 | QuitimFooter::showQuitimFooter(); 89 | 90 | $this->elementStart('div', array('id' => 'header')); 91 | $this->elementStart('a', array('href' => '#top')); 92 | $this->elementStart('h1'); 93 | $this->raw(sprintf(_("users %s follows"), $this->profile->nickname)); 94 | $this->elementEnd('h1'); 95 | $this->elementEnd('a'); 96 | $this->elementStart('div', array('id' => 'topright')); 97 | $this->element('img', array('id' => 'refresh', 'height' => '30', 'width' => '30', 'src' => Plugin::staticPath('Quitim', 'img/refresh.png'))); 98 | $this->elementEnd('div'); 99 | $this->elementEnd('div'); 100 | 101 | $this->elementStart('div', array('id' => 'core')); 102 | $this->elementStart('div', array('id' => 'aside_primary_wrapper')); 103 | $this->elementStart('div', array('id' => 'content_wrapper')); 104 | $this->elementStart('div', array('id' => 'site_nav_local_views_wrapper')); 105 | 106 | $this->elementStart('div', array('id' => 'content')); 107 | if (common_logged_in()) { 108 | if (Event::handle('StartShowNoticeForm', array($this))) { 109 | $this->showNoticeForm(); 110 | Event::handle('EndShowNoticeForm', array($this)); 111 | } 112 | } 113 | 114 | $this->elementStart('div', array('id' => 'content_inner')); 115 | $this->elementStart('div', array('id' => 'quitimprofilelist', 'class' => 'quitimprofilestream')); 116 | $this->elementStart('div', array('id' => 'profiles_primary')); 117 | $this->elementStart('ol', array('class' => 'profiles')); 118 | 119 | 120 | $profiles = $this->getFollowersProfiles(); 121 | if(count($profiles) > 0) { 122 | foreach ($profiles as $id) { 123 | 124 | $profile = Profile::getKV('id', $id); 125 | if ($profile) { 126 | $profile_list_item = new QuitimProfileListItem($profile, $this); 127 | $profile_list_item->show(); 128 | } 129 | } 130 | } else { 131 | $this->raw(_("No followers")); 132 | } 133 | 134 | $this->elementEnd('ol'); 135 | $this->elementEnd('div'); 136 | 137 | $this->elementEnd('div'); 138 | 139 | $this->elementEnd('div'); 140 | $this->elementEnd('div'); 141 | 142 | 143 | $this->elementEnd('div'); 144 | $this->elementEnd('div'); 145 | $this->elementEnd('div'); 146 | $this->elementEnd('div'); 147 | 148 | $this->elementEnd('div'); 149 | $this->showScripts(); 150 | $this->elementEnd('body'); 151 | } 152 | 153 | /** 154 | * Show the content 155 | * 156 | * A list of notices that are replies to the user, plus pagination. 157 | * 158 | * @return void 159 | */ 160 | function showContent() 161 | { 162 | // 163 | } 164 | 165 | 166 | 167 | function isReadOnly($args) 168 | { 169 | return true; 170 | } 171 | 172 | function showStylesheets() 173 | { 174 | 175 | $this->cssLink(Plugin::staticPath('Quitim', 'css/quitim.css')); 176 | 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /actions/quitimlikers.php: -------------------------------------------------------------------------------- 1 | arg('notice'); 24 | $this->notice = Notice::getKV('id', $notice_id); 25 | $this->profile = $this->notice->getProfile(); 26 | $this->scoped = Profile::current(); 27 | 28 | return true; 29 | } 30 | 31 | /** 32 | * Handle a request 33 | * 34 | * Just show the page. All args already handled. 35 | * 36 | * @param array $args $_REQUEST data 37 | * 38 | * @return void 39 | */ 40 | function handle($args) 41 | { 42 | parent::handle($args); 43 | $this->showPage(); 44 | } 45 | 46 | 47 | // get all profiles that likes this notice 48 | function getLikerProfiles() 49 | { 50 | $faves = Fave::byNotice($this->notice); 51 | $profiles = array(); 52 | foreach ($faves as $fave) { 53 | $profiles[] = $fave->user_id; 54 | } 55 | return $profiles; 56 | } 57 | 58 | /** 59 | * Title of the page 60 | * 61 | * Includes name of user and page number. 62 | * 63 | * @return string title of page 64 | */ 65 | function title() 66 | { 67 | return sprintf(_("Likes for %s's image"), $this->profile->nickname); 68 | } 69 | 70 | 71 | function showBody() 72 | { 73 | 74 | $current_user = common_current_user(); 75 | 76 | $bodyclasses = 'quitim'; 77 | if($current_user) { 78 | $bodyclasses .= ' user_in'; 79 | } 80 | $this->elementStart('body', array('id' => strtolower($this->trimmed('action')), 'class' => $bodyclasses, 'ontouchstart' => '')); 81 | $this->element('div', array('id' => 'spinner-overlay')); 82 | 83 | $this->elementStart('div', array('id' => 'wrap')); 84 | QuitimFooter::showQuitimFooter(); 85 | 86 | $this->elementStart('div', array('id' => 'header')); 87 | $this->elementStart('a', array('href' => '#top')); 88 | $this->elementStart('h1'); 89 | $this->raw(_('Likers')); 90 | $this->elementEnd('h1'); 91 | $this->elementEnd('a'); 92 | $this->elementStart('div', array('id' => 'topright')); 93 | $this->element('img', array('id' => 'refresh', 'height' => '30', 'width' => '30', 'src' => Plugin::staticPath('Quitim', 'img/refresh.png'))); 94 | $this->elementEnd('div'); 95 | $this->elementEnd('div'); 96 | 97 | $this->elementStart('div', array('id' => 'core')); 98 | $this->elementStart('div', array('id' => 'aside_primary_wrapper')); 99 | $this->elementStart('div', array('id' => 'content_wrapper')); 100 | $this->elementStart('div', array('id' => 'site_nav_local_views_wrapper')); 101 | 102 | $this->elementStart('div', array('id' => 'content')); 103 | if (common_logged_in()) { 104 | if (Event::handle('StartShowNoticeForm', array($this))) { 105 | $this->showNoticeForm(); 106 | Event::handle('EndShowNoticeForm', array($this)); 107 | } 108 | } 109 | 110 | $this->elementStart('div', array('id' => 'content_inner')); 111 | $this->elementStart('div', array('id' => 'quitimprofilelist', 'class' => 'quitimprofilestream')); 112 | $this->elementStart('div', array('id' => 'profiles_primary')); 113 | $this->elementStart('ol', array('class' => 'profiles')); 114 | 115 | 116 | $profiles = $this->getLikerProfiles(); 117 | if(count($profiles) > 0) { 118 | foreach ($profiles as $id) { 119 | 120 | $profile = Profile::getKV('id', $id); 121 | if ($profile) { 122 | $profile_list_item = new QuitimProfileListItem($profile, $this); 123 | $profile_list_item->show(); 124 | } 125 | } 126 | } else { 127 | $this->raw(_("No likes")); 128 | } 129 | 130 | $this->elementEnd('ol'); 131 | $this->elementEnd('div'); 132 | 133 | $this->elementEnd('div'); 134 | 135 | $this->elementEnd('div'); 136 | $this->elementEnd('div'); 137 | 138 | 139 | $this->elementEnd('div'); 140 | $this->elementEnd('div'); 141 | $this->elementEnd('div'); 142 | $this->elementEnd('div'); 143 | 144 | $this->elementEnd('div'); 145 | $this->showScripts(); 146 | $this->elementEnd('body'); 147 | } 148 | 149 | /** 150 | * Show the content 151 | * 152 | * A list of notices that are replies to the user, plus pagination. 153 | * 154 | * @return void 155 | */ 156 | function showContent() 157 | { 158 | // 159 | } 160 | 161 | 162 | 163 | function isReadOnly($args) 164 | { 165 | return true; 166 | } 167 | 168 | function showStylesheets() 169 | { 170 | 171 | $this->cssLink(Plugin::staticPath('Quitim', 'css/quitim.css')); 172 | 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /actions/quitimnewnotice.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @category Personal 23 | * @package StatusNet 24 | * @author Evan Prodromou 25 | * @author Zach Copley 26 | * @author Sarven Capadisli 27 | * @copyright 2008-2009 StatusNet, Inc. 28 | * @copyright 2013 Free Software Foundation, Inc. 29 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 30 | * @link http://status.net/ 31 | */ 32 | 33 | if (!defined('GNUSOCIAL')) { exit(1); } 34 | 35 | /** 36 | * Action for posting new notices 37 | * 38 | * @category Personal 39 | * @package StatusNet 40 | * @author Evan Prodromou 41 | * @author Zach Copley 42 | * @author Sarven Capadisli 43 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 44 | * @link http://status.net/ 45 | */ 46 | class QuitimNewnoticeAction extends FormAction 47 | { 48 | protected $form = 'Notice'; 49 | 50 | /** 51 | * Title of the page 52 | * 53 | * Note that this usually doesn't get called unless something went wrong 54 | * 55 | * @return string page title 56 | */ 57 | function title() 58 | { 59 | if ($this->getInfo() && $this->stored instanceof Notice) { 60 | // TRANS: Page title after sending a notice. 61 | return _('Notice posted'); 62 | } 63 | if ($this->int('inreplyto')) { 64 | return _m('TITLE', 'New reply'); 65 | } 66 | // TRANS: Page title for sending a new notice. 67 | return _m('TITLE','New notice'); 68 | } 69 | 70 | protected function doPreparation() 71 | { 72 | foreach(array('inreplyto') as $opt) { 73 | if ($this->trimmed($opt)) { 74 | $this->formOpts[$opt] = $this->trimmed($opt); 75 | } 76 | } 77 | 78 | // Backwards compatibility for "share this" widget things. 79 | // If no 'content', use 'status_textarea' 80 | $this->formOpts['content'] = $this->trimmed('content') ?: $this->trimmed('status_textarea'); 81 | } 82 | 83 | /** 84 | * This doPost saves a new notice, based on arguments 85 | * 86 | * If successful, will show the notice, or return an Ajax-y result. 87 | * If not, it will show an error message -- possibly Ajax-y. 88 | * 89 | * Also, if the notice input looks like a command, it will run the 90 | * command and show the results -- again, possibly ajaxy. 91 | * 92 | * @return void 93 | */ 94 | protected function doPost() 95 | { 96 | assert($this->scoped instanceof Profile); // XXX: maybe an error instead... 97 | $user = $this->scoped->getUser(); 98 | $content = $this->trimmed('status_textarea'); 99 | $options = array('source' => 'quitim'); 100 | Event::handle('StartSaveNewNoticeWeb', array($this, $user, &$content, &$options)); 101 | 102 | if (empty($content)) { 103 | // TRANS: Client error displayed trying to send a notice without content. 104 | $this->clientError(_('No content!')); 105 | } 106 | 107 | $inter = new CommandInterpreter(); 108 | 109 | $cmd = $inter->handle_command($user, $content); 110 | 111 | if ($cmd) { 112 | if (GNUsocial::isAjax()) { 113 | $cmd->execute(new AjaxWebChannel($this)); 114 | } else { 115 | $cmd->execute(new WebChannel($this)); 116 | } 117 | return; 118 | } 119 | 120 | $content_shortened = $user->shortenLinks($content); 121 | if (Notice::contentTooLong($content_shortened)) { 122 | // TRANS: Client error displayed when the parameter "status" is missing. 123 | // TRANS: %d is the maximum number of character for a notice. 124 | $this->clientError(sprintf(_m('That\'s too long. Maximum notice size is %d character.', 125 | 'That\'s too long. Maximum notice size is %d characters.', 126 | Notice::maxContent()), 127 | Notice::maxContent())); 128 | } 129 | 130 | $replyto = $this->int('inreplyto'); 131 | if ($replyto) { 132 | $options['reply_to'] = $replyto; 133 | } 134 | 135 | $upload = null; 136 | try { 137 | // throws exception on failure 138 | $upload = MediaFile::fromUpload('attach', $this->scoped); 139 | if (Event::handle('StartSaveNewNoticeAppendAttachment', array($this, $upload, &$content_shortened, &$options))) { 140 | $content_shortened .= ' ' . $upload->shortUrl(); 141 | } 142 | Event::handle('EndSaveNewNoticeAppendAttachment', array($this, $upload, &$content_shortened, &$options)); 143 | 144 | if (Notice::contentTooLong($content_shortened)) { 145 | $upload->delete(); 146 | // TRANS: Client error displayed exceeding the maximum notice length. 147 | // TRANS: %d is the maximum length for a notice. 148 | $this->clientError(sprintf(_m('Maximum notice size is %d character, including attachment URL.', 149 | 'Maximum notice size is %d characters, including attachment URL.', 150 | Notice::maxContent()), 151 | Notice::maxContent())); 152 | } 153 | } catch (NoUploadedMediaException $e) { 154 | // simply no attached media to the new notice 155 | } 156 | 157 | 158 | if ($this->scoped->shareLocation()) { 159 | // use browser data if checked; otherwise profile data 160 | if ($this->arg('notice_data-geo')) { 161 | $locOptions = Notice::locationOptions($this->trimmed('lat'), 162 | $this->trimmed('lon'), 163 | $this->trimmed('location_id'), 164 | $this->trimmed('location_ns'), 165 | $this->scoped); 166 | } else { 167 | $locOptions = Notice::locationOptions(null, 168 | null, 169 | null, 170 | null, 171 | $this->scoped); 172 | } 173 | 174 | $options = array_merge($options, $locOptions); 175 | } 176 | 177 | $author_id = $this->scoped->id; 178 | $text = $content_shortened; 179 | 180 | // Does the heavy-lifting for getting "To:" information 181 | 182 | ToSelector::fillOptions($this, $options); 183 | 184 | if (Event::handle('StartNoticeSaveWeb', array($this, &$author_id, &$text, &$options))) { 185 | 186 | $this->stored = Notice::saveNew($this->scoped->id, $content_shortened, 'web', $options); 187 | 188 | if ($upload instanceof MediaFile) { 189 | $upload->attachToNotice($this->stored); 190 | } 191 | 192 | Event::handle('EndNoticeSaveWeb', array($this, $this->stored)); 193 | } 194 | 195 | Event::handle('EndSaveNewNoticeWeb', array($this, $user, &$content_shortened, &$options)); 196 | 197 | if (!GNUsocial::isAjax()) { 198 | $url = common_local_url('shownotice', array('notice' => $this->stored->id)); 199 | common_redirect($url, 303); 200 | } 201 | 202 | return _('Saved the notice!'); 203 | } 204 | 205 | protected function showContent() 206 | { 207 | if ($this->getInfo() && $this->stored instanceof Notice) { 208 | $this->showNotice($this->stored); 209 | } elseif (!$this->getError()) { 210 | parent::showContent(); 211 | } 212 | } 213 | 214 | /** 215 | * Output a notice 216 | * 217 | * Used to generate the notice code for Ajax results. 218 | * 219 | * @param Notice $notice Notice that was saved 220 | * 221 | * @return void 222 | */ 223 | function showNotice(Notice $notice) 224 | { 225 | $nli = new QuitimNoticeListItem($notice, $this); 226 | $nli->show(); 227 | } 228 | 229 | public function showNoticeForm() 230 | { 231 | // pass 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /actions/quitimnotifications.php: -------------------------------------------------------------------------------- 1 | arg('nickname')); 23 | 24 | $this->user = User::getKV('nickname', $nickname); 25 | $current_user = Profile::current(); 26 | 27 | 28 | if (!$this->user) { 29 | // TRANS: Client error displayed when trying to reply to a non-exsting user. 30 | $this->clientError(_('No such user.')); 31 | } 32 | 33 | if ($this->user->id != $current_user->id) { 34 | // TRANS: Client error displayed when trying to access someone elses notifications 35 | $this->clientError(_('Not available.')); 36 | } 37 | 38 | $profile = $this->user->getProfile(); 39 | 40 | if (!$profile) { 41 | // TRANS: Error message displayed when referring to a user without a profile. 42 | $this->serverError(_('User has no profile.')); 43 | } 44 | 45 | $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; 46 | 47 | common_set_returnto($this->selfUrl()); 48 | 49 | $stream = new NotificationStream($current_user); 50 | 51 | $this->notifications = $stream->getNotifications(($this->page-1) * NOTICES_PER_PAGE, 52 | NOTICES_PER_PAGE + 1, false, false); 53 | 54 | if($this->page > 1 && $this->notifications->N == 0){ 55 | // TRANS: Server error when page not found (404) 56 | $this->serverError(_('No such page.'),$code=404); 57 | } 58 | 59 | return true; 60 | } 61 | 62 | /** 63 | * Handle a request 64 | * 65 | * Just show the page. All args already handled. 66 | * 67 | * @param array $args $_REQUEST data 68 | * 69 | * @return void 70 | */ 71 | function handle($args) 72 | { 73 | parent::handle($args); 74 | $this->showPage(); 75 | } 76 | 77 | /** 78 | * Title of the page 79 | * 80 | * Includes name of user and page number. 81 | * 82 | * @return string title of page 83 | */ 84 | function title() 85 | { 86 | if ($this->page == 1) { 87 | // TRANS: Title for first page of replies for a user. 88 | // TRANS: %s is a user nickname. 89 | return sprintf(_("Notifications for %s"), $this->user->nickname); 90 | } else { 91 | // TRANS: Title for all but the first page of replies for a user. 92 | // TRANS: %1$s is a user nickname, %2$d is a page number. 93 | return sprintf(_('Notifications for %1$s, page %2$d'), 94 | $this->user->nickname, 95 | $this->page); 96 | } 97 | } 98 | 99 | 100 | function showBody() 101 | { 102 | 103 | $current_user = common_current_user(); 104 | 105 | $bodyclasses = 'quitim'; 106 | if($current_user) { 107 | $bodyclasses .= ' user_in'; 108 | } 109 | $this->elementStart('body', array('id' => strtolower($this->trimmed('action')), 'class' => $bodyclasses, 'ontouchstart' => '')); 110 | $this->element('div', array('id' => 'spinner-overlay')); 111 | 112 | $this->elementStart('div', array('id' => 'wrap')); 113 | QuitimFooter::showQuitimFooter(); 114 | 115 | $this->elementStart('div', array('id' => 'header')); 116 | $this->showLogo(); 117 | $this->elementStart('div', array('id' => 'topright')); 118 | $this->element('img', array('id' => 'refresh', 'height' => '30', 'width' => '30', 'src' => Plugin::staticPath('Quitim', 'img/refresh.png'))); 119 | $this->elementEnd('div'); 120 | $this->elementEnd('div'); 121 | 122 | $this->elementStart('div', array('id' => 'core')); 123 | $this->elementStart('div', array('id' => 'aside_primary_wrapper')); 124 | $this->elementStart('div', array('id' => 'content_wrapper')); 125 | $this->elementStart('div', array('id' => 'site_nav_local_views_wrapper')); 126 | 127 | $this->elementStart('div', array('id' => 'content')); 128 | if (common_logged_in()) { 129 | if (Event::handle('StartShowNoticeForm', array($this))) { 130 | $this->showNoticeForm(); 131 | Event::handle('EndShowNoticeForm', array($this)); 132 | } 133 | } 134 | 135 | $this->elementStart('div', array('id' => 'content_inner')); 136 | $this->elementStart('div', array('id' => 'usernotices', 'class' => 'noticestream notification-stream threaded-view')); 137 | $this->elementStart('div', array('id' => 'notices_primary')); 138 | $this->elementStart('ol', array('class' => 'notices notifications')); 139 | 140 | $newstarted=false; 141 | $newended=false; 142 | if($this->notifications->_count > 0) { 143 | foreach($this->notifications->_items as $notification){ 144 | 145 | $first_seen_class = ''; 146 | if(!$newstarted && $notification->is_seen == 0) { 147 | $this->elementStart('li', array('id' => 'new-notifications-start')); 148 | $this->raw(_("New notifications")); 149 | $this->elementEnd('li'); 150 | $newstarted=true; 151 | } 152 | elseif($newstarted && !$newended && $notification->is_seen == 1) { 153 | $newended=true; 154 | $first_seen_class = 'first-seen'; 155 | } 156 | 157 | // mark as seen 158 | if($notification->is_seen == 0) { 159 | $notification->is_seen = 1; 160 | $notification->update(); 161 | $new_notice_class = 'new'; 162 | } 163 | else { 164 | $new_notice_class = ''; 165 | } 166 | 167 | $from_profile = Profile::getKV($notification->from_profile_id); 168 | 169 | // profiles can be deleted or missing or something 170 | if(!$from_profile instanceof Profile) { 171 | continue; 172 | } 173 | 174 | $first_notice_in_conversation = Notice::getKV('id',$notification->first_notice_id_in_conversation); 175 | 176 | $this->elementStart('li', array('id' => 'notice-'.$notification->id, 'class' => 'notice notification '.$new_notice_class.$first_seen_class)); 177 | $this->elementStart('div', array('class' => 'entry-title')); 178 | 179 | if($notification->ntype == "follow") { 180 | $this->showAuthorAndNotificationText($notification, $from_profile, _("is following you")); 181 | } 182 | elseif($notification->ntype == "like") { 183 | $this->showThumb($first_notice_in_conversation); 184 | $this->showAuthorAndNotificationText($notification, $from_profile, _("likes your image")); 185 | } 186 | elseif($notification->ntype == "bourg") { 187 | $this->showThumb($first_notice_in_conversation); 188 | $this->showAuthorAndNotificationText($notification, $from_profile, _("thinks your image is bourgois")); 189 | } 190 | elseif($notification->ntype == "reply") { 191 | $this->showThumb($first_notice_in_conversation); 192 | $comment = Notice::getKV($notification->notice_id); 193 | $this->showAuthorAndNotificationText($notification, $from_profile, _("has commented on your image: ").$comment->rendered); 194 | } 195 | elseif($notification->ntype == "mention") { 196 | $this->showThumb($first_notice_in_conversation); 197 | $comment = Notice::getKV($notification->notice_id); 198 | $this->showAuthorAndNotificationText($notification, $from_profile, _("has mentioned you in a comment: ").$comment->rendered); 199 | } 200 | 201 | $this->elementEnd('div'); 202 | $this->elementEnd('li'); 203 | } 204 | 205 | } 206 | else { 207 | $this->raw(_("No notifications")); 208 | } 209 | 210 | $this->elementEnd('ol'); 211 | $this->elementEnd('div'); 212 | 213 | 214 | 215 | $this->pagination($this->page > 1, $this->notifications->_count > NOTICES_PER_PAGE, 216 | $this->page, 'quitimnotifications', 217 | array('nickname' => $this->user->nickname)); 218 | 219 | 220 | $this->elementEnd('div'); 221 | 222 | $this->elementEnd('div'); 223 | $this->elementEnd('div'); 224 | 225 | 226 | $this->elementEnd('div'); 227 | $this->elementEnd('div'); 228 | $this->elementEnd('div'); 229 | $this->elementEnd('div'); 230 | 231 | $this->elementEnd('div'); 232 | $this->showScripts(); 233 | $this->elementEnd('body'); 234 | } 235 | 236 | /** 237 | * Show the content 238 | * 239 | * A list of notices that are replies to the user, plus pagination. 240 | * 241 | * @return void 242 | */ 243 | function showContent() 244 | { 245 | // 246 | } 247 | 248 | 249 | 250 | function isReadOnly($args) 251 | { 252 | return true; 253 | } 254 | 255 | function showStylesheets() 256 | { 257 | 258 | $this->cssLink(Plugin::staticPath('Quitim', 'css/quitim.css')); 259 | 260 | } 261 | 262 | function showAuthorAndNotificationText($notification, $profile, $notificationtext) 263 | { 264 | $this->elementStart('div', 'author'); 265 | 266 | $this->elementStart('span', 'vcard author'); 267 | 268 | $attrs = array('href' => $profile->profileurl, 269 | 'class' => 'url', 270 | 'title' => $profile->nickname); 271 | 272 | $this->elementStart('a', $attrs); 273 | $this->showAvatar($profile); 274 | $this->text(' '); 275 | $this->element('span',array('class' => 'fn'), $profile->nickname); 276 | $this->elementEnd('a'); 277 | 278 | $this->elementEnd('span'); 279 | $this->elementStart('span', array('class' => 'notificationtext')); 280 | $this->raw($notificationtext); 281 | $this->elementEnd('span'); 282 | $dt = common_date_iso8601($notification->created); 283 | $this->element('abbr', array('class' => 'published','title' => $dt),' · '.common_date_string($notification->created)); 284 | $this->elementEnd('div'); 285 | } 286 | 287 | function showAvatar($profile) 288 | { 289 | 290 | $avatarUrl = $profile->avatarUrl(AVATAR_STREAM_SIZE); 291 | 292 | $this->element('img', array('src' => $avatarUrl, 293 | 'class' => 'avatar photo', 294 | 'width' => AVATAR_STREAM_SIZE, 295 | 'height' => AVATAR_STREAM_SIZE, 296 | 'alt' => 297 | ($profile->fullname) ? 298 | $profile->fullname : 299 | $profile->nickname)); 300 | } 301 | 302 | function showThumb($first_notice_in_conversation) { 303 | $att = $first_notice_in_conversation->attachments(); 304 | foreach ($att as $attachment) { 305 | try { 306 | $thumbnail = $attachment->getThumbnail(); 307 | } catch (Exception $e) { 308 | continue; 309 | } 310 | if ($thumbnail) { 311 | $this->elementStart('a', array('class' => 'thumb', 'href' => common_path('notice/'.$first_notice_in_conversation->id))); 312 | $this->element('img', array('src' => $thumbnail->getUrl(), 'width' => $thumbnail->width, 'height' => $thumbnail->height)); 313 | $this->elementEnd('a'); 314 | break; 315 | } 316 | } 317 | } 318 | 319 | } 320 | -------------------------------------------------------------------------------- /actions/quitimpopular.php: -------------------------------------------------------------------------------- 1 | page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; 26 | 27 | $stream = new PopularNoticeStream(Profile::current()); 28 | $this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE+1); 29 | 30 | return true; 31 | } 32 | 33 | function isReadOnly($args) 34 | { 35 | return true; 36 | } 37 | 38 | function title() 39 | { 40 | return _('Quitim moments'); 41 | } 42 | 43 | protected function handle() 44 | { 45 | 46 | parent::handle(); 47 | 48 | } 49 | 50 | protected function doPost() 51 | { 52 | 53 | } 54 | 55 | public function showPageNotice() 56 | { 57 | 58 | } 59 | 60 | public function showInstructions() 61 | { 62 | 63 | } 64 | 65 | 66 | public function showForm($msg=null, $success=false) 67 | { 68 | 69 | } 70 | 71 | 72 | function showSections() 73 | { 74 | 75 | } 76 | 77 | function showStylesheets() 78 | { 79 | 80 | // We only want quitim stylesheet 81 | $path = Plugin::staticPath('Quitim', ''); 82 | $this->cssLink($path.'css/quitim.css?changed='.date('YmdHis',filemtime(QUITIMDIR.'/css/quitim.css'))); 83 | 84 | 85 | } 86 | 87 | function showBody() 88 | { 89 | 90 | $current_user = common_current_user(); 91 | 92 | $bodyclasses = 'quitim'; 93 | if($current_user) { 94 | $bodyclasses .= ' user_in'; 95 | } else { 96 | $bodyclasses .= ' logged-out'; 97 | } 98 | $this->elementStart('body', array('id' => strtolower($this->trimmed('action')), 'class' => $bodyclasses, 'ontouchstart' => '')); 99 | $this->element('div', array('id' => 'spinner-overlay')); 100 | $this->element('div', array('id' => 'popup-register')); 101 | 102 | $this->elementStart('div', array('id' => 'wrap')); 103 | QuitimFooter::showQuitimFooter(); 104 | 105 | $this->elementStart('div', array('id' => 'header')); 106 | $this->elementStart('a', array('href' => '#top')); 107 | $this->elementStart('h1'); 108 | $this->raw(_('Quitim moments')); 109 | $this->elementEnd('h1'); 110 | $this->elementEnd('a'); 111 | 112 | $this->elementStart('div', array('id' => 'topright')); 113 | $this->elementEnd('div'); 114 | 115 | $this->elementEnd('div'); 116 | 117 | $this->elementStart('div', array('id' => 'core')); 118 | $this->elementStart('div', array('id' => 'aside_primary_wrapper')); 119 | $this->elementStart('div', array('id' => 'content_wrapper')); 120 | $this->elementStart('div', array('id' => 'site_nav_local_views_wrapper')); 121 | 122 | $this->elementStart('div', array('id' => 'content')); 123 | if (common_logged_in()) { 124 | if (Event::handle('StartShowNoticeForm', array($this))) { 125 | $this->showNoticeForm(); 126 | Event::handle('EndShowNoticeForm', array($this)); 127 | } 128 | } 129 | 130 | $this->elementStart('div', array('id' => 'content_inner')); 131 | 132 | $this->elementStart('div', array('id' => 'thumb-thread')); 133 | $this->elementStart('div', array('id' => 'set-thumbnail-view')); 134 | $this->elementEnd('div'); 135 | $this->elementStart('div', array('id' => 'set-threaded-view')); 136 | $this->elementEnd('div'); 137 | $this->elementEnd('div'); 138 | 139 | 140 | $this->elementStart('div', array('id' => 'usernotices', 'class' => 'noticestream thumbnail-view')); 141 | $this->showNoticesWithCommentsAndFavs(); 142 | $this->elementEnd('div'); 143 | 144 | $this->elementEnd('div'); 145 | $this->elementEnd('div'); 146 | 147 | 148 | $this->elementEnd('div'); 149 | $this->elementEnd('div'); 150 | $this->elementEnd('div'); 151 | $this->elementEnd('div'); 152 | 153 | 154 | 155 | $this->elementEnd('div'); 156 | $this->showScripts(); 157 | $this->elementEnd('body'); 158 | } 159 | 160 | 161 | 162 | function showNoticesWithCommentsAndFavs() 163 | { 164 | 165 | $nl = new QuitimThreadedNoticeList($this->notice, $this); 166 | $cnt = $nl->show(); 167 | $this->pagination( 168 | $this->page > 1, $cnt > NOTICES_PER_PAGE, 169 | $this->page, 'quitimfavorited'); 170 | } 171 | 172 | } 173 | -------------------------------------------------------------------------------- /actions/quitimshownotice.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @category Personal 23 | * @package StatusNet 24 | * @author Evan Prodromou 25 | * @copyright 2008-2011 StatusNet, Inc. 26 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 27 | * @link http://status.net/ 28 | */ 29 | 30 | if (!defined('STATUSNET') && !defined('LACONICA')) { 31 | exit(1); 32 | } 33 | 34 | require_once INSTALLDIR.'/lib/personalgroupnav.php'; 35 | require_once INSTALLDIR.'/lib/noticelist.php'; 36 | require_once INSTALLDIR.'/lib/feedlist.php'; 37 | 38 | /** 39 | * Show a single notice 40 | * 41 | * @category Personal 42 | * @package StatusNet 43 | * @author Evan Prodromou 44 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 45 | * @link http://status.net/ 46 | */ 47 | class QuitimShownoticeAction extends Action 48 | { 49 | /** 50 | * Notice object to show 51 | */ 52 | var $notice = null; 53 | 54 | /** 55 | * Profile of the notice object 56 | */ 57 | var $profile = null; 58 | 59 | /** 60 | * Avatar of the profile of the notice object 61 | */ 62 | var $avatar = null; 63 | 64 | /** 65 | * Load attributes based on database arguments 66 | * 67 | * Loads all the DB stuff 68 | * 69 | * @param array $args $_REQUEST array 70 | * 71 | * @return success flag 72 | */ 73 | protected function prepare(array $args=array()) 74 | { 75 | 76 | // conversations redirect here too 77 | if(isset($args['id'])) { 78 | $args['notice'] = $args['id']; 79 | } 80 | 81 | if ($this->boolean('ajax')) { 82 | $this->showAjax(); 83 | } else { 84 | parent::prepare($args); 85 | 86 | $this->notice = $this->getNotice(); 87 | 88 | $cur = common_current_user(); 89 | 90 | if (!$this->notice->inScope($this->scoped)) { 91 | // TRANS: Client exception thrown when trying a view a notice the user has no access to. 92 | throw new ClientException(_('Not available.'), 403); 93 | } 94 | 95 | $this->profile = $this->notice->getProfile(); 96 | 97 | try { 98 | $this->avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE); 99 | } catch (Exception $e) { 100 | $this->avatar = null; 101 | } 102 | } 103 | 104 | return true; 105 | } 106 | 107 | /** 108 | * Fetch the notice to show. This may be overridden by child classes to 109 | * customize what we fetch without duplicating all of the prepare() method. 110 | * 111 | * @return Notice 112 | */ 113 | protected function getNotice() 114 | { 115 | $id = $this->arg('notice'); 116 | 117 | $notice = Notice::getKV('id', $id); 118 | 119 | if (!$notice instanceof Notice) { 120 | // Did we used to have it, and it got deleted? 121 | $deleted = Deleted_notice::getKV($id); 122 | if ($deleted instanceof Deleted_notice) { 123 | // TRANS: Client error displayed trying to show a deleted notice. 124 | $this->clientError(_('Notice deleted.'), 410); 125 | } else { 126 | // TRANS: Client error displayed trying to show a non-existing notice. 127 | $this->clientError(_('No such notice.'), 404); 128 | } 129 | return false; 130 | } 131 | return $notice; 132 | } 133 | 134 | /** 135 | * Is this action read-only? 136 | * 137 | * @return boolean true 138 | */ 139 | function isReadOnly($args) 140 | { 141 | return true; 142 | } 143 | 144 | 145 | /** 146 | * Title of the page 147 | * 148 | * @return string title of the page 149 | */ 150 | function title() 151 | { 152 | $base = $this->profile->getFancyName(); 153 | 154 | // TRANS: Title of the page that shows a notice. 155 | // TRANS: %1$s is a user name, %2$s is the notice creation date/time. 156 | return sprintf(_('%1$s\'s status on %2$s'), 157 | $base, 158 | common_exact_date($this->notice->created)); 159 | } 160 | 161 | /** 162 | * Handle input 163 | * 164 | * Only handles get, so just show the page. 165 | * 166 | * @param array $args $_REQUEST data (unused) 167 | * 168 | * @return void 169 | */ 170 | protected function handle() 171 | { 172 | parent::handle(); 173 | 174 | if ($this->boolean('ajax')) { 175 | $this->showAjax(); 176 | } else { 177 | if ($this->notice->is_local == Notice::REMOTE) { 178 | if (!empty($this->notice->url)) { 179 | $target = $this->notice->url; 180 | } else if (!empty($this->notice->uri) && preg_match('/^https?:/', $this->notice->uri)) { 181 | // Old OMB posts saved the remote URL only into the URI field. 182 | $target = $this->notice->uri; 183 | } else { 184 | // Shouldn't happen. 185 | $target = false; 186 | } 187 | if ($target && $target != $this->selfUrl()) { 188 | // common_redirect($target, 301); 189 | } 190 | } 191 | $this->showPage(); 192 | } 193 | } 194 | 195 | /** 196 | * Fill the content area of the page 197 | * 198 | * Shows a single notice list item. 199 | * 200 | * @return void 201 | */ 202 | function showContent() 203 | { 204 | // 205 | } 206 | 207 | 208 | function showSections() 209 | { 210 | 211 | } 212 | 213 | function showStylesheets() 214 | { 215 | 216 | // We only want quitim stylesheet 217 | $path = Plugin::staticPath('Quitim',''); 218 | $this->cssLink($path.'css/quitim.css?changed='.date('YmdHis',filemtime(QUITIMDIR.'/css/quitim.css'))); 219 | 220 | 221 | } 222 | 223 | function showBody() 224 | { 225 | 226 | $current_user = common_current_user(); 227 | 228 | $bodyclasses = 'quitim'; 229 | if($current_user) { 230 | $bodyclasses .= ' user_in'; 231 | } 232 | if($current_user->id == $this->profile->id) { 233 | $bodyclasses .= ' me'; 234 | } 235 | $this->elementStart('body', array('id' => strtolower($this->trimmed('action')), 'class' => $bodyclasses, 'ontouchstart' => '')); 236 | $this->element('div', array('id' => 'spinner-overlay')); 237 | 238 | $this->elementStart('div', array('id' => 'wrap')); 239 | 240 | $this->elementStart('div', array('id' => 'header')); 241 | $this->showLogo(); 242 | $this->elementStart('div', array('id' => 'topright')); 243 | $this->element('img', array('id' => 'refresh', 'height' => '30', 'width' => '30', 'src' => Plugin::staticPath('Quitim', 'img/refresh.png'))); 244 | $this->elementEnd('div'); 245 | $this->elementEnd('div'); 246 | 247 | $this->elementStart('div', array('id' => 'core')); 248 | $this->elementStart('div', array('id' => 'aside_primary_wrapper')); 249 | $this->elementStart('div', array('id' => 'content_wrapper')); 250 | $this->elementStart('div', array('id' => 'site_nav_local_views_wrapper')); 251 | 252 | $this->elementStart('div', array('id' => 'content')); 253 | if (common_logged_in()) { 254 | if (Event::handle('StartShowNoticeForm', array($this))) { 255 | $this->showNoticeForm(); 256 | Event::handle('EndShowNoticeForm', array($this)); 257 | } 258 | } 259 | 260 | $this->elementStart('div', array('id' => 'content_inner')); 261 | 262 | $this->elementStart('div', array('id' => 'usernotices', 'class' => 'noticestream threaded-view')); 263 | $this->showNoticesWithCommentsAndFavs(); 264 | $this->elementEnd('div'); 265 | 266 | $this->elementEnd('div'); 267 | $this->elementEnd('div'); 268 | 269 | 270 | $this->elementEnd('div'); 271 | $this->elementEnd('div'); 272 | $this->elementEnd('div'); 273 | $this->elementEnd('div'); 274 | 275 | QuitimFooter::showQuitimFooter(); 276 | 277 | $this->elementEnd('div'); 278 | $this->showScripts(); 279 | $this->elementEnd('body'); 280 | } 281 | 282 | 283 | function showProfileBlock() 284 | { 285 | $block = new QuitimAccountProfileBlock($this, $this->profile); 286 | $block->show(); 287 | } 288 | 289 | 290 | function showNoticesWithCommentsAndFavs() 291 | { 292 | if(isset($this->args['id'])) { // full conversations 293 | $nl = new QuitimFullThreadedNoticeList($this->notice, $this, $this->profile); 294 | } 295 | else { // notices, i.e. collapsed conversations 296 | $nl = new QuitimThreadedNoticeList($this->notice, $this, $this->profile); 297 | } 298 | $cnt = $nl->show(); 299 | if (0 == $cnt) { 300 | $this->showEmptyListMessage(); 301 | } 302 | } 303 | 304 | 305 | /** 306 | * Don't show page notice 307 | * 308 | * @return void 309 | */ 310 | function showPageNoticeBlock() 311 | { 312 | } 313 | 314 | /** 315 | * Don't show aside 316 | * 317 | * @return void 318 | */ 319 | function showAside() { 320 | } 321 | 322 | /** 323 | * Extra content 324 | * 325 | * We show the microid(s) for the author, if any. 326 | * 327 | * @return void 328 | */ 329 | function extraHead() 330 | { 331 | $user = User::getKV($this->profile->id); 332 | 333 | if (!$user) { 334 | return; 335 | } 336 | 337 | if ($user->emailmicroid && $user->email && $this->notice->uri) { 338 | $id = new Microid('mailto:'. $user->email, 339 | $this->notice->uri); 340 | $this->element('meta', array('name' => 'microid', 341 | 'content' => $id->toString())); 342 | } 343 | 344 | // Extras to aid in sharing notices to Facebook 345 | $avatarUrl = $this->profile->avatarUrl(AVATAR_PROFILE_SIZE); 346 | $this->element('meta', array('property' => 'og:image', 347 | 'content' => $avatarUrl)); 348 | $this->element('meta', array('property' => 'og:description', 349 | 'content' => $this->notice->content)); 350 | } 351 | 352 | 353 | function showAjax() 354 | { 355 | $this->startHTML('text/xml;charset=utf-8'); 356 | $this->elementStart('head'); 357 | // TRANS: Title for conversation page. 358 | $this->element('title', null, _m('TITLE','Notice')); 359 | $this->elementEnd('head'); 360 | $this->elementStart('body'); 361 | $ct = new QuitimFullThreadedNoticeList($this->notice, $this, $this->scoped); 362 | $cnt = $ct->show(); 363 | $this->elementEnd('body'); 364 | $this->endHTML(); 365 | } 366 | 367 | } 368 | 369 | // @todo FIXME: Class documentation missing. 370 | class SingleNoticeItem extends DoFollowListItem 371 | { 372 | function avatarSize() 373 | { 374 | return AVATAR_STREAM_SIZE; 375 | } 376 | } 377 | -------------------------------------------------------------------------------- /actions/quitimsubscribe.php: -------------------------------------------------------------------------------- 1 | . 20 | * 21 | * PHP version 5 22 | * 23 | * @category Action 24 | * @package StatusNet 25 | * @author Evan Prodromou 26 | * @copyright 2008-2010 StatusNet, Inc. 27 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 28 | * @link http://status.net/ 29 | */ 30 | 31 | if (!defined('STATUSNET')) { 32 | exit(1); 33 | } 34 | 35 | /** 36 | * Subscription action 37 | * 38 | * Subscribing to a profile. Likely to work for OStatus profiles. 39 | * 40 | * Takes parameters: 41 | * 42 | * - subscribeto: a profile ID 43 | * - token: session token to prevent CSRF attacks 44 | * - ajax: boolean; whether to return Ajax or full-browser results 45 | * 46 | * Only works if the current user is logged in. 47 | * 48 | * @category Action 49 | * @package StatusNet 50 | * @author Evan Prodromou 51 | * @copyright 2008-2010 StatusNet, Inc. 52 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 53 | * @link http://status.net/ 54 | */ 55 | class QuitimSubscribeAction extends Action 56 | { 57 | var $user; 58 | var $other; 59 | 60 | /** 61 | * Check pre-requisites and instantiate attributes 62 | * 63 | * @param Array $args array of arguments (URL, GET, POST) 64 | * 65 | * @return boolean success flag 66 | */ 67 | function prepare($args) 68 | { 69 | parent::prepare($args); 70 | 71 | // Only allow POST requests 72 | 73 | if ($_SERVER['REQUEST_METHOD'] != 'POST') { 74 | // TRANS: Client error displayed trying to perform any request method other than POST. 75 | // TRANS: Do not translate POST. 76 | $this->clientError(_('This action only accepts POST requests.')); 77 | } 78 | 79 | // CSRF protection 80 | 81 | $token = $this->trimmed('token'); 82 | 83 | if (!$token || $token != common_session_token()) { 84 | // TRANS: Client error displayed when the session token is not okay. 85 | $this->clientError(_('There was a problem with your session token.'. 86 | ' Try again, please.')); 87 | } 88 | 89 | // Only for logged-in users 90 | 91 | $this->user = common_current_user(); 92 | 93 | if (empty($this->user)) { 94 | // TRANS: Error message displayed when trying to perform an action that requires a logged in user. 95 | $this->clientError(_('Not logged in.')); 96 | } 97 | 98 | // Profile to subscribe to 99 | 100 | $other_id = $this->arg('subscribeto'); 101 | 102 | $this->other = Profile::getKV('id', $other_id); 103 | 104 | if (empty($this->other)) { 105 | // TRANS: Client error displayed trying to subscribe to a non-existing profile. 106 | $this->clientError(_('No such profile.')); 107 | } 108 | 109 | return true; 110 | } 111 | 112 | /** 113 | * Handle request 114 | * 115 | * Does the subscription and returns results. 116 | * 117 | * @param Array $args unused. 118 | * 119 | * @return void 120 | */ 121 | function handle($args) 122 | { 123 | // Throws exception on error 124 | 125 | $sub = Subscription::ensureStart($this->user->getProfile(), 126 | $this->other); 127 | 128 | if ($this->boolean('ajax')) { 129 | $this->startHTML('text/xml;charset=utf-8'); 130 | $this->elementStart('head'); 131 | // TRANS: Page title when subscription succeeded. 132 | $this->element('title', null, _('Subscribed')); 133 | $this->elementEnd('head'); 134 | $this->elementStart('body'); 135 | if ($sub instanceof Subscription) { 136 | $form = new QuitimUnsubscribeForm($this, $this->other); 137 | } else { 138 | $form = new CancelSubscriptionForm($this, $this->other); 139 | } 140 | $form->show(); 141 | $this->elementEnd('body'); 142 | $this->endHTML(); 143 | } else { 144 | $url = common_local_url('subscriptions', 145 | array('nickname' => $this->user->nickname)); 146 | common_redirect($url, 303); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /actions/quitimunsubscribe.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Robin Millette 11 | * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 12 | * @link http://status.net/ 13 | * 14 | * StatusNet - the distributed open-source microblogging tool 15 | * Copyright (C) 2008, 2009, StatusNet, Inc. 16 | * 17 | * This program is free software: you can redistribute it and/or modify 18 | * it under the terms of the GNU Affero General Public License as published by 19 | * the Free Software Foundation, either version 3 of the License, or 20 | * (at your option) any later version. 21 | * 22 | * This program is distributed in the hope that it will be useful, 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | * GNU Affero General Public License for more details. 26 | * 27 | * You should have received a copy of the GNU Affero General Public License 28 | * along with this program. If not, see . 29 | */ 30 | 31 | if (!defined('STATUSNET') && !defined('LACONICA')) { 32 | exit(1); 33 | } 34 | 35 | /** 36 | * Unsubscribe handler 37 | * 38 | * @category Action 39 | * @package StatusNet 40 | * @author Evan Prodromou 41 | * @author Robin Millette 42 | * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 43 | * @link http://status.net/ 44 | */ 45 | class QuitimUnsubscribeAction extends Action 46 | { 47 | function handle($args) 48 | { 49 | parent::handle($args); 50 | if (!common_logged_in()) { 51 | // TRANS: Error message displayed when trying to perform an action that requires a logged in user. 52 | $this->clientError(_('Not logged in.')); 53 | } 54 | 55 | if ($_SERVER['REQUEST_METHOD'] != 'POST') { 56 | common_redirect(common_local_url('subscriptions', 57 | array('nickname' => $this->scoped->nickname))); 58 | } 59 | 60 | /* Use a session token for CSRF protection. */ 61 | 62 | $token = $this->trimmed('token'); 63 | 64 | if (!$token || $token != common_session_token()) { 65 | // TRANS: Client error displayed when the session token does not match or is not given. 66 | $this->clientError(_('There was a problem with your session token. ' . 67 | 'Try again, please.')); 68 | } 69 | 70 | $other_id = $this->arg('unsubscribeto'); 71 | 72 | if (!$other_id) { 73 | // TRANS: Client error displayed when trying to unsubscribe without providing a profile ID. 74 | $this->clientError(_('No profile ID in request.')); 75 | } 76 | 77 | $other = Profile::getKV('id', $other_id); 78 | 79 | if (!($other instanceof Profile)) { 80 | // TRANS: Client error displayed when trying to unsubscribe while providing a non-existing profile ID. 81 | $this->clientError(_('No profile with that ID.')); 82 | } 83 | 84 | try { 85 | Subscription::cancel($this->scoped, $other); 86 | } catch (Exception $e) { 87 | $this->clientError($e->getMessage()); 88 | } 89 | 90 | if ($this->boolean('ajax')) { 91 | $this->startHTML('text/xml;charset=utf-8'); 92 | $this->elementStart('head'); 93 | // TRANS: Page title for page to unsubscribe. 94 | $this->element('title', null, _('Unsubscribed')); 95 | $this->elementEnd('head'); 96 | $this->elementStart('body'); 97 | $subscribe = new QuitimSubscribeForm($this, $other); 98 | $subscribe->show(); 99 | $this->elementEnd('body'); 100 | $this->endHTML(); 101 | } else { 102 | common_redirect(common_local_url('subscriptions', array('nickname' => $this->scoped->nickname)), 303); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /actions/quitimuserstream.php: -------------------------------------------------------------------------------- 1 | target->getFancyName(); 25 | } 26 | 27 | function showSections() 28 | { 29 | 30 | } 31 | 32 | function showStylesheets() 33 | { 34 | 35 | // We only want quitim stylesheet 36 | $path = Plugin::staticPath('Quitim',''); 37 | $this->cssLink($path.'css/quitim.css?changed='.date('YmdHis',filemtime(QUITIMDIR.'/css/quitim.css'))); 38 | 39 | 40 | } 41 | 42 | function showBody() 43 | { 44 | 45 | $this->notice = $this->getNoticesButNotReplies(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); 46 | 47 | $current_user = common_current_user(); 48 | 49 | $bodyclasses = 'quitim'; 50 | if($current_user) { 51 | $bodyclasses .= ' user_in'; 52 | } 53 | if($current_user->id == $this->target->id) { 54 | $bodyclasses .= ' me'; 55 | } 56 | $this->elementStart('body', array('id' => strtolower($this->trimmed('action')), 'class' => $bodyclasses, 'ontouchstart' => '')); 57 | $this->element('div', array('id' => 'spinner-overlay')); 58 | 59 | $this->elementStart('div', array('id' => 'wrap')); 60 | QuitimFooter::showQuitimFooter(); 61 | 62 | $this->elementStart('div', array('id' => 'header')); 63 | $this->showLogo(); 64 | 65 | $this->elementStart('a', array('href' => '#top')); 66 | $this->elementStart('h1'); 67 | $this->raw($this->target->getNickname()); 68 | $this->elementEnd('h1'); 69 | $this->elementEnd('a'); 70 | $this->elementEnd('div'); 71 | 72 | $this->elementStart('div', array('id' => 'core')); 73 | $this->elementStart('div', array('id' => 'aside_primary_wrapper')); 74 | $this->elementStart('div', array('id' => 'content_wrapper')); 75 | $this->elementStart('div', array('id' => 'site_nav_local_views_wrapper')); 76 | 77 | $this->elementStart('div', array('id' => 'content')); 78 | if (common_logged_in()) { 79 | if (Event::handle('StartShowNoticeForm', array($this))) { 80 | $this->showNoticeForm(); 81 | Event::handle('EndShowNoticeForm', array($this)); 82 | } 83 | } 84 | 85 | $this->elementStart('div', array('id' => 'content_inner')); 86 | 87 | $this->elementStart('div', array('id' => 'profileblock')); 88 | $this->showProfileBlock(); 89 | 90 | // subscribe form if logged in and not me 91 | if(common_current_user() && ($current_user->id != $this->target->id)) { 92 | $this->elementStart('div', 'profile_subscribe'); 93 | 94 | if ($current_user->isSubscribed($this->target)) { 95 | $usff = new QuitimUnsubscribeForm($this, $this->target); 96 | $usff->show(); 97 | } else if ($current_user->hasPendingSubscription($this->target)) { 98 | $sff = new CancelSubscriptionForm($this, $this->target); 99 | $sff->show(); 100 | } else { 101 | $sff = new QuitimSubscribeForm($this, $this->target); 102 | $sff->show(); 103 | } 104 | $this->elementEnd('div'); 105 | } else { 106 | if (Event::handle('StartProfileRemoteSubscribe', array($this, $this->target))) { 107 | Event::handle('EndProfileRemoteSubscribe', array($this, $this->target)); 108 | } 109 | } 110 | 111 | 112 | $this->elementStart('h2', array('id'=>'noticecountlink')); 113 | // TRANS: H2 text for user subscription statistics. 114 | $this->element('a', array('href' => common_local_url('showstream', array('nickname' => $this->target->getNickname())),'class' => ''), _('Images')); 115 | $this->text(' '); 116 | $this->text(QuitimImageNoticeCount::imageNoticeCount($this->target)); 117 | $this->elementEnd('h2'); 118 | 119 | 120 | $this->elementStart('h2', array('id'=>'subscriberscountlink')); 121 | // TRANS: H2 text for user subscriber statistics. 122 | $this->element('a', array('href' => common_local_url('quitimfollowers', array('nickname' => $this->target->getNickname())),'class' => ''), _('Followers')); 123 | $this->text(' '); 124 | $this->text($this->target->subscriberCount()); 125 | $this->elementEnd('h2'); 126 | 127 | $this->elementStart('h2', array('id'=>'subscriptionscountlink')); 128 | // TRANS: H2 text for user subscription statistics. 129 | $this->element('a', array('href' => common_local_url('quitimfollowing', array('nickname' => $this->target->getNickname())),'class' => ''), _('Following')); 130 | $this->text(' '); 131 | $this->text($this->target->subscriptionCount()); 132 | $this->elementEnd('h2'); 133 | 134 | $this->elementEnd('div'); 135 | 136 | 137 | $this->elementStart('div', array('id' => 'thumb-thread')); 138 | $this->elementStart('div', array('id' => 'set-thumbnail-view')); 139 | $this->elementEnd('div'); 140 | $this->elementStart('div', array('id' => 'set-threaded-view')); 141 | $this->elementEnd('div'); 142 | $this->elementEnd('div'); 143 | 144 | 145 | $this->elementStart('div', array('id' => 'usernotices', 'class' => 'noticestream thumbnail-view')); 146 | if($this->notice->N>0) { 147 | $this->showNoticesWithCommentsAndFavs(); 148 | } 149 | else { 150 | // show welcome 151 | } 152 | $this->elementEnd('div'); 153 | 154 | $this->elementEnd('div'); 155 | $this->elementEnd('div'); 156 | 157 | 158 | $this->elementEnd('div'); 159 | $this->elementEnd('div'); 160 | $this->elementEnd('div'); 161 | $this->elementEnd('div'); 162 | 163 | $this->elementEnd('div'); 164 | $this->showScripts(); 165 | $this->elementEnd('body'); 166 | } 167 | 168 | 169 | function showProfileBlock() 170 | { 171 | $block = new QuitimAccountProfileBlock($this, $this->target); 172 | $block->show(); 173 | } 174 | 175 | 176 | function showNoticesWithCommentsAndFavs() 177 | { 178 | $nl = new QuitimThreadedNoticeList($this->notice, $this, $this->target); 179 | $cnt = $nl->show(); 180 | if (0 == $cnt) { 181 | $this->showEmptyListMessage(); 182 | } 183 | $this->pagination( 184 | $this->page > 1, $cnt > NOTICES_PER_PAGE, 185 | $this->page, 'quitimuserstream', array('nickname' => $this->target->getNickname()) 186 | ); 187 | } 188 | 189 | 190 | function getFeeds() 191 | { 192 | if (!empty($this->tag)) { 193 | return array(new Feed(Feed::RSS1, 194 | common_local_url('userrss', 195 | array('nickname' => $this->target->getNickname(), 196 | 'tag' => $this->tag)), 197 | // TRANS: Title for link to notice feed. 198 | // TRANS: %1$s is a user nickname, %2$s is a hashtag. 199 | sprintf(_('Notice feed for %1$s tagged %2$s (RSS 1.0)'), 200 | $this->target->getNickname(), $this->tag))); 201 | } 202 | 203 | return array(new Feed(Feed::JSON, 204 | common_local_url('ApiTimelineUser', 205 | array( 206 | 'id' => $this->target->getID(), 207 | 'format' => 'as')), 208 | // TRANS: Title for link to notice feed. 209 | // TRANS: %s is a user nickname. 210 | sprintf(_('Notice feed for %s (Activity Streams JSON)'), 211 | $this->target->getNickname())), 212 | new Feed(Feed::RSS1, 213 | common_local_url('userrss', 214 | array('nickname' => $this->target->getNickname())), 215 | // TRANS: Title for link to notice feed. 216 | // TRANS: %s is a user nickname. 217 | sprintf(_('Notice feed for %s (RSS 1.0)'), 218 | $this->target->getNickname())), 219 | new Feed(Feed::RSS2, 220 | common_local_url('ApiTimelineUser', 221 | array( 222 | 'id' => $this->target->getID(), 223 | 'format' => 'rss')), 224 | // TRANS: Title for link to notice feed. 225 | // TRANS: %s is a user nickname. 226 | sprintf(_('Notice feed for %s (RSS 2.0)'), 227 | $this->target->getNickname())), 228 | new Feed(Feed::ATOM, 229 | common_local_url('ApiTimelineUser', 230 | array( 231 | 'id' => $this->target->getID(), 232 | 'format' => 'atom')), 233 | // TRANS: Title for link to notice feed. 234 | // TRANS: %s is a user nickname. 235 | sprintf(_('Notice feed for %s (Atom)'), 236 | $this->target->getNickname())), 237 | new Feed(Feed::FOAF, 238 | common_local_url('foaf', array('nickname' => 239 | $this->target->getNickname())), 240 | // TRANS: Title for link to notice feed. FOAF stands for Friend of a Friend. 241 | // TRANS: More information at http://www.foaf-project.org. %s is a user nickname. 242 | sprintf(_('FOAF for %s'), $this->target->getNickname()))); 243 | } 244 | 245 | function extraHead() 246 | { 247 | if ($this->target->bio) { 248 | $this->element('meta', array('name' => 'description', 249 | 'content' => $this->target->bio)); 250 | } 251 | 252 | if ($this->user->emailmicroid && $this->target->getUser()->email) { 253 | $id = new Microid('mailto:'.$this->target->getUser()->email, 254 | $this->selfUrl()); 255 | $this->element('meta', array('name' => 'microid', 256 | 'content' => $id->toString())); 257 | } 258 | 259 | // See https://wiki.mozilla.org/Microsummaries 260 | 261 | $this->element('link', array('rel' => 'microsummary', 262 | 'href' => common_local_url('microsummary', 263 | array('nickname' => $this->target->getNickname())))); 264 | 265 | $rsd = common_local_url('rsd', 266 | array('nickname' => $this->target->getNickname())); 267 | 268 | // RSD, http://tales.phrasewise.com/rfc/rsd 269 | $this->element('link', array('rel' => 'EditURI', 270 | 'type' => 'application/rsd+xml', 271 | 'href' => $rsd)); 272 | 273 | if ($this->page != 1) { 274 | $this->element('link', array('rel' => 'canonical', 275 | 'href' => $this->target->getUrl())); 276 | } 277 | } 278 | 279 | /** 280 | * Get notices but not replies 281 | * 282 | * @return array notices 283 | */ 284 | function getNoticesButNotReplies($offset, $limit, $since_id=0, $max_id=0) 285 | { 286 | 287 | $notice = new Notice(); 288 | 289 | $notice->profile_id = $this->target->id; 290 | 291 | $notice->selectAdd(); 292 | $notice->selectAdd('id'); 293 | 294 | Notice::addWhereSinceId($notice, $since_id); 295 | Notice::addWhereMaxId($notice, $max_id); 296 | $notice->whereAdd("(reply_to IS NULL)"); 297 | 298 | $notice->orderBy('created DESC, id DESC'); 299 | 300 | if (!is_null($offset)) { 301 | $notice->limit($offset, $limit); 302 | } 303 | 304 | $notice->find(); 305 | 306 | $ids = array(); 307 | 308 | while ($notice->fetch()) { 309 | $ids[] = $notice->id; 310 | } 311 | 312 | return Notice::multiGet('id', $ids); 313 | } 314 | 315 | } 316 | 317 | 318 | class QuitimAccountProfileBlock extends AccountProfileBlock 319 | { 320 | function showTags() 321 | { 322 | // don't show tags 323 | } 324 | } 325 | 326 | 327 | class QuitimImageNoticeCount extends Notice 328 | { 329 | function imageNoticeCount($profile) 330 | { 331 | $c = Cache::instance(); 332 | 333 | if (!empty($c)) { 334 | $cnt = $c->get(Cache::key('profile:image_notice_count:'.$profile->id)); 335 | if (is_integer($cnt)) { 336 | return (int) $cnt; 337 | } 338 | } 339 | 340 | $notices = new Notice(); 341 | $notices->profile_id = $profile->id; 342 | $notices->reply_to = 'NULL'; // only non-replies 343 | $cnt = (int) $notices->count('distinct id'); 344 | 345 | if (!empty($c)) { 346 | $c->set(Cache::key('profile:image_notice_count:'.$profile->id), $cnt); 347 | } 348 | 349 | return $cnt; 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /classes/ChronologicalInboxStream.php: -------------------------------------------------------------------------------- 1 | . 22 | * 23 | * @category NoticeStream 24 | * @package StatusNet 25 | * @author Evan Prodromou 26 | * @author Mikael Nordfeldth 27 | * @copyright 2011 StatusNet, Inc. 28 | * @copyright 2014 Free Software Foundation, Inc. 29 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 30 | * @link http://status.net/ 31 | */ 32 | 33 | if (!defined('GNUSOCIAL') && !defined('STATUSNET')) { exit(1); } 34 | 35 | /** 36 | * Stream of notices for a profile's "all" feed 37 | * 38 | * @category General 39 | * @package StatusNet 40 | * @author Evan Prodromou 41 | * @author Mikael Nordfeldth 42 | * @copyright 2011 StatusNet, Inc. 43 | * @copyright 2014 Free Software Foundation, Inc. 44 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 45 | * @link http://status.net/ 46 | */ 47 | class ChronologicalInboxStream extends ScopingNoticeStream 48 | { 49 | /** 50 | * Constructor 51 | * 52 | * @param Profile $target Profile to get a stream for 53 | * @param Profile $scoped Currently scoped profile (if null, it is fetched) 54 | */ 55 | function __construct(Profile $target, Profile $scoped=null) 56 | { 57 | if ($scoped === null) { 58 | $scoped = Profile::current(); 59 | } 60 | // FIXME: we don't use CachingNoticeStream - but maybe we should? 61 | parent::__construct(new CachingNoticeStream(new QuitimRawInboxNoticeStream($target), 'quitimprofileall'), $scoped); 62 | } 63 | } 64 | 65 | /** 66 | * Raw stream of notices for the target's inbox 67 | * 68 | * @category General 69 | * @package StatusNet 70 | * @author Evan Prodromou 71 | * @copyright 2011 StatusNet, Inc. 72 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 73 | * @link http://status.net/ 74 | */ 75 | class QuitimRawInboxNoticeStream extends NoticeStream 76 | { 77 | protected $target = null; 78 | protected $inbox = null; 79 | 80 | /** 81 | * Constructor 82 | * 83 | * @param Profile $target Profile to get a stream for 84 | */ 85 | function __construct(Profile $target) 86 | { 87 | $this->target = $target; 88 | } 89 | 90 | /** 91 | * Get IDs in a range 92 | * 93 | * @param int $offset Offset from start 94 | * @param int $limit Limit of number to get 95 | * @param int $since_id Since this notice 96 | * @param int $max_id Before this notice 97 | * 98 | * @return Array IDs found 99 | */ 100 | function getNoticeIds($offset, $limit, $since_id, $max_id) 101 | { 102 | $notice = new Notice(); 103 | $notice->selectAdd(); 104 | $notice->selectAdd('id'); 105 | $notice->whereAdd('reply_to IS NULL'); 106 | $notice->whereAdd(sprintf('notice.created > "%s"', $notice->escape($this->target->created))); 107 | // Reply:: is a table of mentions 108 | // Subscription:: is a table of subscriptions (every user is subscribed to themselves) 109 | $notice->whereAdd( 110 | sprintf('notice.id IN (SELECT notice_id FROM reply WHERE profile_id=%1$d) ' . 111 | 'OR notice.profile_id IN (SELECT subscribed FROM subscription WHERE subscriber=%1$d) ' . 112 | 'OR notice.id IN (SELECT notice_id FROM group_inbox WHERE group_id IN (SELECT group_id FROM group_member WHERE profile_id=%1$d))' . 113 | 'OR notice.id IN (SELECT notice_id FROM attention WHERE profile_id=%1$d)', 114 | $this->target->id) 115 | ); 116 | $notice->limit($offset, $limit); 117 | $notice->orderBy('notice.created DESC'); 118 | 119 | if (!$notice->find()) { 120 | return array(); 121 | } 122 | 123 | $ids = $notice->fetchAll('id'); 124 | 125 | return $ids; 126 | } 127 | 128 | function getNotices($offset, $limit, $sinceId, $maxId) 129 | { 130 | $all = array(); 131 | 132 | do { 133 | 134 | $ids = $this->getNoticeIds($offset, $limit, $sinceId, $maxId); 135 | 136 | $notices = Notice::pivotGet('id', $ids); 137 | 138 | // By default, takes out false values 139 | 140 | $notices = array_filter($notices); 141 | 142 | $all = array_merge($all, $notices); 143 | 144 | if (count($notices < count($ids))) { 145 | $offset += $limit; 146 | $limit -= count($notices); 147 | } 148 | 149 | } while (count($notices) < count($ids) && count($ids) > 0); 150 | 151 | return new ArrayWrapper($all); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /classes/NotificationStream.php: -------------------------------------------------------------------------------- 1 | target = $target; 22 | } 23 | 24 | /** 25 | * Get IDs in a range 26 | * 27 | * @param int $offset Offset from start 28 | * @param int $limit Limit of number to get 29 | * @param int $since_id Since this notice 30 | * @param int $max_id Before this notice 31 | * 32 | * @return Array IDs found 33 | */ 34 | function getNotificationIds($offset, $limit, $since_id, $max_id) 35 | { 36 | $notification = new QuitimNotification(); 37 | $notification->selectAdd(); 38 | $notification->selectAdd('id'); 39 | $notification->whereAdd(sprintf('quitimnotification.to_profile_id = "%s"', $notification->escape($this->target->id))); 40 | $notification->whereAdd(sprintf('quitimnotification.created > "%s"', $notification->escape($this->target->created))); 41 | $notification->limit($offset, $limit); 42 | $notification->orderBy('quitimnotification.created DESC'); 43 | 44 | if (!$notification->find()) { 45 | return array(); 46 | } 47 | 48 | $ids = $notification->fetchAll('id'); 49 | 50 | return $ids; 51 | } 52 | 53 | function getNotifications($offset, $limit, $sinceId, $maxId) 54 | { 55 | $all = array(); 56 | 57 | do { 58 | 59 | $ids = $this->getNotificationIds($offset, $limit, $sinceId, $maxId); 60 | 61 | $notifications = QuitimNotification::pivotGet('id', $ids); 62 | 63 | // By default, takes out false values 64 | 65 | $notifications = array_filter($notifications); 66 | 67 | $all = array_merge($all, $notifications); 68 | 69 | if (count($notifications < count($ids))) { 70 | $offset += $limit; 71 | $limit -= count($notifications); 72 | } 73 | 74 | } while (count($notifications) < count($ids) && count($ids) > 0); 75 | 76 | return new ArrayWrapper($all); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /classes/QuitimFooter.php: -------------------------------------------------------------------------------- 1 | . 18 | * 19 | * @author Hannes Mannerheim 20 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 21 | * 22 | */ 23 | 24 | if (!defined('GNUSOCIAL') && !defined('STATUSNET')) { exit(1); } 25 | 26 | class QuitimFooter 27 | { 28 | function showQuitimFooter() { 29 | $current_user = common_current_user(); 30 | if($current_user) { 31 | $homeurl = common_local_url('all', array('nickname' => $current_user->nickname)); 32 | $profileurl = common_local_url('quitimuserstream', array('nickname' => $current_user->nickname)); 33 | $popularurl = common_local_url('quitimfavorited'); 34 | $notificationsurl = common_local_url('quitimnotifications', array('nickname' => $current_user->nickname)); 35 | $this->elementStart('div', array('id' => 'fixed-footer')); 36 | $this->elementStart('a', (strtolower($this->trimmed('action')) == 'quitimall') ? array('id' => 'home-all','class' => 'active','href' => $homeurl) : array('id' => 'home-all','href' => $homeurl)); 37 | $this->elementStart('div'); 38 | $this->elementStart('div'); 39 | $this->elementEnd('div'); 40 | $this->elementEnd('div'); 41 | $this->elementEnd('a'); 42 | $this->elementStart('a', (strtolower($this->trimmed('action')) == 'quitimfavorited') ? array('id' => 'popular','class' => 'active','href' => $popularurl) : array('id' => 'popular','href' => $popularurl)); 43 | $this->elementStart('div'); 44 | $this->elementStart('div'); 45 | $this->elementEnd('div'); 46 | $this->elementEnd('div'); 47 | $this->elementEnd('a'); 48 | $this->elementStart('a', array('id' => 'camera')); 49 | $this->elementStart('div'); 50 | $this->elementStart('div'); 51 | $this->elementEnd('div'); 52 | $this->elementEnd('div'); 53 | $this->elementEnd('a'); 54 | $this->elementStart('a', (strtolower($this->trimmed('action')) == 'quitimnotifications') ? array('id' => 'notifications','class' => 'active', 'href' => $notificationsurl) : array('id' => 'notifications','href' => $notificationsurl)); 55 | $this->elementStart('div'); 56 | $this->elementStart('div'); 57 | $this->elementEnd('div'); 58 | $this->elementEnd('div'); 59 | $this->elementEnd('a'); 60 | $this->elementStart('a', (strtolower($this->trimmed('action')) == 'quitimuserstream') ? array('id' => 'my-profile','class' => 'active', 'href' => $profileurl) : array('id' => 'my-profile','href' => $profileurl)); 61 | $this->elementStart('div'); 62 | $this->elementStart('div'); 63 | $this->elementEnd('div'); 64 | $this->elementEnd('div'); 65 | $this->elementEnd('a'); 66 | $this->elementEnd('div'); 67 | } 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /classes/QuitimFullThreadedNoticeList.php: -------------------------------------------------------------------------------- 1 | . 22 | * 23 | * @category Cache 24 | * @package StatusNet 25 | * @author Evan Prodromou 26 | * @copyright 2011 StatusNet, Inc. 27 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 28 | * @link http://status.net/ 29 | */ 30 | 31 | if (!defined('STATUSNET')) { 32 | // This check helps protect against security problems; 33 | // your code file can't be executed directly from the web. 34 | exit(1); 35 | } 36 | 37 | /** 38 | * A threaded notice list that shows all notices 39 | * 40 | * @category General 41 | * @package StatusNet 42 | * @author Evan Prodromou 43 | * @author Brion Vibber 44 | * @copyright 2011 StatusNet, Inc. 45 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 46 | * @link http://status.net/ 47 | */ 48 | 49 | class QuitimFullThreadedNoticeList extends QuitimThreadedNoticeList 50 | { 51 | function newListItem($notice) 52 | { 53 | return new QuitimFullThreadedNoticeListItem($notice, $this->out, $this->userProfile); 54 | } 55 | } 56 | 57 | /** 58 | * A threaded notice list item that shows everything 59 | * 60 | * @category General 61 | * @package StatusNet 62 | * @author Evan Prodromou 63 | * @author Brion Vibber 64 | * @copyright 2011 StatusNet, Inc. 65 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 66 | * @link http://status.net/ 67 | */ 68 | 69 | class QuitimFullThreadedNoticeListItem extends QuitimThreadedNoticeListItem 70 | { 71 | function initialItems() 72 | { 73 | return 1000; // @fixme 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /classes/QuitimNoticeListItem.php: -------------------------------------------------------------------------------- 1 | elementStart('footer'); 12 | $this->showNoticeInfo(); 13 | if ($this->options) { $this->showNoticeOptions(); } 14 | // if ($this->attachments) { $this->showNoticeAttachments(); } 15 | $this->elementEnd('footer'); 16 | } 17 | 18 | function showStart() 19 | { 20 | 21 | // see if this is an "empty" notice with only image attachments 22 | $attachments = $this->notice->attachments(); 23 | $content_stripped_of_attachments = $this->notice->content; 24 | $image_attachments_num = 0; 25 | foreach($attachments as $attachment) { 26 | $attachment_type = substr($attachment->mimetype, 0, strpos($attachment->mimetype,'/')); 27 | if(empty($this->notice->reply_to) && $attachment_type == 'image' && $attachment instanceof File) { 28 | $image_attachments_num++; 29 | $redirection_aliases = File_redirection::multiGet('file_id',array($attachment->id)); 30 | while ($redirection_aliases->fetch()) { 31 | $content_stripped_of_attachments = trim(str_replace($redirection_aliases->url,'',$content_stripped_of_attachments)); 32 | } 33 | } 34 | } 35 | 36 | 37 | // if (Event::handle('StartOpenNoticeListItemElement', array($this))) { 38 | $id = (empty($this->repeat)) ? $this->notice->id : $this->repeat->id; 39 | $class = 'h-entry notice'; 40 | if ($this->notice->scope != 0 && $this->notice->scope != 1) { 41 | $class .= ' limited-scope'; 42 | } 43 | if (!empty($this->notice->source)) { 44 | $class .= ' notice-source-'.$this->notice->source; 45 | } 46 | if($content_stripped_of_attachments == '') { 47 | $class .= ' empty-text'; 48 | } 49 | if(substr($this->notice->rendered,0,27) == '
') { 50 | $class .= ' old-quitim-notice'; 51 | } 52 | if(isset($this->notice->is_conversation_starter)) { 53 | $class .= ' conversation-starter'; 54 | } 55 | if($image_attachments_num == 0) { 56 | $class .= ' no-images'; 57 | } 58 | $id_prefix = (strlen($this->id_prefix) ? $this->id_prefix . '-' : ''); 59 | $this->out->elementStart($this->item_tag, array('class' => $class, 60 | 'id' => "${id_prefix}notice-${id}", 61 | 'data-local-permalink' => $this->notice->getLocalUrl())); 62 | Event::handle('EndOpenNoticeListItemElement', array($this)); 63 | // } 64 | } 65 | 66 | 67 | function showAuthor() 68 | { 69 | $attrs = array('href' => $this->profile->profileurl, 70 | 'class' => 'h-card p-author', 71 | 'title' => $this->profile->getStreamName()); 72 | 73 | if (Event::handle('StartShowNoticeItemAuthor', array($this->profile, $this->out, &$attrs))) { 74 | $this->out->elementStart('a', $attrs); 75 | $this->showAvatar($this->profile); 76 | $this->out->text($this->profile->getNickname()); 77 | $this->out->elementEnd('a'); 78 | Event::handle('EndShowNoticeItemAuthor', array($this->profile, $this->out)); 79 | } 80 | } 81 | 82 | 83 | function showNoticeLink() 84 | { 85 | $this->out->elementStart('a', array('rel' => 'bookmark', 86 | 'class' => 'timestamp', 87 | 'href' => common_path('notice/'.$this->notice->id))); 88 | $this->out->element('time', array('class' => 'dt-published', 89 | 'datetime' => common_date_iso8601($this->notice->created), 90 | 'title' => common_exact_date($this->notice->created)), 91 | common_date_string($this->notice->created)); 92 | $this->out->elementEnd('a'); 93 | } 94 | 95 | 96 | 97 | function showContent() 98 | { 99 | 100 | $this->out->elementStart('article', array('class' => 'e-content')); 101 | 102 | $attachments = $this->notice->attachments(); 103 | 104 | $conversation_root = $this->notice->conversationRoot(); 105 | $is_conversation_root = ($this->notice->id == $conversation_root->id); 106 | 107 | $image_attachments_num = 0; 108 | foreach($attachments as $attachment) { 109 | $attachment_type = substr($attachment->mimetype, 0, strpos($attachment->mimetype,'/')); 110 | 111 | // we only show conversation starting images and local attachments 112 | if($is_conversation_root && $attachment_type == 'image' && $attachment instanceof File && $attachment->filename !== null) { 113 | 114 | // show full image if small 115 | if($attachment->width < 1000) { 116 | $thumb_url = $attachment->url; 117 | // thumbnail scaled to 1000px wide if big 118 | } else { 119 | $ratio = $attachment->width/$attachment->height; 120 | $thumb = $attachment->getThumbnail(1000, 1000/$ratio); 121 | $thumb_url = $thumb->url; 122 | } 123 | $this->out->raw('
'); 124 | $image_attachments_num++; 125 | } 126 | } 127 | 128 | // if this is a root notice but without image, we show the text 129 | if($is_conversation_root && $image_attachments_num==0) { 130 | $this->out->raw('
'.$this->notice->rendered.'
'); 131 | } 132 | 133 | // don't know why i had to do this, but when QuitimNoticeListItem is used from quitimnewnotice.php it can't find this clas... 134 | // but we don't need it then, since it's always the question about getting a comment with ajax then. 135 | if(class_exists('QuitimThreadedNoticeListFavesItem')) { 136 | $item = new QuitimThreadedNoticeListFavesItem($this->notice, $this->out); 137 | $hasFaves = $item->show(); 138 | } else { 139 | $hasFaves = false; 140 | } 141 | 142 | // don't know why i had to do this, but when QuitimNoticeListItem is used from quitimnewnotice.php it can't find this clas... 143 | // but we don't need it then, since it's always the question about getting a comment with ajax then. 144 | if(class_exists('QuitimThreadedNoticeListBourgeoisItem')) { 145 | $item = new QuitimThreadedNoticeListBourgeoisItem($this->notice, $this->out); 146 | $hasBourgeois = $item->show(); 147 | } else { 148 | $hasBourgeois = false; 149 | } 150 | 151 | // add a fav container even if no faves, to load into with ajax when faving 152 | if(!isset($hasFaves) || !$hasFaves) { 153 | $this->element('div',array('class' => 'notice-data notice-faves')); 154 | } 155 | // add a bourgeois container even if no bourgeois 156 | if(!isset($hasBourgeois) || !$hasBourgeois) { 157 | $this->element('div',array('class' => 'notice-data notice-bourgeois')); 158 | } 159 | 160 | $this->out->elementStart('div', 'first-comment'); 161 | $this->showAuthor(); 162 | $this->out->elementStart('span', 'quitim-notice-text'); 163 | if ($this->maxchars > 0 && mb_strlen($this->notice->content) > $this->maxchars) { 164 | $this->out->text(mb_substr($this->notice->content, 0, $this->maxchars) . '[…]'); 165 | } elseif ($this->notice->rendered) { 166 | $this->out->raw($this->notice->rendered); 167 | } 168 | $this->out->elementEnd('span'); 169 | $this->out->elementEnd('div'); 170 | 171 | $this->out->elementEnd('article'); 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /classes/QuitimNotification.php: -------------------------------------------------------------------------------- 1 | array( 28 | 'id' => array('type' => 'serial', 'not null' => true), 29 | 'to_profile_id' => array('type' => 'int', 'description' => 'the profile being notified'), 30 | 'from_profile_id' => array('type' => 'int', 'description' => 'the profile that is notifying'), 31 | 'ntype' => array('type' => 'varchar', 'length' => 7, 'description' => 'reply, like, mention or follow'), 32 | 'first_notice_id_in_conversation' => array('type' => 'int', 'description' => 'the conversation starter, e.i. the image'), 33 | 'notice_id' => array('type' => 'int', 'description' => 'id for the reply or mention or notice being faved'), 34 | 'is_seen' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'if the notification has been seen'), 35 | 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created') 36 | ), 37 | 'primary key' => array('id') 38 | ); 39 | } 40 | 41 | /** 42 | * Wrapper for record insertion to update related caches 43 | */ 44 | function insert() 45 | { 46 | $result = parent::insert(); 47 | 48 | if ($result) { 49 | self::blow('quitimnotification:stream:%d', $this->profile_id); 50 | } 51 | 52 | return $result; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /classes/QuitimProfileListItem.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @category Public 23 | * @package StatusNet 24 | * @author Evan Prodromou 25 | * @copyright 2008-2009 StatusNet, Inc. 26 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 27 | * @link http://status.net/ 28 | */ 29 | 30 | if (!defined('GNUSOCIAL')) { exit(1); } 31 | 32 | class QuitimProfileListItem extends Widget 33 | { 34 | /** Current profile. */ 35 | var $profile = null; 36 | /** Action object using us. */ 37 | var $action = null; 38 | 39 | function __construct($profile, $action) 40 | { 41 | parent::__construct($action); 42 | 43 | $this->profile = $profile; 44 | $this->action = $action; 45 | } 46 | 47 | function show() 48 | { 49 | if (Event::handle('StartProfileListItem', array($this))) { 50 | $this->startItem(); 51 | if (Event::handle('StartProfileListItemProfile', array($this))) { 52 | $this->showProfile(); 53 | Event::handle('EndProfileListItemProfile', array($this)); 54 | } 55 | $this->endItem(); 56 | Event::handle('EndProfileListItem', array($this)); 57 | } 58 | } 59 | 60 | function startItem() 61 | { 62 | $this->out->elementStart('li', array('class' => 'profile', 63 | 'id' => 'profile-' . $this->profile->id)); 64 | } 65 | 66 | function showProfile() 67 | { 68 | $this->startProfile(); 69 | if (Event::handle('StartProfileListItemProfileElements', array($this))) { 70 | if (Event::handle('StartProfileListItemAvatar', array($this))) { 71 | $aAttrs = $this->linkAttributes(); 72 | $this->out->elementStart('a', $aAttrs); 73 | $this->showAvatar($this->profile); 74 | $this->out->elementEnd('a'); 75 | Event::handle('EndProfileListItemAvatar', array($this)); 76 | } 77 | 78 | if (Event::handle('StartProfileListItemActions', array($this))) { 79 | $this->showActions(); 80 | Event::handle('EndProfileListItemActions', array($this)); 81 | } 82 | 83 | if (Event::handle('StartProfileListItemNickname', array($this))) { 84 | $this->showNickname(); 85 | Event::handle('EndProfileListItemNickname', array($this)); 86 | } 87 | if (Event::handle('StartProfileListItemFullName', array($this))) { 88 | $this->showFullName(); 89 | Event::handle('EndProfileListItemFullName', array($this)); 90 | } 91 | 92 | Event::handle('EndProfileListItemProfileElements', array($this)); 93 | } 94 | $this->endProfile(); 95 | } 96 | 97 | function startProfile() 98 | { 99 | $this->out->elementStart('div', 'entity_profile h-card'); 100 | } 101 | 102 | function showNickname() 103 | { 104 | $external_class = ''; 105 | if(!$this->profile->isLocal()) { 106 | $external_class = ' external'; 107 | } 108 | 109 | $this->out->elementStart('a', array('href'=>$this->profile->getUrl(), 'class'=>'p-nickname'.$external_class)); 110 | $this->out->elementStart('span', array('class'=>'nickname-container')); 111 | $this->out->raw(htmlspecialchars($this->profile->getNickname())); 112 | $this->out->elementEnd('span'); 113 | if(!$this->profile->isLocal()) { 114 | $this->out->elementStart('span', array('class'=>'external-user')); 115 | $this->out->raw('('.parse_url($this->profile->getUri(), PHP_URL_HOST).')'); 116 | $this->out->elementEnd('span'); 117 | } 118 | $this->out->elementEnd('a'); 119 | } 120 | 121 | function showFullName() 122 | { 123 | if (!empty($this->profile->fullname)) { 124 | $this->out->elementStart('a', array('href'=>$this->profile->getUrl(), 'class'=>'p-name')); 125 | $this->out->raw(htmlspecialchars($this->profile->fullname)); 126 | $this->out->elementEnd('a'); 127 | } 128 | } 129 | 130 | function showLocation() 131 | { 132 | if (!empty($this->profile->location)) { 133 | $this->out->element('span', 'label p-locality', $this->profile->location); 134 | } 135 | } 136 | 137 | function showHomepage() 138 | { 139 | if (!empty($this->profile->homepage)) { 140 | $this->out->text(' '); 141 | $aAttrs = $this->homepageAttributes(); 142 | $this->out->elementStart('a', $aAttrs); 143 | $this->out->raw($this->highlight($this->profile->homepage)); 144 | $this->out->elementEnd('a'); 145 | } 146 | } 147 | 148 | function showBio() 149 | { 150 | if (!empty($this->profile->bio)) { 151 | $this->out->elementStart('p', 'note'); 152 | $this->out->raw($this->highlight($this->profile->bio)); 153 | $this->out->elementEnd('p'); 154 | } 155 | } 156 | 157 | function showTags() 158 | { 159 | $user = common_current_user(); 160 | if (!empty($user)) { 161 | if ($user->id == $this->profile->id) { 162 | $tags = new SelftagsWidget($this->out, $user, $this->profile); 163 | $tags->show(); 164 | } else if ($user->getProfile()->canTag($this->profile)) { 165 | $tags = new PeopletagsWidget($this->out, $user, $this->profile); 166 | $tags->show(); 167 | } 168 | } 169 | } 170 | 171 | function endProfile() 172 | { 173 | $this->out->elementEnd('div'); 174 | } 175 | 176 | function showActions() 177 | { 178 | $this->startActions(); 179 | if (Event::handle('StartProfileListItemActionElements', array($this))) { 180 | $this->showSubscribeButton(); 181 | Event::handle('EndProfileListItemActionElements', array($this)); 182 | } 183 | $this->endActions(); 184 | } 185 | 186 | function startActions() 187 | { 188 | $this->out->elementStart('div', 'entity_actions'); 189 | $this->out->elementStart('ul'); 190 | } 191 | 192 | function showSubscribeButton() 193 | { 194 | // Is this a logged-in user, looking at someone else's 195 | // profile? 196 | 197 | $user = common_current_user(); 198 | 199 | if (!empty($user) && $this->profile->id != $user->id) { 200 | $this->out->elementStart('li', 'entity_subscribe'); 201 | if ($user->isSubscribed($this->profile)) { 202 | $usf = new QuitimUnsubscribeForm($this->out, $this->profile); 203 | $usf->show(); 204 | } else { 205 | if (Event::handle('StartShowProfileListSubscribeButton', array($this))) { 206 | $sf = new QuitimSubscribeForm($this->out, $this->profile); 207 | $sf->show(); 208 | Event::handle('EndShowProfileListSubscribeButton', array($this)); 209 | } 210 | } 211 | $this->out->elementEnd('li'); 212 | } 213 | } 214 | 215 | function endActions() 216 | { 217 | $this->out->elementEnd('ul'); 218 | $this->out->elementEnd('div'); 219 | } 220 | 221 | function endItem() 222 | { 223 | $this->out->elementEnd('li'); 224 | } 225 | 226 | function highlight($text) 227 | { 228 | return htmlspecialchars($text); 229 | } 230 | 231 | function linkAttributes() 232 | { 233 | return array('href' => $this->profile->profileurl, 234 | 'class' => 'u-url', 235 | 'rel' => 'contact'); 236 | } 237 | 238 | function homepageAttributes() 239 | { 240 | return array('href' => $this->profile->homepage, 241 | 'class' => 'u-url'); 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /classes/QuitimSubscribeForm.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @category Form 23 | * @package StatusNet 24 | * @author Evan Prodromou 25 | * @author Sarven Capadisli 26 | * @copyright 2009 StatusNet, Inc. 27 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 28 | * @link http://status.net/ 29 | */ 30 | 31 | if (!defined('STATUSNET') && !defined('LACONICA')) { 32 | exit(1); 33 | } 34 | 35 | require_once INSTALLDIR.'/lib/form.php'; 36 | 37 | /** 38 | * Form for subscribing to a user 39 | * 40 | * @category Form 41 | * @package StatusNet 42 | * @author Evan Prodromou 43 | * @author Sarven Capadisli 44 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 45 | * @link http://status.net/ 46 | * 47 | * @see UnsubscribeForm 48 | */ 49 | class QuitimSubscribeForm extends Form 50 | { 51 | /** 52 | * Profile of user to subscribe to 53 | */ 54 | var $profile = null; 55 | 56 | /** 57 | * Constructor 58 | * 59 | * @param HTMLOutputter $out output channel 60 | * @param Profile $profile profile of user to subscribe to 61 | */ 62 | function __construct($out=null, $profile=null) 63 | { 64 | parent::__construct($out); 65 | 66 | $this->profile = $profile; 67 | } 68 | 69 | /** 70 | * ID of the form 71 | * 72 | * @return int ID of the form 73 | */ 74 | function id() 75 | { 76 | return 'subscribe-' . $this->profile->id; 77 | } 78 | 79 | /** 80 | * class of the form 81 | * 82 | * @return string of the form class 83 | */ 84 | function formClass() 85 | { 86 | return 'form_user_subscribe ajax'; 87 | } 88 | 89 | /** 90 | * Action of the form 91 | * 92 | * @return string URL of the action 93 | */ 94 | function action() 95 | { 96 | return common_local_url('subscribe'); 97 | } 98 | 99 | /** 100 | * Legend of the Form 101 | * 102 | * @return void 103 | */ 104 | function formLegend() 105 | { 106 | // TRANS: Form of form to subscribe to a user. 107 | $this->out->element('legend', null, _('Subscribe to this user')); 108 | } 109 | 110 | /** 111 | * Data elements of the form 112 | * 113 | * @return void 114 | */ 115 | function formData() 116 | { 117 | $this->out->hidden('subscribeto-' . $this->profile->id, 118 | $this->profile->id, 119 | 'subscribeto'); 120 | } 121 | 122 | /** 123 | * Action elements 124 | * 125 | * @return void 126 | */ 127 | function formActions() 128 | { 129 | // TRANS: Button text to subscribe to a user. 130 | $this->out->element('button', array('id'=>'submit', 131 | 'name'=>'submit', 132 | 'type'=>'submit', 133 | 'value'=>_m('BUTTON','Subscribe'),'title'=>_('Follow this user.')),_m('BUTTON','Follow')); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /classes/QuitimUnsubscribeForm.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @category Form 23 | * @package StatusNet 24 | * @author Evan Prodromou 25 | * @author Sarven Capadisli 26 | * @copyright 2009 StatusNet, Inc. 27 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 28 | * @link http://status.net/ 29 | */ 30 | 31 | if (!defined('STATUSNET') && !defined('LACONICA')) { 32 | exit(1); 33 | } 34 | 35 | require_once INSTALLDIR.'/lib/form.php'; 36 | 37 | /** 38 | * Form for unsubscribing from a user 39 | * 40 | * @category Form 41 | * @package StatusNet 42 | * @author Evan Prodromou 43 | * @author Sarven Capadisli 44 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 45 | * @link http://status.net/ 46 | * 47 | * @see SubscribeForm 48 | */ 49 | class QuitimUnsubscribeForm extends Form 50 | { 51 | /** 52 | * Profile of user to unsubscribe from 53 | */ 54 | 55 | var $profile = null; 56 | 57 | /** 58 | * Constructor 59 | * 60 | * @param HTMLOutputter $out output channel 61 | * @param Profile $profile profile of user to unsub from 62 | */ 63 | function __construct($out=null, $profile=null) 64 | { 65 | parent::__construct($out); 66 | 67 | $this->profile = $profile; 68 | } 69 | 70 | /** 71 | * ID of the form 72 | * 73 | * @return int ID of the form 74 | */ 75 | function id() 76 | { 77 | return 'unsubscribe-' . $this->profile->id; 78 | } 79 | 80 | 81 | /** 82 | * class of the form 83 | * 84 | * @return string of the form class 85 | */ 86 | function formClass() 87 | { 88 | return 'form_user_unsubscribe ajax'; 89 | } 90 | 91 | /** 92 | * Action of the form 93 | * 94 | * @return string URL of the action 95 | */ 96 | function action() 97 | { 98 | return common_local_url('unsubscribe'); 99 | } 100 | 101 | /** 102 | * Legend of the Form 103 | * 104 | * @return void 105 | */ 106 | function formLegend() 107 | { 108 | // TRANS: Form legend on unsubscribe form. 109 | $this->out->element('legend', null, _('Unsubscribe from this user')); 110 | } 111 | 112 | /** 113 | * Data elements of the form 114 | * 115 | * @return void 116 | */ 117 | function formData() 118 | { 119 | $this->out->hidden('unsubscribeto-' . $this->profile->id, 120 | $this->profile->id, 121 | 'unsubscribeto'); 122 | } 123 | 124 | /** 125 | * Action elements 126 | * 127 | * @return void 128 | */ 129 | function formActions() 130 | { 131 | // TRANS: Button text to subscribe to a user. 132 | $this->out->element('button', array('id'=>'submit', 133 | 'name'=>'submit', 134 | 'type'=>'submit', 135 | 'value'=>_m('BUTTON','Unsubscribe'),'title'=>_('Following this user.')),_m('BUTTON','Following')); 136 | 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /fonts/font-awesome-4.3.0/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/fonts/font-awesome-4.3.0/FontAwesome.otf -------------------------------------------------------------------------------- /fonts/font-awesome-4.3.0/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/fonts/font-awesome-4.3.0/fontawesome-webfont.eot -------------------------------------------------------------------------------- /fonts/font-awesome-4.3.0/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/fonts/font-awesome-4.3.0/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /fonts/font-awesome-4.3.0/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/fonts/font-awesome-4.3.0/fontawesome-webfont.woff -------------------------------------------------------------------------------- /fonts/font-awesome-4.3.0/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/fonts/font-awesome-4.3.0/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /img/cc-by-nc-80x15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/img/cc-by-nc-80x15.png -------------------------------------------------------------------------------- /img/ekan4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/img/ekan4.jpg -------------------------------------------------------------------------------- /img/quitim-sprite-preview.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/img/quitim-sprite-preview.ai -------------------------------------------------------------------------------- /img/quitim-sprite.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/img/quitim-sprite.ai -------------------------------------------------------------------------------- /img/refresh.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/img/refresh.ai -------------------------------------------------------------------------------- /img/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/img/refresh.png -------------------------------------------------------------------------------- /img/smallogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/img/smallogo.png -------------------------------------------------------------------------------- /img/sprite-preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/img/sprite-preview.jpg -------------------------------------------------------------------------------- /img/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannesmannerheim/quitim/acb05a6a969c32ec588ead9c69d8db6b540f8626/img/sprite.png -------------------------------------------------------------------------------- /js/bowser.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | @licstart The following is the entire license notice for the 4 | JavaScript code in this page. 5 | 6 | Copyright (c) Dustin Diaz 2015 MIT License https://github.com/ded/bowser 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining 9 | a copy of this software and associated documentation files (the 10 | "Software"), to deal in the Software without restriction, including 11 | without limitation the rights to use, copy, modify, merge, publish, 12 | distribute, sublicense, and/or sell copies of the Software, and to 13 | permit persons to whom the Software is furnished to do so, subject to 14 | the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included 17 | in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | @licend The above is the entire license notice 28 | for the JavaScript code in this page. 29 | 30 | */ 31 | 32 | !function(e,t){typeof module!="undefined"&&module.exports?module.exports=t():typeof define=="function"&&define.amd?define(t):this[e]=t()}("bowser",function(){function t(t){function n(e){var n=t.match(e);return n&&n.length>1&&n[1]||""}function r(e){var n=t.match(e);return n&&n.length>1&&n[2]||""}var i=n(/(ipod|iphone|ipad)/i).toLowerCase(),s=/like android/i.test(t),o=!s&&/android/i.test(t),u=/CrOS/.test(t),a=n(/edge\/(\d+(\.\d+)?)/i),f=n(/version\/(\d+(\.\d+)?)/i),l=/tablet/i.test(t),c=!l&&/[^-]mobi/i.test(t),h;/opera|opr/i.test(t)?h={name:"Opera",opera:e,version:f||n(/(?:opera|opr)[\s\/](\d+(\.\d+)?)/i)}:/yabrowser/i.test(t)?h={name:"Yandex Browser",yandexbrowser:e,version:f||n(/(?:yabrowser)[\s\/](\d+(\.\d+)?)/i)}:/windows phone/i.test(t)?(h={name:"Windows Phone",windowsphone:e},a?(h.msedge=e,h.version=a):(h.msie=e,h.version=n(/iemobile\/(\d+(\.\d+)?)/i))):/msie|trident/i.test(t)?h={name:"Internet Explorer",msie:e,version:n(/(?:msie |rv:)(\d+(\.\d+)?)/i)}:u?h={name:"Chrome",chromeBook:e,chrome:e,version:n(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)}:/chrome.+? edge/i.test(t)?h={name:"Microsoft Edge",msedge:e,version:a}:/chrome|crios|crmo/i.test(t)?h={name:"Chrome",chrome:e,version:n(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)}:i?(h={name:i=="iphone"?"iPhone":i=="ipad"?"iPad":"iPod"},f&&(h.version=f)):/sailfish/i.test(t)?h={name:"Sailfish",sailfish:e,version:n(/sailfish\s?browser\/(\d+(\.\d+)?)/i)}:/seamonkey\//i.test(t)?h={name:"SeaMonkey",seamonkey:e,version:n(/seamonkey\/(\d+(\.\d+)?)/i)}:/firefox|iceweasel/i.test(t)?(h={name:"Firefox",firefox:e,version:n(/(?:firefox|iceweasel)[ \/](\d+(\.\d+)?)/i)},/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(t)&&(h.firefoxos=e)):/silk/i.test(t)?h={name:"Amazon Silk",silk:e,version:n(/silk\/(\d+(\.\d+)?)/i)}:o?h={name:"Android",version:f}:/phantom/i.test(t)?h={name:"PhantomJS",phantom:e,version:n(/phantomjs\/(\d+(\.\d+)?)/i)}:/blackberry|\bbb\d+/i.test(t)||/rim\stablet/i.test(t)?h={name:"BlackBerry",blackberry:e,version:f||n(/blackberry[\d]+\/(\d+(\.\d+)?)/i)}:/(web|hpw)os/i.test(t)?(h={name:"WebOS",webos:e,version:f||n(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)},/touchpad\//i.test(t)&&(h.touchpad=e)):/bada/i.test(t)?h={name:"Bada",bada:e,version:n(/dolfin\/(\d+(\.\d+)?)/i)}:/tizen/i.test(t)?h={name:"Tizen",tizen:e,version:n(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i)||f}:/safari/i.test(t)?h={name:"Safari",safari:e,version:f}:h={name:n(/^(.*)\/(.*) /),version:r(/^(.*)\/(.*) /)},!h.msedge&&/(apple)?webkit/i.test(t)?(h.name=h.name||"Webkit",h.webkit=e,!h.version&&f&&(h.version=f)):!h.opera&&/gecko\//i.test(t)&&(h.name=h.name||"Gecko",h.gecko=e,h.version=h.version||n(/gecko\/(\d+(\.\d+)?)/i)),!h.msedge&&(o||h.silk)?h.android=e:i&&(h[i]=e,h.ios=e);var p="";h.windowsphone?p=n(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i):i?(p=n(/os (\d+([_\s]\d+)*) like mac os x/i),p=p.replace(/[_\s]/g,".")):o?p=n(/android[ \/-](\d+(\.\d+)*)/i):h.webos?p=n(/(?:web|hpw)os\/(\d+(\.\d+)*)/i):h.blackberry?p=n(/rim\stablet\sos\s(\d+(\.\d+)*)/i):h.bada?p=n(/bada\/(\d+(\.\d+)*)/i):h.tizen&&(p=n(/tizen[\/\s](\d+(\.\d+)*)/i)),p&&(h.osversion=p);var d=p.split(".")[0];if(l||i=="ipad"||o&&(d==3||d==4&&!c)||h.silk)h.tablet=e;else if(c||i=="iphone"||i=="ipod"||o||h.blackberry||h.webos||h.bada)h.mobile=e;return h.msedge||h.msie&&h.version>=10||h.yandexbrowser&&h.version>=15||h.chrome&&h.version>=20||h.firefox&&h.version>=20||h.safari&&h.version>=6||h.opera&&h.version>=10||h.ios&&h.osversion&&h.osversion.split(".")[0]>=6||h.blackberry&&h.version>=10.1?h.a=e:h.msie&&h.version<10||h.chrome&&h.version<20||h.firefox&&h.version<20||h.safari&&h.version<6||h.opera&&h.version<10||h.ios&&h.osversion&&h.osversion.split(".")[0]<6?h.c=e:h.x=e,h}var e=!0,n=t(typeof navigator!="undefined"?navigator.userAgent:"");return n.test=function(e){for(var t=0;t",{id:"filtrr2-"+a.attr("id"),"class":a.attr("class"),style:a.attr("style")}).css({width:a.width(),height:a.height(),top:c.top,left:c.left}),d=f[0];this.canvas=f;d.width=b.width;d.height=b.height;d.getContext("2d").drawImage(b,0,0);a.hide();a.parent().append(f);this.processor=new Filtrr2.ImageProcessor(this);j&&j.call(this.processor); 2 | h=!0},this)};this.el=a;this.created=e;this.canvas=this.processor=null;d=new Filtrr2.Events;this.on=$.proxy(function(a,b){d.on(a,b,this)},this);this.off=d.off;this.trigger=d.trigger;this.ready=function(a){if(!a)return h;j=a;h&&j.call(this.ip)};this.update=function(a){a&&h&&a.call(this.processor)};this.save=function(a){var b="image/"+(a||"png");h&&(a=this.canvas[0].toDataURL(b),-1==a.indexOf(b)&&(b="image/png"),a=a.replace(b,"image/octet-stream"),window.location.href=a)};this.reset=function(){if(h)return this.processor.reset()}; 3 | if("img"==f)b.call(this,a);else if("canvas"==f)this.canvas=a,this.processor=new Filtrr2.ImageProcessor(this),j&&j.call(this.processor),h=!0;else throw Error("'"+f+"' is an invalid object.");return this},Filtrr2=function(){var a={};if(null==$("")[0].getContext("2d"))throw Error("Canvas is not supported in this browser.");return function(b,e,f){var c,d,h;null==f&&(f={store:!0});if("undefined"===typeof b||null===b)throw Error("The element you gave Filtrr2 was not defined.");c=typeof b;d=b;c= 4 | (h="string"===c||"object"===c&&-1g;g++){var k=a.y*g/1024*(g/1024)*(g/1024)+b.y*3*(g/1024)*(g/1024)*(1-g/1024)+d.y*3*(g/1024)*(1-g/1024)*(1-g/1024)+h.y*(1-g/1024)*(1-g/1024)*(1-g/1024);e[parseInt(a.x*g/1024* 14 | (g/1024)*(g/1024)+b.x*3*(g/1024)*(g/1024)*(1-g/1024)+d.x*3*(g/1024)*(1-g/1024)*(1-g/1024)+h.x*(1-g/1024)*(1-g/1024)*(1-g/1024))]=parseInt(k)}return e}};return a}();Filtrr2.Events=function(){var a={};this.on=function(b,e,f){a[b]||(a[b]=[]);void 0===f&&(f=null);a[b].push({cback:e,ctx:f})};this.off=function(b,e){var f=0,c=[],d=null;if(a[b]&&0b?255*((1-2*b)*a*a+2*b*a):255*((1-(2*b-1))*a+(2*b-1)*Math.pow(a,0.5))};b(a,c,function(a,b){a.r=d(a.r,b.r);a.g=d(a.g,b.g);a.b=d(a.b,b.b)})},addition:function(a,c){b(a,c,function(a, 16 | b){a.r+=b.r;a.g+=b.g;a.b+=b.b})},exclusion:function(a,c){b(a,c,function(a,b){a.r=128-2*(a.r-128)*(b.r-128)/255;a.g=128-2*(a.g-128)*(b.g-128)/255;a.b=128-2*(a.b-128)*(b.b-128)/255})},difference:function(a,c){var d=Math.abs;b(a,c,function(a,b){a.r=d(b.r-a.r);a.g=d(b.g-a.g);a.b=d(b.b-a.b)})}};this.merge=function(a,b,d){if(null!=e[a])e[a](b,d);else throw Error("Unknown layer blend type '"+a+"'.");}}; 17 | -------------------------------------------------------------------------------- /js/jquery.mobile-events.min.js: -------------------------------------------------------------------------------- 1 | (function(e){function d(){var e=o();if(e!==u){u=e;i.trigger("orientationchange")}}function E(t,n,r,i){var s=r.type;r.type=n;e.event.dispatch.call(t,r,i);r.type=s}e.attrFn=e.attrFn||{};var t=navigator.userAgent.toLowerCase(),n=t.indexOf("chrome")>-1&&(t.indexOf("windows")>-1||t.indexOf("macintosh")>-1||t.indexOf("linux")>-1)&&t.indexOf("mobile")<0,r={tap_pixel_range:5,swipe_h_threshold:50,swipe_v_threshold:50,taphold_threshold:750,doubletap_int:500,touch_capable:"ontouchstart"in document.documentElement&&!n,orientation_support:"orientation"in window&&"onorientationchange"in window,startevent:"ontouchstart"in document.documentElement&&!n?"touchstart":"mousedown",endevent:"ontouchstart"in document.documentElement&&!n?"touchend":"mouseup",moveevent:"ontouchstart"in document.documentElement&&!n?"touchmove":"mousemove",tapevent:"ontouchstart"in document.documentElement&&!n?"tap":"click",scrollevent:"ontouchstart"in document.documentElement&&!n?"touchmove":"scroll",hold_timer:null,tap_timer:null};e.isTouchCapable=function(){return r.touch_capable};e.getStartEvent=function(){return r.startevent};e.getEndEvent=function(){return r.endevent};e.getMoveEvent=function(){return r.moveevent};e.getTapEvent=function(){return r.tapevent};e.getScrollEvent=function(){return r.scrollevent};e.each(["tapstart","tapend","tap","singletap","doubletap","taphold","swipe","swipeup","swiperight","swipedown","swipeleft","swipeend","scrollstart","scrollend","orientationchange"],function(t,n){e.fn[n]=function(e){return e?this.on(n,e):this.trigger(n)};e.attrFn[n]=true});e.event.special.tapstart={setup:function(){var t=this,n=e(t);n.on(r.startevent,function(e){n.data("callee",arguments.callee);if(e.which&&e.which!==1){return false}var i=e.originalEvent,s={position:{x:r.touch_capable?i.touches[0].screenX:e.screenX,y:r.touch_capable?i.touches[0].screenY:e.screenY},offset:{x:r.touch_capable?i.touches[0].pageX-i.touches[0].target.offsetLeft:e.offsetX,y:r.touch_capable?i.touches[0].pageY-i.touches[0].target.offsetTop:e.offsetY},time:(new Date).getTime(),target:e.target};E(t,"tapstart",e,s);return true})},remove:function(){e(this).off(r.startevent,e(this).data.callee)}};e.event.special.tapmove={setup:function(){var t=this,n=e(t);n.on(r.moveevent,function(e){n.data("callee",arguments.callee);var i=e.originalEvent,s={position:{x:r.touch_capable?i.touches[0].screenX:e.screenX,y:r.touch_capable?i.touches[0].screenY:e.screenY},offset:{x:r.touch_capable?i.touches[0].pageX-i.touches[0].target.offsetLeft:e.offsetX,y:r.touch_capable?i.touches[0].pageY-i.touches[0].target.offsetTop:e.offsetY},time:(new Date).getTime(),target:e.target};E(t,"tapmove",e,s);return true})},remove:function(){e(this).off(r.moveevent,e(this).data.callee)}};e.event.special.tapend={setup:function(){var t=this,n=e(t);n.on(r.endevent,function(e){n.data("callee",arguments.callee);var i=e.originalEvent;var s={position:{x:r.touch_capable?i.changedTouches[0].screenX:e.screenX,y:r.touch_capable?i.changedTouches[0].screenY:e.screenY},offset:{x:r.touch_capable?i.changedTouches[0].pageX-i.changedTouches[0].target.offsetLeft:e.offsetX,y:r.touch_capable?i.changedTouches[0].pageY-i.changedTouches[0].target.offsetTop:e.offsetY},time:(new Date).getTime(),target:e.target};E(t,"tapend",e,s);return true})},remove:function(){e(this).off(r.endevent,e(this).data.callee)}};e.event.special.taphold={setup:function(){var t=this,n=e(t),i,s,o={x:0,y:0};n.on(r.startevent,function(e){if(e.which&&e.which!==1){return false}else{n.data("tapheld",false);i=e.target;var s=e.originalEvent;var u=(new Date).getTime(),a={x:r.touch_capable?s.touches[0].screenX:e.screenX,y:r.touch_capable?s.touches[0].screenY:e.screenY},f={x:r.touch_capable?s.touches[0].pageX-s.touches[0].target.offsetLeft:e.offsetX,y:r.touch_capable?s.touches[0].pageY-s.touches[0].target.offsetTop:e.offsetY};o.x=e.originalEvent.targetTouches?e.originalEvent.targetTouches[0].pageX:e.pageX;o.y=e.originalEvent.targetTouches?e.originalEvent.targetTouches[0].pageY:e.pageY;r.hold_timer=window.setTimeout(function(){var l=e.originalEvent.targetTouches?e.originalEvent.targetTouches[0].pageX:e.pageX,c=e.originalEvent.targetTouches?e.originalEvent.targetTouches[0].pageY:e.pageY;if(e.target==i&&o.x==l&&o.y==c){n.data("tapheld",true);var h=(new Date).getTime(),p={x:r.touch_capable?s.touches[0].screenX:e.screenX,y:r.touch_capable?s.touches[0].screenY:e.screenY},d={x:r.touch_capable?s.touches[0].pageX-s.touches[0].target.offsetLeft:e.offsetX,y:r.touch_capable?s.touches[0].pageY-s.touches[0].target.offsetTop:e.offsetY};duration=h-u;var v={startTime:u,endTime:h,startPosition:a,startOffset:f,endPosition:p,endOffset:d,duration:duration,target:e.target};n.data("callee1",arguments.callee);E(t,"taphold",e,v)}},r.taphold_threshold);return true}}).on(r.endevent,function(){n.data("callee2",arguments.callee);n.data("tapheld",false);window.clearTimeout(r.hold_timer)})},remove:function(){e(this).off(r.startevent,e(this).data.callee1).off(r.endevent,e(this).data.callee2)}};e.event.special.doubletap={setup:function(){var t=this,n=e(t),i,s,o,u;n.on(r.startevent,function(e){if(e.which&&e.which!==1){return false}else{n.data("doubletapped",false);i=e.target;n.data("callee1",arguments.callee);u=e.originalEvent;o={position:{x:r.touch_capable?u.touches[0].screenX:e.screenX,y:r.touch_capable?u.touches[0].screenY:e.screenY},offset:{x:r.touch_capable?u.touches[0].pageX-u.touches[0].target.offsetLeft:e.offsetX,y:r.touch_capable?u.touches[0].pageY-u.touches[0].target.offsetTop:e.offsetY},time:(new Date).getTime(),target:e.target};return true}}).on(r.endevent,function(e){var a=(new Date).getTime();var f=n.data("lastTouch")||a+1;var l=a-f;window.clearTimeout(s);n.data("callee2",arguments.callee);if(l0&&e.target==i&&l>100){n.data("doubletapped",true);window.clearTimeout(r.tap_timer);var c={position:{x:r.touch_capable?u.touches[0].screenX:e.screenX,y:r.touch_capable?u.touches[0].screenY:e.screenY},offset:{x:r.touch_capable?u.touches[0].pageX-u.touches[0].target.offsetLeft:e.offsetX,y:r.touch_capable?u.touches[0].pageY-u.touches[0].target.offsetTop:e.offsetY},time:(new Date).getTime(),target:e.target};var h={firstTap:o,secondTap:c,interval:c.time-o.time};E(t,"doubletap",e,h)}else{n.data("lastTouch",a);s=window.setTimeout(function(e){window.clearTimeout(s)},r.doubletap_int,[e])}n.data("lastTouch",a)})},remove:function(){e(this).off(r.startevent,e(this).data.callee1).off(r.endevent,e(this).data.callee2)}};e.event.special.singletap={setup:function(){var t=this,n=e(t),i=null,s=null,o={x:0,y:0};n.on(r.startevent,function(e){if(e.which&&e.which!==1){return false}else{s=(new Date).getTime();i=e.target;n.data("callee1",arguments.callee);o.x=e.originalEvent.targetTouches?e.originalEvent.targetTouches[0].pageX:e.pageX;o.y=e.originalEvent.targetTouches?e.originalEvent.targetTouches[0].pageY:e.pageY;return true}}).on(r.endevent,function(e){n.data("callee2",arguments.callee);if(e.target==i){end_pos_x=e.originalEvent.changedTouches?e.originalEvent.changedTouches[0].pageX:e.pageX;end_pos_y=e.originalEvent.changedTouches?e.originalEvent.changedTouches[0].pageY:e.pageY;r.tap_timer=window.setTimeout(function(){if(!n.data("doubletapped")&&!n.data("tapheld")&&o.x==end_pos_x&&o.y==end_pos_y){var i=e.originalEvent;var u={position:{x:r.touch_capable?i.changedTouches[0].screenX:e.screenX,y:r.touch_capable?i.changedTouches[0].screenY:e.screenY},offset:{x:r.touch_capable?i.changedTouches[0].pageX-i.changedTouches[0].target.offsetLeft:e.offsetX,y:r.touch_capable?i.changedTouches[0].pageY-i.changedTouches[0].target.offsetTop:e.offsetY},time:(new Date).getTime(),target:e.target};if(u.time-s=-r.tap_pixel_range&&diff_x<=r.tap_pixel_range&&diff_y>=-r.tap_pixel_range&&diff_y<=r.tap_pixel_range)){var l=e.originalEvent;var c={position:{x:r.touch_capable?l.changedTouches[0].screenX:e.screenX,y:r.touch_capable?l.changedTouches[0].screenY:e.screenY},offset:{x:r.touch_capable?l.changedTouches[0].pageX-l.changedTouches[0].target.offsetLeft:e.offsetX,y:r.touch_capable?l.changedTouches[0].pageY-l.changedTouches[0].target.offsetTop:e.offsetY},time:(new Date).getTime(),target:e.target};E(t,"tap",e,c)}})},remove:function(){e(this).off(r.startevent,e(this).data.callee1).off(r.endevent,e(this).data.callee2)}};e.event.special.swipe={setup:function(){function f(t){n=e(t.target);n.data("callee1",arguments.callee);o.x=t.originalEvent.targetTouches?t.originalEvent.targetTouches[0].pageX:t.pageX;o.y=t.originalEvent.targetTouches?t.originalEvent.targetTouches[0].pageY:t.pageY;u.x=o.x;u.y=o.y;i=true;var s=t.originalEvent;a={position:{x:r.touch_capable?s.touches[0].screenX:t.screenX,y:r.touch_capable?s.touches[0].screenY:t.screenY},offset:{x:r.touch_capable?s.touches[0].pageX-s.touches[0].target.offsetLeft:t.offsetX,y:r.touch_capable?s.touches[0].pageY-s.touches[0].target.offsetTop:t.offsetY},time:(new Date).getTime(),target:t.target};var f=new Date;while(new Date-f<100){}}function l(t){n=e(t.target);n.data("callee2",arguments.callee);u.x=t.originalEvent.targetTouches?t.originalEvent.targetTouches[0].pageX:t.pageX;u.y=t.originalEvent.targetTouches?t.originalEvent.targetTouches[0].pageY:t.pageY;window.clearTimeout(r.hold_timer);var f;var l=n.data("xthreshold"),c=n.data("ythreshold"),h=typeof l!=="undefined"&&l!==false&&parseInt(l)?parseInt(l):r.swipe_h_threshold,p=typeof c!=="undefined"&&c!==false&&parseInt(c)?parseInt(c):r.swipe_v_threshold;if(o.y>u.y&&o.y-u.y>p){f="swipeup"}if(o.xh){f="swiperight"}if(o.yp){f="swipedown"}if(o.x>u.x&&o.x-u.x>h){f="swipeleft"}if(f!=undefined&&i){o.x=0;o.y=0;u.x=0;u.y=0;i=false;var d=t.originalEvent;endEvnt={position:{x:r.touch_capable?d.touches[0].screenX:t.screenX,y:r.touch_capable?d.touches[0].screenY:t.screenY},offset:{x:r.touch_capable?d.touches[0].pageX-d.touches[0].target.offsetLeft:t.offsetX,y:r.touch_capable?d.touches[0].pageY-d.touches[0].target.offsetTop:t.offsetY},time:(new Date).getTime(),target:t.target};var v=Math.abs(a.position.x-endEvnt.position.x),m=Math.abs(a.position.y-endEvnt.position.y);var g={startEvnt:a,endEvnt:endEvnt,direction:f.replace("swipe",""),xAmount:v,yAmount:m,duration:endEvnt.time-a.time};s=true;n.trigger("swipe",g).trigger(f,g)}}function c(t){n=e(t.target);var o="";n.data("callee3",arguments.callee);if(s){var u=n.data("xthreshold"),f=n.data("ythreshold"),l=typeof u!=="undefined"&&u!==false&&parseInt(u)?parseInt(u):r.swipe_h_threshold,c=typeof f!=="undefined"&&f!==false&&parseInt(f)?parseInt(f):r.swipe_v_threshold;var h=t.originalEvent;endEvnt={position:{x:r.touch_capable?h.changedTouches[0].screenX:t.screenX,y:r.touch_capable?h.changedTouches[0].screenY:t.screenY},offset:{x:r.touch_capable?h.changedTouches[0].pageX-h.changedTouches[0].target.offsetLeft:t.offsetX,y:r.touch_capable?h.changedTouches[0].pageY-h.changedTouches[0].target.offsetTop:t.offsetY},time:(new Date).getTime(),target:t.target};if(a.position.y>endEvnt.position.y&&a.position.y-endEvnt.position.y>c){o="swipeup"}if(a.position.xl){o="swiperight"}if(a.position.yc){o="swipedown"}if(a.position.x>endEvnt.position.x&&a.position.x-endEvnt.position.x>l){o="swipeleft"}var p=Math.abs(a.position.x-endEvnt.position.x),d=Math.abs(a.position.y-endEvnt.position.y);var v={startEvnt:a,endEvnt:endEvnt,direction:o.replace("swipe",""),xAmount:p,yAmount:d,duration:endEvnt.time-a.time};n.trigger("swipeend",v)}i=false;s=false}var t=this,n=e(t),i=false,s=false,o={x:0,y:0},u={x:0,y:0},a;n.on(r.startevent,f);n.on(r.moveevent,l);n.on(r.endevent,c)},remove:function(){e(this).off(r.startevent,e(this).data.callee1).off(r.moveevent,e(this).data.callee2).off(r.endevent,e(this).data.callee3)}};e.event.special.scrollstart={setup:function(){function o(e,n){i=n;E(t,i?"scrollstart":"scrollend",e)}var t=this,n=e(t),i,s;n.on(r.scrollevent,function(e){n.data("callee",arguments.callee);if(!i){o(e,true)}clearTimeout(s);s=setTimeout(function(){o(e,false)},50)})},remove:function(){e(this).off(r.scrollevent,e(this).data.callee)}};var i=e(window),s,o,u,a,f,l={0:true,180:true};if(r.orientation_support){var c=window.innerWidth||e(window).width(),h=window.innerHeight||e(window).height(),p=50;a=c>h&&c-h>p;f=l[window.orientation];if(a&&f||!a&&!f){l={"-90":true,90:true}}}e.event.special.orientationchange=s={setup:function(){if(r.orientation_support){return false}u=o();i.on("throttledresize",d);return true},teardown:function(){if(r.orientation_support){return false}i.off("throttledresize",d);return true},add:function(e){var t=e.handler;e.handler=function(e){e.orientation=o();return t.apply(this,arguments)}}};e.event.special.orientationchange.orientation=o=function(){var e=true,t=document.documentElement;if(r.orientation_support){e=l[window.orientation]}else{e=t&&t.clientWidth/t.clientHeight<1.1}return e?"portrait":"landscape"};e.event.special.throttledresize={setup:function(){e(this).on("resize",m)},teardown:function(){e(this).off("resize",m)}};var v=250,m=function(){b=(new Date).getTime();w=b-g;if(w>=v){g=b;e(this).trigger("throttledresize")}else{if(y){window.clearTimeout(y)}y=window.setTimeout(d,v-w)}},g=0,y,b,w;e.each({scrollend:"scrollstart",swipeup:"swipe",swiperight:"swipe",swipedown:"swipe",swipeleft:"swipe",swipeend:"swipe"},function(t,n,r){e.event.special[t]={setup:function(){e(this).on(n,e.noop)}}})})(jQuery) 2 | -------------------------------------------------------------------------------- /js/jquery.vintage.min.js: -------------------------------------------------------------------------------- 1 | /**! 2 | * vintageJS 3 | * Add a retro/vintage effect to images using the HTML5 canvas element 4 | * 5 | * @license Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. 6 | * @author Robert Fleischmann 7 | * @version 1.1.4 8 | **/ 9 | !function(a,b){"object"==typeof exports?module.exports=b(require("jquery")):"function"==typeof define&&define.amd?define("vintagejs",["jquery"],b):a.VintageJS=b(a.jQuery)}(this,function(a){var b=function(a,b,c){if(!1==a instanceof HTMLImageElement)throw"The element (1st parameter) must be an instance of HTMLImageElement";var d,e,f,g,h,i,j,k,l,m=new Image,n=new Image,o=document.createElement("canvas"),p=o.getContext("2d"),q={onStart:function(){},onStop:function(){},onError:function(){},mime:"image/jpeg"},r={curves:!1,screen:!1,desaturate:!1,vignette:!1,lighten:!1,noise:!1,viewFinder:!1,sepia:!1,brightness:!1,contrast:!1};m.onerror=q.onError,m.onload=function(){i=o.width=m.width,j=o.height=m.height,d()},n.onerror=q.onError,n.onload=function(){p.clearRect(0,0,i,j),p.drawImage(n,0,0,i,j),(window.vjsImageCache||(window.vjsImageCache={}))[l]=p.getImageData(0,0,i,j).data,d()},e=function(a){q.onStart(),k={};for(var b in r)k[b]=a[b]||r[b];g=[],k.viewFinder&&g.push(k.viewFinder),m.src==h?d():m.src=h},d=function(){if(0===g.length)return f();var a=g.pop();return l=[i,j,a].join("-"),window.vjsImageCache&&window.vjsImageCache[l]?d():(n.src=a,void 0)},f=function(){var b,c,d;p.clearRect(0,0,i,j),p.drawImage(m,0,0,i,j),(k.vignette||k.lighten)&&(b=Math.sqrt(Math.pow(i/2,2)+Math.pow(j/2,2))),k.vignette&&(p.globalCompositeOperation="source-over",c=p.createRadialGradient(i/2,j/2,0,i/2,j/2,b),c.addColorStop(0,"rgba(0,0,0,0)"),c.addColorStop(.5,"rgba(0,0,0,0)"),c.addColorStop(1,["rgba(0,0,0,",k.vignette,")"].join("")),p.fillStyle=c,p.fillRect(0,0,i,j)),k.lighten&&(p.globalCompositeOperation="lighter",c=p.createRadialGradient(i/2,j/2,0,i/2,j/2,b),c.addColorStop(0,["rgba(255,255,255,",k.lighten,")"].join("")),c.addColorStop(.5,"rgba(255,255,255,0)"),c.addColorStop(1,"rgba(0,0,0,0)"),p.fillStyle=c,p.fillRect(0,0,i,j)),d=p.getImageData(0,0,i,j);var e,f,g,h,l,n,o,r,s,t=d.data;k.contrast&&(s=259*(k.contrast+255)/(255*(259-k.contrast))),k.viewFinder&&(r=window.vjsImageCache[[i,j,k.viewFinder].join("-")]);for(var u=i*j;u>=0;--u)for(e=u<<2,k.curves&&(t[e]=k.curves.r[t[e]],t[e+1]=k.curves.g[t[e+1]],t[e+2]=k.curves.b[t[e+2]]),k.contrast&&(t[e]=s*(t[e]-128)+128,t[e+1]=s*(t[e+1]-128)+128,t[e+2]=s*(t[e+2]-128)+128),k.brightness&&(t[e]+=k.brightness,t[e+1]+=k.brightness,t[e+2]+=k.brightness),k.screen&&(t[e]=255-(255-t[e])*(255-k.screen.r*k.screen.a)/255,t[e+1]=255-(255-t[e+1])*(255-k.screen.g*k.screen.a)/255,t[e+2]=255-(255-t[e+2])*(255-k.screen.b*k.screen.a)/255),k.noise&&(o=k.noise-Math.random()*k.noise/2,t[e]+=o,t[e+1]+=o,t[e+2]+=o),k.viewFinder&&(t[e]=t[e]*r[e]/255,t[e+1]=t[e+1]*r[e+1]/255,t[e+2]=t[e+2]*r[e+2]/255),k.sepia&&(g=t[e],h=t[e+1],l=t[e+2],t[e]=.393*g+.769*h+.189*l,t[e+1]=.349*g+.686*h+.168*l,t[e+2]=.272*g+.534*h+.131*l),k.desaturate&&(n=(t[e]+t[e+1]+t[e+2])/3,t[e]+=(n-t[e])*k.desaturate,t[e+1]+=(n-t[e+1])*k.desaturate,t[e+2]+=(n-t[e+2])*k.desaturate),f=2;f>=0;--f)t[e+f]=~~(t[e+f]>255?255:t[e+f]<0?0:t[e+f]);p.putImageData(d,0,0),a.src=p.canvas.toDataURL(q.mime),q.onStop()},h=a.src,b=b||{};for(var s in q)q[s]=b[s]||q[s];return c&&e(c),{apply:function(){h=a.src},reset:function(){a.src=h},vintage:e}};return a.fn.vintage=function(c,d){return this.each(function(){a.data(this,"vintageJS")||a.data(this,"vintageJS",new b(this,c,d))})},b}); -------------------------------------------------------------------------------- /plugins/Bourgeois/EVENTS.txt: -------------------------------------------------------------------------------- 1 | Events that come with the Favorite plugin 2 | ========================================= 3 | 4 | EndFavorNotice: After saving a notice as a favorite 5 | - $profile: profile of the person faving (can be remote!) 6 | - $notice: notice being faved 7 | 8 | StartDisfavorNotice: Saving a notice as a favorite 9 | - $profile: profile of the person faving (can be remote!) 10 | - $notice: notice being faved 11 | - &$result: result of the disfavoring (if you override) 12 | 13 | EndDisfavorNotice: After saving a notice as a favorite 14 | - $profile: profile of the person faving (can be remote!) 15 | - $notice: notice being faved 16 | 17 | StartFavorNoticeForm: starting the data in the form for favoring a notice 18 | - $FavorForm: the favor form being shown 19 | - $notice: notice being favored 20 | 21 | EndFavorNoticeForm: Ending the data in the form for favoring a notice 22 | - $FavorForm: the favor form being shown 23 | - $notice: notice being favored 24 | 25 | StartDisFavorNoticeForm: starting the data in the form for disfavoring a notice 26 | - $DisfavorForm: the disfavor form being shown 27 | - $notice: notice being difavored 28 | 29 | EndDisFavorNoticeForm: Ending the data in the form for disfavoring a notice 30 | - $DisfavorForm: the disfavor form being shown 31 | - $notice: notice being disfavored 32 | 33 | StartShowFaveForm: just before showing the fave form 34 | - $item: the NoticeListItem object being shown 35 | 36 | EndShowFaveForm: just after showing the fave form 37 | - $item: the NoticeListItem object being shown 38 | 39 | -------------------------------------------------------------------------------- /plugins/Bourgeois/actions/bourgeois.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @category Public 23 | * @package StatusNet 24 | * @author Zach Copley 25 | * @author Evan Prodromou 26 | * @copyright 2008-2009 StatusNet, Inc. 27 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 28 | * @link http://status.net/ 29 | */ 30 | 31 | if (!defined('GNUSOCIAL')) { exit(1); } 32 | 33 | /** 34 | * List of popular notices 35 | * 36 | * We provide a list of the most popular notices. Popularity 37 | * is measured by 38 | * 39 | * @category Personal 40 | * @package StatusNet 41 | * @author Zach Copley 42 | * @author Evan Prodromou 43 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 44 | * @link http://status.net/ 45 | */ 46 | class BourgeoisAction extends Action 47 | { 48 | var $page = null; 49 | 50 | /** 51 | * Title of the page 52 | * 53 | * @return string Title of the page 54 | */ 55 | 56 | function title() 57 | { 58 | if ($this->page == 1) { 59 | // TRANS: Page title for first page of favorited notices. 60 | return _('Bourgeois notices'); 61 | } else { 62 | // TRANS: Page title for all but first page of favorited notices. 63 | // TRANS: %d is the page number being displayed. 64 | return sprintf(_('Bourgeois notices, page %d'), $this->page); 65 | } 66 | } 67 | 68 | /** 69 | * Instructions for use 70 | * 71 | * @return instructions for use 72 | */ 73 | function getInstructions() 74 | { 75 | // TRANS: Description on page displaying favorited notices. 76 | return _('The most bourgeois notices on the site right now.'); 77 | } 78 | 79 | /** 80 | * Is this page read-only? 81 | * 82 | * @return boolean true 83 | */ 84 | function isReadOnly($args) 85 | { 86 | return true; 87 | } 88 | 89 | /** 90 | * Take arguments for running 91 | * 92 | * @param array $args $_REQUEST args 93 | * 94 | * @return boolean success flag 95 | * 96 | * @todo move queries from showContent() to here 97 | */ 98 | function prepare($args) 99 | { 100 | parent::prepare($args); 101 | $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; 102 | 103 | common_set_returnto($this->selfUrl()); 104 | 105 | return true; 106 | } 107 | 108 | /** 109 | * Handle request 110 | * 111 | * Shows a page with list of favorite notices 112 | * 113 | * @param array $args $_REQUEST args; handled in prepare() 114 | * 115 | * @return void 116 | */ 117 | function handle($args) 118 | { 119 | parent::handle($args); 120 | 121 | $this->showPage(); 122 | } 123 | 124 | /** 125 | * Show the page notice 126 | * 127 | * Shows instructions for the page 128 | * 129 | * @return void 130 | */ 131 | function showPageNotice() 132 | { 133 | $instr = $this->getInstructions(); 134 | $output = common_markup_to_html($instr); 135 | 136 | $this->elementStart('div', 'instructions'); 137 | $this->raw($output); 138 | $this->elementEnd('div'); 139 | } 140 | 141 | function showEmptyList() 142 | { 143 | // TRANS: Text displayed instead of a list when a site does not yet have any favourited notices. 144 | $message = _('Bourgeois notices appear on this page but no one has been marked as bourgeois yet.') . ' '; 145 | 146 | if (common_logged_in()) { 147 | // TRANS: Additional text displayed instead of a list when a site does not yet have any favourited notices for logged in users. 148 | $message .= _('Be the first to add a notice to your bourgeois notices by clicking the "mark as bourgeois" button next to any notice you think is bourgeois.'); 149 | } 150 | else { 151 | // TRANS: Additional text displayed instead of a list when a site does not yet have any favourited notices for not logged in users. 152 | // TRANS: %%action.register%% is a registration link. "[link text](link)" is Mark Down. Do not change the formatting. 153 | $message .= _('Why not [register an account](%%action.register%%) and be the first to mark a notice as bourgeois!'); 154 | } 155 | 156 | $this->elementStart('div', 'guide'); 157 | $this->raw(common_markup_to_html($message)); 158 | $this->elementEnd('div'); 159 | } 160 | 161 | /** 162 | * Content area 163 | * 164 | * Shows the list of popular notices 165 | * 166 | * @return void 167 | */ 168 | function showContent() 169 | { 170 | $stream = new AllBourgeoisNoticeStream(Profile::current()); 171 | $notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE+1); 172 | 173 | $nl = new NoticeList($notice, $this); 174 | 175 | $cnt = $nl->show(); 176 | 177 | if ($cnt == 0) { 178 | $this->showEmptyList(); 179 | } 180 | 181 | $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, 182 | $this->page, 'bourgeois'); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /plugins/Bourgeois/actions/bourgeoisrss.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Robin Millette 11 | * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 12 | * @link http://status.net/ 13 | * 14 | * StatusNet - the distributed open-source microblogging tool 15 | * Copyright (C) 2008, 2009, StatusNet, Inc. 16 | * 17 | * This program is free software: you can redistribute it and/or modify 18 | * it under the terms of the GNU Affero General Public License as published by 19 | * the Free Software Foundation, either version 3 of the License, or 20 | * (at your option) any later version. 21 | * 22 | * This program is distributed in the hope that it will be useful, 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | * GNU Affero General Public License for more details. 26 | * 27 | * You should have received a copy of the GNU Affero General Public License 28 | * along with this program. If not, see . 29 | */ 30 | 31 | if (!defined('GNUSOCIAL')) { exit(1); } 32 | 33 | /** 34 | * RSS feed for user favorites action class. 35 | * 36 | * Formatting of RSS handled by Rss10Action 37 | * 38 | * @category Action 39 | * @package StatusNet 40 | * @author Evan Prodromou 41 | * @author Robin Millette 42 | * @author Zach Copley 43 | * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 44 | * @link http://status.net/ 45 | */ 46 | class BourgeoisrssAction extends TargetedRss10Action 47 | { 48 | protected function getNotices() 49 | { 50 | // is this our own stream? 51 | $own = $this->scoped instanceof Profile ? $this->target->getID() === $this->scoped->getID() : false; 52 | 53 | $stream = Bourgeois::stream($this->target->getID(), 0, $this->limit, $own); 54 | return $stream->fetchAll(); 55 | } 56 | 57 | /** 58 | * Get channel. 59 | * 60 | * @return array associative array on channel information 61 | */ 62 | function getChannel() 63 | { 64 | $user = $this->user; 65 | $c = array('url' => common_local_url('bourgeoisrss', 66 | array('nickname' => 67 | $user->nickname)), 68 | // TRANS: Title of RSS feed with favourite notices of a user. 69 | // TRANS: %s is a user's nickname. 70 | 'title' => sprintf(_("notices marked as bourgeois by %s"), $user->nickname), 71 | 'link' => common_local_url('showbourgeois', 72 | array('nickname' => 73 | $user->nickname)), 74 | // TRANS: Desciption of RSS feed with favourite notices of a user. 75 | // TRANS: %1$s is a user's nickname, %2$s is the name of the StatusNet site. 76 | 'description' => sprintf(_('Notices marked as bourgeois by %1$s on %2$s!'), 77 | $user->nickname, common_config('site', 'name'))); 78 | return $c; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /plugins/Bourgeois/actions/showbourgeois.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @category Personal 23 | * @package StatusNet 24 | * @author Evan Prodromou 25 | * @copyright 2008-2011 StatusNet, Inc. 26 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 27 | * @link http://status.net/ 28 | */ 29 | 30 | if (!defined('GNUSOCIAL')) { exit(1); } 31 | 32 | /** 33 | * List of replies 34 | * 35 | * @category Personal 36 | * @package StatusNet 37 | * @author Evan Prodromou 38 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 39 | * @link http://status.net/ 40 | */ 41 | class ShowbourgeoisAction extends ShowstreamAction 42 | { 43 | function title() 44 | { 45 | if ($this->page == 1) { 46 | // TRANS: Title for first page of favourite notices of a user. 47 | // TRANS: %s is the user for whom the favourite notices are displayed. 48 | return sprintf(_('notices marked as bourgeois by %s'), $this->getTarget()->getNickname()); 49 | } else { 50 | // TRANS: Title for all but the first page of favourite notices of a user. 51 | // TRANS: %1$s is the user for whom the favourite notices are displayed, %2$d is the page number. 52 | return sprintf(_('notices marked as bourgeois by %1$s, page %2$d'), 53 | $this->getTarget()->getNickname(), 54 | $this->page); 55 | } 56 | } 57 | 58 | public function getStream() 59 | { 60 | $own = $this->scoped instanceof Profile ? $this->scoped->sameAs($this->getTarget()) : false; 61 | return new BourgeoisNoticeStream($this->getTarget()->getID(), $own); 62 | } 63 | 64 | function getFeeds() 65 | { 66 | return array(new Feed(Feed::RSS1, 67 | common_local_url('bourgeoisrss', 68 | array('nickname' => $this->user->nickname)), 69 | // TRANS: Feed link text. %s is a username. 70 | sprintf(_('Feed for notices marked as bourgeois by %s (RSS 1.0)'), 71 | $this->user->nickname))); 72 | } 73 | 74 | function showEmptyListMessage() 75 | { 76 | if (common_logged_in()) { 77 | $current_user = common_current_user(); 78 | if ($this->user->id === $current_user->id) { 79 | // TRANS: Text displayed instead of favourite notices for the current logged in user that has no favourites. 80 | $message = _('You haven\'t marked any notices as bourgeois yet. Click the "mark as bourgeois" button on notices you think is bourgeois.'); 81 | } else { 82 | // TRANS: Text displayed instead of favourite notices for a user that has no favourites while logged in. 83 | // TRANS: %s is a username. 84 | $message = sprintf(_('%s hasn\'t marked any notices as bourgeois yet. Post something bourgeois :)'), $this->user->nickname); 85 | } 86 | } 87 | else { 88 | // TRANS: Text displayed instead of favourite notices for a user that has no favourites while not logged in. 89 | // TRANS: %s is a username, %%%%action.register%%%% is a link to the user registration page. 90 | // TRANS: (link text)[link] is a Mark Down link. 91 | $message = sprintf(_('%s hasn\'t marked any notices as bourgeois yet. Why not [register an account](%%%%action.register%%%%) and then post something bourgeois :)'), $this->user->nickname); 92 | } 93 | 94 | $this->elementStart('div', 'guide'); 95 | $this->raw(common_markup_to_html($message)); 96 | $this->elementEnd('div'); 97 | } 98 | 99 | /** 100 | * Show the content 101 | * 102 | * A list of notices that this user has marked as a favorite 103 | * 104 | * @return void 105 | */ 106 | function showNotices() 107 | { 108 | $nl = new BourgeoisNoticeList($this->notice, $this); 109 | 110 | $cnt = $nl->show(); 111 | if (0 == $cnt) { 112 | $this->showEmptyListMessage(); 113 | } 114 | 115 | $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, 116 | $this->page, 'showbourgeois', 117 | array('nickname' => $this->getTarget()->getNickname())); 118 | } 119 | 120 | function showPageNotice() { 121 | // TRANS: Page notice for show favourites page. 122 | $this->element('p', 'instructions', _('This is a way to share what you like.')); 123 | } 124 | } 125 | 126 | class BourgeoisNoticeList extends NoticeList 127 | { 128 | function newListItem($notice) 129 | { 130 | return new BourgeoisNoticeListItem($notice, $this->out); 131 | } 132 | } 133 | 134 | // All handled by superclass 135 | class BourgeoisNoticeListItem extends DoFollowListItem 136 | { 137 | } 138 | -------------------------------------------------------------------------------- /plugins/Bourgeois/forms/markbourgeois.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @category Form 23 | * @package GNUsocial 24 | * @author Evan Prodromou 25 | * @author Sarven Capadisli 26 | * @author Mikael Nordfeldth 27 | * @copyright 2009 StatusNet, Inc. 28 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 29 | * @link http://www.gnu.org/software/social/ 30 | */ 31 | 32 | if (!defined('GNUSOCIAL')) { exit(1); } 33 | 34 | /** 35 | * Form for favoring a notice 36 | * 37 | * @category Form 38 | * @package GNUsocial 39 | * @author Evan Prodromou 40 | * @author Sarven Capadisli 41 | * @author Mikael Nordfeldth 42 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 43 | * @link http://www.gnu.org/software/social/ 44 | * 45 | * @see DisfavorForm 46 | */ 47 | class MarkBourgeoisForm extends Form 48 | { 49 | /** 50 | * Notice to favor 51 | */ 52 | var $notice = null; 53 | 54 | /** 55 | * Constructor 56 | * 57 | * @param HTMLOutputter $out output channel 58 | * @param Notice $notice notice to favor 59 | */ 60 | function __construct($out=null, $notice=null) 61 | { 62 | parent::__construct($out); 63 | 64 | $this->notice = $notice; 65 | } 66 | 67 | /** 68 | * ID of the form 69 | * 70 | * @return int ID of the form 71 | */ 72 | function id() 73 | { 74 | return 'markbourgeois-' . $this->notice->id; 75 | } 76 | 77 | /** 78 | * Action of the form 79 | * 80 | * @return string URL of the action 81 | */ 82 | function action() 83 | { 84 | return common_local_url('activityverb', 85 | array('id' => $this->notice->getID(), 86 | 'verb' => ActivityUtils::resolveUri('http://activitystrea.ms/schema/1.0/bourgeois', true))); 87 | } 88 | 89 | /** 90 | * Legend of the Form 91 | * 92 | * @return void 93 | */ 94 | function formLegend() 95 | { 96 | // TRANS: Form legend for adding the favourite status to a notice. 97 | $this->out->element('legend', null, _('Mark this notice as bourgeois')); 98 | } 99 | 100 | /** 101 | * Data elements 102 | * 103 | * @return void 104 | */ 105 | function formData() 106 | { 107 | if (Event::handle('StartMarkBourgeoisNoticeForm', array($this, $this->notice))) { 108 | $this->out->hidden('notice-n'.$this->notice->id, 109 | $this->notice->id, 110 | 'notice'); 111 | Event::handle('EndMarkBourgeoisNoticeForm', array($this, $this->notice)); 112 | } 113 | } 114 | 115 | /** 116 | * Action elements 117 | * 118 | * @return void 119 | */ 120 | function formActions() 121 | { 122 | $this->out->submit('markbourgeois-submit-' . $this->notice->id, 123 | // TRANS: Button text for adding the favourite status to a notice. 124 | _m('BUTTON','Mark as bourgeois'), 125 | 'submit', 126 | null, 127 | // TRANS: Button title for adding the favourite status to a notice. 128 | _('Borgerligt!')); 129 | } 130 | 131 | /** 132 | * Class of the form. 133 | * 134 | * @return string the form's class 135 | */ 136 | function formClass() 137 | { 138 | return 'form_markbourgeois ajax'; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /plugins/Bourgeois/forms/unmarkbourgeois.php: -------------------------------------------------------------------------------- 1 | . 21 | * 22 | * @category Form 23 | * @package GNUsocial 24 | * @author Evan Prodromou 25 | * @author Sarven Capadisli 26 | * @author Mikael Nordfeldth 27 | * @copyright 2009 StatusNet, Inc. 28 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 29 | * @link http://www.gnu.org/software/social/ 30 | */ 31 | 32 | if (!defined('GNUSOCIAL')) { exit(1); } 33 | 34 | /** 35 | * Form for disfavoring a notice 36 | * 37 | * @category Form 38 | * @package GNUsocial 39 | * @author Evan Prodromou 40 | * @author Sarven Capadisli 41 | * @author Mikael Nordfeldth 42 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 43 | * @link http://www.gnu.org/software/social/ 44 | * 45 | * @see FavorForm 46 | */ 47 | class UnmarkBourgeoisForm extends Form 48 | { 49 | /** 50 | * Notice to disfavor 51 | */ 52 | var $notice = null; 53 | 54 | /** 55 | * Constructor 56 | * 57 | * @param HTMLOutputter $out output channel 58 | * @param Notice $notice notice to disfavor 59 | */ 60 | function __construct($out=null, $notice=null) 61 | { 62 | parent::__construct($out); 63 | 64 | $this->notice = $notice; 65 | } 66 | 67 | /** 68 | * ID of the form 69 | * 70 | * @return int ID of the form 71 | */ 72 | function id() 73 | { 74 | return 'unmarkbourgeois-' . $this->notice->id; 75 | } 76 | 77 | /** 78 | * Action of the form 79 | * 80 | * @return string URL of the action 81 | */ 82 | function action() 83 | { 84 | return common_local_url('activityverb', 85 | array('id' => $this->notice->getID(), 86 | 'verb' => ActivityUtils::resolveUri('http://activitystrea.ms/schema/1.0/unmarkbourgeois', true))); 87 | } 88 | 89 | /** 90 | * Legend of the Form 91 | * 92 | * @return void 93 | */ 94 | function formLegend() 95 | { 96 | // TRANS: Form legend for removing the favourite status for a favourite notice. 97 | $this->out->element('legend', null, _('Unmark this notice as bourgeois')); 98 | } 99 | 100 | /** 101 | * Data elements 102 | * 103 | * @return void 104 | */ 105 | 106 | function formData() 107 | { 108 | if (Event::handle('StartUnmarkBourgeoisNoticeForm', array($this, $this->notice))) { 109 | $this->out->hidden('notice-n'.$this->notice->id, 110 | $this->notice->id, 111 | 'notice'); 112 | Event::handle('EndUnmarkBourgeoisNoticeForm', array($this, $this->notice)); 113 | } 114 | } 115 | 116 | /** 117 | * Action elements 118 | * 119 | * @return void 120 | */ 121 | function formActions() 122 | { 123 | $this->out->submit('unmarkbourgeois-submit-' . $this->notice->id, 124 | // TRANS: Button text for removing the favourite status for a favourite notice. 125 | _m('BUTTON','Unmark as bourgeois'), 126 | 'submit', 127 | null, 128 | // TRANS: Button title for removing the favourite status for a favourite notice. 129 | _('Remove this notice from your list of bourgeois notices.')); 130 | } 131 | 132 | /** 133 | * Class of the form. 134 | * 135 | * @return string the form's class 136 | */ 137 | function formClass() 138 | { 139 | return 'form_unmarkbourgeois ajax'; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /plugins/Bourgeois/lib/allbourgeoisnoticestream.php: -------------------------------------------------------------------------------- 1 | . 22 | * 23 | * @category Popular 24 | * @package StatusNet 25 | * @author Evan Prodromou 26 | * @copyright 2011 StatusNet, Inc. 27 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 28 | * @link http://status.net/ 29 | */ 30 | 31 | if (!defined('STATUSNET')) { 32 | // This check helps protect against security problems; 33 | // your code file can't be executed directly from the web. 34 | exit(1); 35 | } 36 | 37 | /** 38 | * Stream of notices sorted by popularity 39 | * 40 | * @category Popular 41 | * @package StatusNet 42 | * @author Evan Prodromou 43 | * @copyright 2011 StatusNet, Inc. 44 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 45 | * @link http://status.net/ 46 | */ 47 | 48 | class AllBourgeoisNoticeStream extends ScopingNoticeStream 49 | { 50 | function __construct($profile=null) 51 | { 52 | parent::__construct(new CachingNoticeStream(new RawAllBourgeoisNoticeStream(), 53 | 'allbourgeois', 54 | false), 55 | $profile); 56 | } 57 | } 58 | 59 | class RawAllBourgeoisNoticeStream extends NoticeStream 60 | { 61 | function getNoticeIds($offset, $limit, $since_id, $max_id) 62 | { 63 | $weightexpr = common_sql_weight('modified', common_config('popular', 'dropoff')); 64 | $cutoff = sprintf("modified > '%s'", 65 | common_sql_date(time() - common_config('popular', 'cutoff'))); 66 | 67 | $bourgeois = new Bourgeois(); 68 | $bourgeois->selectAdd(); 69 | $bourgeois->selectAdd('notice_id'); 70 | $bourgeois->selectAdd("$weightexpr as weight"); 71 | $bourgeois->whereAdd($cutoff); 72 | $bourgeois->orderBy('weight DESC'); 73 | $bourgeois->groupBy('notice_id'); 74 | 75 | if (!is_null($offset)) { 76 | $bourgeois->limit($offset, $limit); 77 | } 78 | 79 | // FIXME: $since_id, $max_id are ignored 80 | 81 | $ids = array(); 82 | 83 | if ($bourgeois->find()) { 84 | while ($bourgeois->fetch()) { 85 | $ids[] = $bourgeois->notice_id; 86 | } 87 | } 88 | 89 | return $ids; 90 | } 91 | } 92 | 93 | -------------------------------------------------------------------------------- /plugins/Bourgeois/lib/bourgeoisnoticestream.php: -------------------------------------------------------------------------------- 1 | . 22 | * 23 | * @category Stream 24 | * @package StatusNet 25 | * @author Evan Prodromou 26 | * @copyright 2011 StatusNet, Inc. 27 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 28 | * @link http://status.net/ 29 | */ 30 | 31 | if (!defined('STATUSNET')) { 32 | // This check helps protect against security problems; 33 | // your code file can't be executed directly from the web. 34 | exit(1); 35 | } 36 | 37 | /** 38 | * Notice stream for favorites 39 | * 40 | * @category Stream 41 | * @package StatusNet 42 | * @author Evan Prodromou 43 | * @copyright 2011 StatusNet, Inc. 44 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 45 | * @link http://status.net/ 46 | */ 47 | class BourgeoisNoticeStream extends ScopingNoticeStream 48 | { 49 | function __construct($user_id, $own, $profile = -1) 50 | { 51 | $stream = new RawBourgeoisNoticeStream($user_id, $own); 52 | if ($own) { 53 | $key = 'bourgeois:ids_by_user_own:'.$user_id; 54 | } else { 55 | $key = 'bourgeois:ids_by_user:'.$user_id; 56 | } 57 | if (is_int($profile) && $profile == -1) { 58 | $profile = Profile::current(); 59 | } 60 | parent::__construct(new CachingNoticeStream($stream, $key), 61 | $profile); 62 | } 63 | } 64 | 65 | /** 66 | * Raw notice stream for favorites 67 | * 68 | * @category Stream 69 | * @package StatusNet 70 | * @author Evan Prodromou 71 | * @copyright 2011 StatusNet, Inc. 72 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 73 | * @link http://status.net/ 74 | */ 75 | class RawBourgeoisNoticeStream extends NoticeStream 76 | { 77 | protected $user_id; 78 | protected $own; 79 | 80 | function __construct($user_id, $own) 81 | { 82 | parent::__construct(); 83 | 84 | $this->user_id = $user_id; 85 | $this->own = $own; 86 | 87 | $this->selectVerbs = array(); 88 | } 89 | 90 | /** 91 | * Note that the sorting for this is by order of *fave* not order of *notice*. 92 | * 93 | * @fixme add since_id, max_id support? 94 | * 95 | * @param $user_id 96 | * @param $own 97 | * @param $offset 98 | * @param $limit 99 | * @param $since_id 100 | * @param $max_id 101 | * @return 102 | */ 103 | function getNoticeIds($offset, $limit, $since_id, $max_id) 104 | { 105 | $bourgeois = new Bourgeois(); 106 | $qry = null; 107 | 108 | if ($this->own) { 109 | $qry = 'SELECT bourgeois.* FROM bourgeois '; 110 | $qry .= 'WHERE bourgeois.user_id = ' . $this->user_id . ' '; 111 | } else { 112 | $qry = 'SELECT bourgeois.* FROM bourgeois '; 113 | $qry .= 'INNER JOIN notice ON bourgeois.notice_id = notice.id '; 114 | $qry .= 'WHERE bourgeois.user_id = ' . $this->user_id . ' '; 115 | $qry .= 'AND notice.is_local != ' . Notice::GATEWAY . ' '; 116 | } 117 | 118 | if ($since_id != 0) { 119 | $qry .= 'AND notice_id > ' . $since_id . ' '; 120 | } 121 | 122 | if ($max_id != 0) { 123 | $qry .= 'AND notice_id <= ' . $max_id . ' '; 124 | } 125 | 126 | // NOTE: we sort by fave time, not by notice time! 127 | 128 | $qry .= 'ORDER BY modified DESC '; 129 | 130 | if (!is_null($offset)) { 131 | $qry .= "LIMIT $limit OFFSET $offset"; 132 | } 133 | 134 | $bourgeois->query($qry); 135 | 136 | $ids = array(); 137 | 138 | while ($bourgeois->fetch()) { 139 | $ids[] = $bourgeois->notice_id; 140 | } 141 | 142 | $bourgeois->free(); 143 | unset($bourgeois); 144 | 145 | return $ids; 146 | } 147 | } 148 | 149 | -------------------------------------------------------------------------------- /plugins/Bourgeois/lib/threadednoticelistbourgeoisitem.php: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | 20 | if (!defined('GNUSOCIAL')) { exit(1); } 21 | 22 | /** 23 | * Placeholder for showing faves... 24 | */ 25 | class ThreadedNoticeListBourgeoisItem extends NoticeListActorsItem 26 | { 27 | function getProfiles() 28 | { 29 | $bourgeois = Bourgeois::byNotice($this->notice); 30 | $profiles = array(); 31 | foreach ($bourgeois as $bourg) { 32 | $profiles[] = $bourg->user_id; 33 | } 34 | return $profiles; 35 | } 36 | 37 | function magicList($items) 38 | { 39 | if (count($items) > 4) { 40 | return parent::magicList(array_slice($items, 0, 3)); 41 | } else { 42 | return parent::magicList($items); 43 | } 44 | } 45 | 46 | function getListMessage($count, $you) 47 | { 48 | if ($count == 1 && $you) { 49 | // darn first person being different from third person! 50 | // TRANS: List message for notice favoured by logged in user. 51 | return _m('BOURGEOISLIST', 'You think this is bourgeois.'); 52 | } else if ($count > 4) { 53 | // TRANS: List message for when more than 4 people like something. 54 | // TRANS: %%s is a list of users liking a notice, %d is the number over 4 that like the notice. 55 | // TRANS: Plural is decided on the total number of users liking the notice (count of %%s + %d). 56 | return sprintf(_m('%%s and %d others think this is bourgeois.', 57 | '%%s and %d others think this is bourgeois.', 58 | $count), 59 | $count - 3); 60 | } else { 61 | // TRANS: List message for favoured notices. 62 | // TRANS: %%s is a list of users liking a notice. 63 | // TRANS: Plural is based on the number of of users that have favoured a notice. 64 | return sprintf(_m('%%s thinks this is bourgeois.', 65 | '%%s think this is bourgeois.', 66 | $count), 67 | $count); 68 | } 69 | } 70 | 71 | function showStart() 72 | { 73 | $this->out->elementStart('li', array('class' => 'notice-data notice-bourgeois')); 74 | } 75 | 76 | function showEnd() 77 | { 78 | $this->out->elementEnd('li'); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /plugins/Bourgeois/lib/threadednoticelistinlinebourgeoisitem.php: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | 20 | if (!defined('GNUSOCIAL')) { exit(1); } 21 | 22 | // @todo FIXME: needs documentation. 23 | class ThreadedNoticeListInlineBourgeoisItem extends ThreadedNoticeListFavesItem 24 | { 25 | function showStart() 26 | { 27 | $this->out->elementStart('div', array('class' => 'notice-bourgeois')); 28 | } 29 | 30 | function showEnd() 31 | { 32 | $this->out->elementEnd('div'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /plugins/Bourgeois/locale/sv/LC_MESSAGES/Bourgeois.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # Hannes Mannerheim , 2015 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: GNU social\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2015-02-02 17:47+0100\n" 12 | "PO-Revision-Date: 2015-12-26 16:42+0000\n" 13 | "Last-Translator: Hannes Mannerheim \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Language: sv\n" 18 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 19 | 20 | #. TRANS: Button text for adding the favourite status to a notice. 21 | #: forms/markbourgeois.php:124 22 | msgctxt "BUTTON" 23 | msgid "Mark as bourgeois" 24 | msgstr "Markera som borgerligt" 25 | 26 | #. TRANS: Button text for adding the favourite status to a notice. 27 | #: forms/markbourgeois.php:128 28 | msgctxt "BUTTON" 29 | msgid "Add this notice to your list of bourgeois notices." 30 | msgstr "Markera som borgerligt" 31 | 32 | 33 | #. TRANS: Button text for removing the favourite status for a favourite 34 | #. notice. 35 | #: forms/unmarkbourgeois.php:125 36 | msgctxt "BUTTON" 37 | msgid "Unmark as bourgeois" 38 | msgstr "Avmarkera som borgerligt" 39 | 40 | #. TRANS: Button text for removing the favourite status for a favourite 41 | #. notice. 42 | #: forms/unmarkbourgeois.php:129 43 | msgctxt "BUTTON" 44 | msgid "Remove this notice from your list of bourgeois notices." 45 | msgstr "Avmarkera som borgerligt" 46 | 47 | #. TRANS: Menu item in personal group navigation menu. 48 | #: BourgeoisPlugin.php:469 49 | msgctxt "MENU" 50 | msgid "Bourgeois" 51 | msgstr "Borgerligt" 52 | 53 | #. TRANS: Menu item in search group navigation panel. 54 | #: BourgeoisPlugin.php:482 55 | msgctxt "MENU" 56 | msgid "Bourgeois notices" 57 | msgstr "Borgerliga notiser" 58 | 59 | #. TRANS: List message for notice favoured by logged in user. 60 | #: lib/threadednoticelistbourgeoisitem.php:51 61 | msgctxt "FAVELIST" 62 | msgid "You think this is bourgeois." 63 | msgstr "Du tycker att det här är borgerligt" 64 | 65 | #. TRANS: List message for when more than 4 people like something. 66 | #. TRANS: %%s is a list of users liking a notice, %d is the number over 4 that 67 | #. like the notice. 68 | #. TRANS: Plural is decided on the total number of users liking the notice 69 | #. (count of %%s + %d). 70 | #: lib/threadednoticelistbourgeoisitem.php:56 71 | #, php-format 72 | msgid "%%s and %d others think this is bourgeois." 73 | msgid_plural "%%s and %d others think this is bourgeois." 74 | msgstr[0] "" 75 | msgstr[1] "" 76 | 77 | #. TRANS: List message for favoured notices. 78 | #. TRANS: %%s is a list of users liking a notice. 79 | #. TRANS: Plural is based on the number of of users that have favoured a 80 | #. notice. 81 | #: lib/threadednoticelistfavesitem.php:64 82 | #, php-format 83 | msgid "%%s thinks this is bourgeois." 84 | msgid_plural "%%s think this is bourgeois." 85 | msgstr[0] "" 86 | msgstr[1] "" 87 | --------------------------------------------------------------------------------