├── assets ├── vendors │ └── achtung │ │ ├── version.txt │ │ ├── LICENSE.txt │ │ ├── AUTHORS.txt │ │ ├── ui.achtung.css │ │ ├── ui.achtung.min.js │ │ └── ui.achtung.js └── js │ └── bpln.js ├── languages ├── bp-live-notifications-en_US.mo └── bp-live-notifications-en_US.po ├── core ├── bp-live-notifications-ajax-handler.php └── bp-live-notifications-functions.php ├── readme.txt └── bp-live-notification.php /assets/vendors/achtung/version.txt: -------------------------------------------------------------------------------- 1 | 0.3.0 -------------------------------------------------------------------------------- /languages/bp-live-notifications-en_US.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbrajesh/bp-live-notification/HEAD/languages/bp-live-notifications-en_US.mo -------------------------------------------------------------------------------- /languages/bp-live-notifications-en_US.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: BuddyPress Live Notification\n" 4 | "POT-Creation-Date: 2018-10-28 02:09+0530\n" 5 | "PO-Revision-Date: 2018-10-28 02:09+0530\n" 6 | "Last-Translator: \n" 7 | "Language-Team: BuddyDev\n" 8 | "Language: en\n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "X-Generator: Poedit 1.8.7.1\n" 13 | "X-Poedit-Basepath: ..\n" 14 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 15 | "X-Poedit-KeywordsList: __;_e\n" 16 | "X-Poedit-SearchPath-0: .\n" 17 | -------------------------------------------------------------------------------- /assets/vendors/achtung/LICENSE.txt: -------------------------------------------------------------------------------- 1 | achtung 0.3.0 2 | Copyright (c) 2009 Josh Varner, http://achtung-ui.googlecode.com/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/vendors/achtung/AUTHORS.txt: -------------------------------------------------------------------------------- 1 | achtung 0.3.0 2 | 3 | Josh Varner 4 | http://achtung-ui.googlecode.com/ 5 | 6 | =============================================================================== 7 | For portions from jQuery UI: 8 | =============================================================================== 9 | 10 | jQuery UI Authors (http://ui.jquery.com/about) 11 | 12 | This software consists of voluntary contributions made by many 13 | individuals. For exact contribution history, see the revision history 14 | and logs, available at http://jquery-ui.googlecode.com/svn/ 15 | 16 | Brandon Aaron 17 | Paul Bakaus (paulbakaus.com) 18 | David Bolter 19 | Rich Caloggero 20 | Chi Cheng (cloudream@gmail.com) 21 | Colin Clark (http://colin.atrc.utoronto.ca/) 22 | Michelle D'Souza 23 | Aaron Eisenberger (aaronchi@gmail.com) 24 | Ariel Flesler 25 | Bohdan Ganicky 26 | Scott González 27 | Marc Grabanski (m@marcgrabanski.com) 28 | Klaus Hartl (stilbuero.de) 29 | Scott Jehl 30 | Cody Lindley 31 | Eduardo Lundgren (eduardolundgren@gmail.com) 32 | Todd Parker 33 | John Resig 34 | Patty Toland 35 | Ca-Phun Ung (yelotofu.com) 36 | Keith Wood (kbwood@virginbroadband.com.au) 37 | Maggie Costello Wachs 38 | Richard D. Worth (rdworth.org) 39 | Jörn Zaefferer (bassistance.de) 40 | -------------------------------------------------------------------------------- /core/bp-live-notifications-ajax-handler.php: -------------------------------------------------------------------------------- 1 | $notifications, 45 | 'last_notified' => $last_notified_id, 46 | ); 47 | 48 | return $response; 49 | } 50 | 51 | add_filter( 'heartbeat_received', 'bpln_process_notification_request', 10, 3 ); 52 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === BuddyPress Live Notification === 2 | Contributors: buddydev,anusharma,sbrajesh 3 | Tags: buddypress, notifications, buddypress-live-notification 4 | Requires at least: 4.5 5 | Tested up to: 5.5.1 6 | Stable tag: 2.1.1 7 | License: GPLv2 8 | License URI: http://www.gnu.org/licenses/gpl-2.0.html 9 | 10 | BuddyPress Live Notification adds a Facebook Like realtime user notifications for BuddyPress sites. 11 | 12 | == Description == 13 | 14 | BuddyPress Live Notification adds Facebook Like real-time notifications for user. 15 | 16 | = How it works:- = 17 | Shows live notifications to other members on a BuddyPress based social network. The new and improved version uses WordPress heartbeat api to fetch notifications 18 | and allows a theme author to implement their own ui for notifying the update. 19 | 20 | Please do let us know your thoughts & suggestion on our blog [BuddyDev](https://buddydev.com/buddypress/introducing-buddypress-live-notification-2-0/) 21 | 22 | **Do you need more awesome BuddyPress Plugins?** Checkout [BuddyPress Plugins by BuddyDev](https://buddydev.com/plugins/) 23 | == Installation == 24 | 25 | This section describes how to install the plugin and get it working. 26 | 27 | 28 | 1. Download the zip file and extract 29 | 1. Upload `bp-live-notification` directory to the `/wp-content/plugins/` directory 30 | 1. Activate the plugin through the 'Plugins' menu. 31 | 1. Alternatively you can use WordPress Plugin installer from Dashboard->Plugins->Add New to add this plugin 32 | 1. Enjoy 33 | 34 | == Frequently Asked Questions == 35 | 36 | = Does This plugin works without BuddyPress = 37 | No, It needs you to have BuddyPress installed and activated and the BuddyPress notifications component must be enabled 38 | 39 | = Where Do I Ask for support? = 40 | Please visit [BuddyDev](https://buddydev.com/support/forums/) for support. 41 | 42 | == Screenshots == 43 | 44 | 1. This shows live notification message screenshot-1.png 45 | 1. This shows live update of notification bar screenshot-2.png 46 | 47 | == Changelog == 48 | = 2.1.1 = 49 | 1. Changed notification to use the avatar of the context item( e.g contains avatar+message). 50 | 51 | = 2.1.0 = 52 | 1. Tested with BuddyPress 3.2 53 | 1. Code improvement 54 | 1. Prevents fatal error when BuddyPress is not active. 55 | 56 | = 2.0.2 = 57 | 1. Compatibility with BuddyPress 2.8.2 58 | 1. Code improvement 59 | 60 | = 2.0.1 = 61 | 1. Fixes the infinite notification bug. 62 | 1. Uses latest notification id instead of time for checking the new notifications. 63 | 64 | = 2.0.0 = 65 | 1. Complete rewrite for better code and efficiency. 66 | 1. Uses WordPress heartbeat api instead of long polling via the ajax. 67 | 1. Allows theme authors to replace the inbuilt notification UI with a different one . 68 | 69 | = 1.0.5 = 70 | 1. Updated for properly handling json response. 71 | = 1.0.4 = 72 | 73 | == Other Notes == 74 | Please leave a comment on our blog [BuddyDev](http://buddydev.com/plugins/buddypress-live-notification/) -------------------------------------------------------------------------------- /assets/vendors/achtung/ui.achtung.css: -------------------------------------------------------------------------------- 1 | /** 2 | * achtung 0.3.0 3 | * 4 | * Growl-like notifications for jQuery 5 | * 6 | * Copyright (c) 2009 Josh Varner 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | * Portions of this file are from the jQuery UI CSS framework. 27 | * 28 | * @license http://www.opensource.org/licenses/mit-license.php 29 | * @author Josh Varner 30 | */ 31 | 32 | /* IE 6 doesn't support position: fixed */ 33 | * html #achtung-overlay { 34 | position:absolute; 35 | } 36 | 37 | /* IE6 includes padding in width */ 38 | * html .achtung { 39 | width: 280px; 40 | } 41 | 42 | #achtung-overlay { 43 | overflow: hidden; 44 | position: fixed; 45 | /*top: 15px; 46 | right: 15px;*/ 47 | bottom:50px; 48 | left:50px; 49 | width: 280px; 50 | z-index:50; 51 | } 52 | 53 | .achtung { 54 | display:none; 55 | margin-bottom: 8px; 56 | padding: 15px 15px; 57 | background-color: #333; 58 | color: #fff; 59 | width: 250px; 60 | font-weight: normal; 61 | position:relative; 62 | overflow: hidden; 63 | -moz-box-shadow: #aaa 1px 1px 2px; 64 | -webkit-box-shadow: #aaa 1px 1px 2px; 65 | box-shadow: #aaa 1px 1px 2px; 66 | -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; 67 | /* Note that if using show/hide animations, IE will lose 68 | this setting */ 69 | opacity: .85; 70 | filter:Alpha(Opacity=85); 71 | } 72 | 73 | 74 | .achtung .achtung-message-icon { 75 | margin-top: 0px; 76 | margin-left: -.5em; 77 | margin-right: .5em; 78 | float: left; 79 | zoom: 1; 80 | } 81 | 82 | .achtung .ui-icon.achtung-close-button { 83 | overflow: hidden; 84 | float: right; 85 | position: relative; 86 | top: -8px; 87 | right: -8px; 88 | height:14px; 89 | font-weight: bold; 90 | width:10px; 91 | color:#000; 92 | cursor: pointer; 93 | 94 | } 95 | 96 | .achtung .ui-icon.achtung-close-button-hover { 97 | color:#000; 98 | } 99 | 100 | /* Slightly darker for these colors (readability) */ 101 | .achtungSuccess, .achtungFail, .achtungWait { 102 | /* Note that if using show/hide animations, IE will lose 103 | this setting */ 104 | opacity: .93; filter:Alpha(Opacity=93); 105 | } 106 | .achtung .achtung-message { 107 | display: inline; 108 | } 109 | .achtung .achtung-message a{ 110 | color:#fff; 111 | text-decoration: none; 112 | } 113 | 114 | /* custom css for layout */ 115 | .bpln-notification-message { 116 | display: flex; 117 | align-items: center; 118 | } 119 | 120 | .bpln-notification-message a.bpln-item-avatar { 121 | margin-right: 5px; 122 | } 123 | -------------------------------------------------------------------------------- /assets/vendors/achtung/ui.achtung.min.js: -------------------------------------------------------------------------------- 1 | 2 | /*include the achtung.js here*/ 3 | /** 4 | * achtung 0.3.0 5 | * 6 | * Growl-like notifications for jQuery 7 | * 8 | * Copyright (c) 2009 Josh Varner 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | * 28 | * @license http://www.opensource.org/licenses/mit-license.php 29 | * @author Josh Varner 30 | */ 31 | 32 | eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('(8($){$.S.6=8(4){f s=(X 4===\'1l\'),c=1i.H.C.17(1f,0),Q=\'6\';k 2.1m(8(){f n=$.14(2,Q);a(s&&4.1n(0,1)===\'1k\'){k 2}(!n&&!s&&$.14(2,Q,1q $.6(2)).1g(c));(n&&s&&$.U(n[4])&&n[4].F(n,c.C(1)))})};$.6=8(y){f c=1i.H.C.17(1f,0),$t;a(!y||!y.1o){$t=$(\'\');k $t.6.F($t,c)}2.$5=$(y)};$.B($.6,{1p:\'0.3.0\',$i:d,19:{b:10,V:d,9:d,e:\'\',J:d,K:{\'11\':\'A\',\'W\':\'A\'},P:{\'11\':\'A\',\'W\':\'A\'},Y:R,15:1r}});$.B($.6.H,{$5:d,u:d,4:{},1g:8(c){f o,7=2;c=$.1E(c)?c:[];c.1d($.6.19);c.1d({});o=2.4=$.B.F($,c);a(!$.6.$i){$.6.$i=$(\'\').16(1G.1H)}a(!o.V){$(\'x\').1I(8(){7.l()}).I(8(){$(2).q(\'6-l-M-I\')},8(){$(2).O(\'6-l-M-I\')}).1J(2.$5)}2.T(o.9,1h);a(o.g){2.$5.1M($(\'\'+o.g+\'\'))}(o.e&&2.$5.q(o.e));(o.m&&2.$5.m(o.m));2.$5.q(\'6\').16($.6.$i);a(o.K){2.$5.1e(o.K,o.Y)}r{2.$5.1L()}a(o.b>0){2.b(o.b)}},b:8(b){f 7=2;a(2.u){1F(2.u)}2.u=1x(8(){7.l()},b*1w);2.4.b=b},12:8(p){f 7=2;a(2.4.e===p){k}2.$5.w(8(){a(!7.4.J||/18/.1a(1b.1c.13())||!$.U($.S.v)){7.$5.O(7.4.e);7.$5.q(p)}r{7.$5.v(7.4.e,p,R)}7.4.e=p;7.$5.z()})},T:8(j,D){f 7=2;a((D!==1h||j===d)&&2.4.9===j){k}a(D||2.4.9===d){2.$5.1s($(\'\'));2.4.9=j;k}r a(j===d){2.$5.1t(\'.6-g-9\').G();2.4.9=d;k}2.$5.w(8(){f $h=$(\'.6-g-9\',7.$5);a(!7.4.J||/18/.1a(1b.1c.13())||!$.U($.S.v)){$h.O(7.4.9);$h.q(j)}r{$h.v(7.4.9,j,R)}7.4.9=j;7.$5.z()})},1j:8(Z){2.$5.w(8(){$(\'.6-g\',$(2)).1u(Z);$(2).z()})},1y:8(4){(4.e&&2.12(4.e));(4.m&&2.$5.m(4.m));(X(4.9)!==\'1z\'&&2.T(4.9));(4.g&&2.1j(4.g));(4.b&&2.b(4.b))},l:8(){f o=2.4,$5=2.$5;a(o.P){2.$5.1e(o.P,o.15)}r{2.$5.1D()}$5.w(8(){$5.1C(\'6\');$5.G();a($.6.$i&&$.6.$i.1B(\':1A\')){$.6.$i.G();$.6.$i=d}$5.z()})}})})(1v);',62,111,'||this||options|container|achtung|self|function|icon|if|timeout|args|false|className|var|message|span|overlay|newIcon|return|close|css|instance||newClass|addClass|else|isMethodCall|el|closeTimer|switchClass|queue||element|dequeue|toggle|extend|slice|force|class|apply|remove|prototype|hover|animateClassSwitch|showEffects|div|button|ui|removeClass|hideEffects|name|500|fn|changeIcon|isFunction|disableClose|height|typeof|showEffectDuration|newMessage||opacity|changeClass|toLowerCase|data|hideEffectDuration|appendTo|call|webkit|defaults|test|navigator|userAgent|unshift|animate|arguments|_init|true|Array|changeMessage|_|string|each|substring|nodeType|version|new|700|prepend|find|html|jQuery|1000|setTimeout|update|undefined|empty|is|removeData|hide|isArray|clearTimeout|document|body|click|prependTo|id|show|append'.split('|'),0,{})) 33 | -------------------------------------------------------------------------------- /bp-live-notification.php: -------------------------------------------------------------------------------- 1 | url = plugin_dir_url( __FILE__ ); 49 | $this->path = plugin_dir_path( __FILE__ ); 50 | 51 | add_action( 'bp_include', array( $this, 'load' ) ); 52 | 53 | add_action( 'bp_loaded', array( $this, 'load_translations' ) ); 54 | 55 | add_action( 'bp_enqueue_scripts', array( $this, 'load_css' ) ); 56 | add_action( 'bp_enqueue_scripts', array( $this, 'load_js' ) ); 57 | 58 | add_action( 'wp_head', array( $this, 'add_js_global' ) ); 59 | } 60 | 61 | /** 62 | * Get the singleton. 63 | * 64 | * @return BP_Live_Notification_Helper 65 | */ 66 | public static function get_instance() { 67 | 68 | if ( ! isset( self::$instance ) ) { 69 | self::$instance = new self(); 70 | } 71 | 72 | return self::$instance; 73 | } 74 | 75 | /** 76 | * Load core files 77 | */ 78 | public function load() { 79 | 80 | if ( ! $this->is_active() ) { 81 | return; 82 | } 83 | 84 | $files = array( 85 | 'core/bp-live-notifications-functions.php', 86 | 'core/bp-live-notifications-ajax-handler.php', 87 | ); 88 | 89 | foreach ( $files as $file ) { 90 | require_once $this->path . $file; 91 | } 92 | } 93 | 94 | /** 95 | * Load translation file 96 | */ 97 | public function load_translations() { 98 | load_plugin_textdomain( 'bp-live-notification', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); 99 | } 100 | 101 | /** 102 | * Get js variables. 103 | * 104 | * @return array 105 | */ 106 | public function get_js_settings() { 107 | return apply_filters( 'bpln_get_js_settings', array( 108 | // timeout in 10 seconds. 109 | 'timeout' => 10, 110 | // please do not change last_notified as we use it to filter the new notifications. 111 | 'last_notified' => bpln_get_latest_notification_id(), 112 | ) ); 113 | } 114 | 115 | /** 116 | * Load required js 117 | */ 118 | public function load_js() { 119 | 120 | if ( ! $this->is_active() ) { 121 | return; 122 | } 123 | 124 | if ( ! is_user_logged_in() || is_admin() && bpln_disable_in_dashboard() ) { 125 | return; 126 | } 127 | 128 | wp_register_script( 'achtung_js', $this->url . 'assets/vendors/achtung/ui.achtung.min.js', array( 'jquery' ) ); 129 | 130 | wp_register_script( 'bpln_js', $this->url . 'assets/js/bpln.js', array( 'jquery', 'json2', 'heartbeat' ) ); 131 | 132 | wp_enqueue_script( 'achtung_js' ); 133 | wp_enqueue_script( 'bpln_js' );// I am not adding achtung_js as a dependency to avoid the condition when the achtung_js will be replaced by some other library and bpln_js won't load. 134 | } 135 | 136 | /** 137 | * Load CSS file 138 | */ 139 | public function load_css() { 140 | 141 | if ( ! $this->is_active() ) { 142 | return; 143 | } 144 | 145 | if ( ! is_user_logged_in() || is_admin() && bpln_disable_in_dashboard() ) { 146 | return; 147 | } 148 | 149 | wp_register_style( 'achtung_css', $this->url . 'assets/vendors/achtung/ui.achtung.css' ); 150 | wp_enqueue_style( 'achtung_css' ); 151 | } 152 | 153 | /** 154 | * Add global bpln object 155 | */ 156 | public function add_js_global() { 157 | if ( ! $this->is_active() ) { 158 | return; 159 | } 160 | 161 | ?> 162 | 165 | 166 | 0) { 66 | updateCountText($('#ab-pending-notifications'), data.count); 67 | 68 | var myAccountNotificationMenu = $('#wp-admin-bar-my-account-notifications > a span'); 69 | // if the count menu does not exist. 70 | if (!myAccountNotificationMenu.length) { 71 | if ($('#wp-admin-bar-my-account-notifications').length) { 72 | $('#wp-admin-bar-my-account-notifications > a').append(' ' + data.count + " "); 73 | $('#wp-admin-bar-my-account-notifications-unread a').append(' ' + data.count + " "); 74 | } 75 | } else { 76 | updateCountText(myAccountNotificationMenu, data.count); 77 | updateCountText($('#wp-admin-bar-my-account-notifications-unread span'), data.count); 78 | } 79 | 80 | var $listParent = $('#wp-admin-bar-bp-notifications-default'); 81 | 82 | if ($listParent.length) { 83 | var strMarkup = ''; 84 | for (var i = 0; i < data.messages.length; i++) { 85 | strMarkup += "
  • " + data.messages[i].plain + '
  • '; 86 | } 87 | $listParent.append(strMarkup); 88 | } 89 | } 90 | }); 91 | 92 | // private functions. 93 | /** 94 | * Get last notified time 95 | * 96 | * @returns string 97 | */ 98 | function getLastNotified() { 99 | // last notified is accessible in this scope but not outside. 100 | return _lastNotified; 101 | } 102 | 103 | /** 104 | * Set last notified time 105 | * 106 | * @param time String datetime 107 | * @returns null 108 | */ 109 | function updateLastNotified(time) { 110 | _lastNotified = time; 111 | } 112 | 113 | function emitNewNotificationsRecieved(count, messages) { 114 | $(document).trigger('bpln:new_notifications', [{count: count, messages: messages}]); 115 | } 116 | 117 | function updateCountText(elements, count) { 118 | // don't do anything if the element does not exist or the count is zero. 119 | if (!elements.length || !count) { 120 | return; 121 | } 122 | 123 | elements.each(function () { 124 | var $element = $(this); 125 | var currentCount = parseInt($element.text()); 126 | currentCount = currentCount + parseInt(count) - 0; 127 | $element.text('' + currentCount); 128 | }); 129 | } 130 | 131 | bpln.updateCount = updateCountText; 132 | 133 | });//end of $(document).ready() 134 | -------------------------------------------------------------------------------- /core/bp-live-notifications-functions.php: -------------------------------------------------------------------------------- 1 | notifications->table_name; 22 | 23 | $registered_components = bp_notifications_get_registered_components(); 24 | 25 | 26 | $components_list = array(); 27 | 28 | foreach ( $registered_components as $component ) { 29 | $components_list[] = $wpdb->prepare( '%s', $component ); 30 | } 31 | 32 | $components_list = implode( ',', $components_list ); 33 | 34 | 35 | $query = "SELECT * FROM {$table} WHERE user_id = %d AND component_name IN ({$components_list}) AND id > %d AND is_new = %d "; 36 | 37 | $query = $wpdb->prepare( $query, $user_id, $last_notified, 1 ); 38 | 39 | return $wpdb->get_results( $query ); 40 | } 41 | 42 | /** 43 | * Get the last notification id for the user 44 | * 45 | * @param int $user_id user id. 46 | * 47 | * @return int 48 | */ 49 | function bpln_get_latest_notification_id( $user_id = 0 ) { 50 | 51 | if ( ! $user_id ) { 52 | $user_id = get_current_user_id(); 53 | } 54 | 55 | global $wpdb; 56 | 57 | $bp = buddypress(); 58 | 59 | $table = $bp->notifications->table_name; 60 | 61 | $registered_components = bp_notifications_get_registered_components(); 62 | 63 | 64 | $components_list = array(); 65 | 66 | foreach ( $registered_components as $component ) { 67 | $components_list[] = $wpdb->prepare( '%s', $component ); 68 | } 69 | 70 | $components_list = implode( ',', $components_list ); 71 | 72 | 73 | $query = "SELECT MAX(id) FROM {$table} WHERE user_id = %d AND component_name IN ({$components_list}) AND is_new = %d "; 74 | 75 | $query = $wpdb->prepare( $query, $user_id, 1 ); 76 | 77 | return (int) $wpdb->get_var( $query ); 78 | } 79 | 80 | /** 81 | * Get notifications messages 82 | * 83 | * @param array $notifications Notifications array. 84 | * 85 | * @return array 86 | */ 87 | function _bpln_get_notification_messages( $notifications ) { 88 | $messages = array(); 89 | 90 | if ( empty( $notifications ) ) { 91 | return $messages; 92 | } 93 | 94 | $total_notifications = count( $notifications ); 95 | 96 | $class = 'bpln-notification-message bpln-buddypress'; 97 | for ( $i = 0; $i < $total_notifications; $i ++ ) { 98 | $notification = $notifications[ $i ]; 99 | 100 | if ( defined( 'BP_PLATFORM_VERSION' ) ) { 101 | $class = 'bpln-notification-message bpln-buddyboss'; 102 | } 103 | $avatar = bpln_get_notification_avatar( $notification ); 104 | $message = bpln_get_the_notification_description( $notification ); 105 | 106 | $messages[] = array( 107 | 'plain' => $message, 108 | 'html' => '
    ' . $avatar . $message . '
    ' 109 | ); 110 | } 111 | 112 | return $messages; 113 | } 114 | 115 | /** 116 | * Get a list of processed messages 117 | * 118 | * @param array $notifications notifications array. 119 | * 120 | * @return array 121 | */ 122 | function bpln_get_notification_messages( $notifications ) { 123 | return _bpln_get_notification_messages( $notifications ); 124 | } 125 | 126 | /** 127 | * A copy of bp_get_the_notification_description to server our purpose of parsing notification to extract the message 128 | * 129 | * @see bp_get_the_notification_description 130 | * 131 | * @param stdClass $notification notification object. 132 | * 133 | * @return string 134 | */ 135 | function bpln_get_the_notification_description( $notification ) { 136 | 137 | $bp = buddypress(); 138 | 139 | // Callback function exists. 140 | if ( isset( $bp->{$notification->component_name}->notification_callback ) && is_callable( $bp->{$notification->component_name}->notification_callback ) ) { 141 | $description = call_user_func( $bp->{$notification->component_name}->notification_callback, $notification->component_action, $notification->item_id, $notification->secondary_item_id, 1 ); 142 | 143 | // @deprecated format_notification_function - 1.5 144 | } elseif ( isset( $bp->{$notification->component_name}->format_notification_function ) && function_exists( $bp->{$notification->component_name}->format_notification_function ) ) { 145 | $description = call_user_func( $bp->{$notification->component_name}->format_notification_function, $notification->component_action, $notification->item_id, $notification->secondary_item_id, 1 ); 146 | 147 | // Allow non BuddyPress components to hook in. 148 | } else { 149 | 150 | /** This filter is documented in bp-notifications/bp-notifications-functions.php */ 151 | $description = apply_filters_ref_array( 'bp_notifications_get_notifications_for_user', array( 152 | $notification->component_action, 153 | $notification->item_id, 154 | $notification->secondary_item_id, 155 | 1, 156 | 'string', 157 | $notification->component_action, // Duplicated so plugins can check the canonical action name. 158 | $notification->component_name, 159 | $notification->id, 160 | ) ); 161 | } 162 | 163 | /** 164 | * Filters the full-text description for a specific notification. 165 | * 166 | * @param string $description Full-text description for a specific notification. 167 | */ 168 | return apply_filters( 'bp_get_the_notification_description', $description ); 169 | } 170 | 171 | /** 172 | * Should we disable it in dashboard. 173 | * 174 | * @return bool 175 | */ 176 | function bpln_disable_in_dashboard() { 177 | // use this hook to disable notification in the backend. 178 | return apply_filters( 'bpln_disable_in_dashboard', false ); 179 | } 180 | 181 | /** 182 | * Get notification avatar 183 | * 184 | * @param BP_Notifications_Notification $notification notification object. 185 | * @param int $avatar_size Avatar size. 186 | * 187 | * @return string 188 | */ 189 | function bpln_get_notification_avatar( $notification, $avatar_size = 30 ) { 190 | $component = $notification->component_name; 191 | 192 | $item_id = ''; 193 | 194 | switch ( $component ) { 195 | case 'groups': 196 | if ( ! empty( $notification->item_id ) ) { 197 | $item_id = $notification->item_id; 198 | $object = 'group'; 199 | } 200 | break; 201 | case 'follow': 202 | case 'friends': 203 | if ( ! empty( $notification->item_id ) ) { 204 | $item_id = $notification->item_id; 205 | $object = 'user'; 206 | } 207 | break; 208 | default: 209 | if ( ! empty( $notification->secondary_item_id ) ) { 210 | $item_id = $notification->secondary_item_id; 211 | $object = 'user'; 212 | } else { 213 | $item_id = $notification->item_id; 214 | $object = 'user'; 215 | } 216 | break; 217 | } 218 | 219 | if ( ! $item_id || ! $object ) { 220 | return ''; 221 | } 222 | 223 | if ( $object === 'group' ) { 224 | $link = bp_get_group_permalink( new BP_Groups_Group( $item_id ) ); 225 | } else { 226 | $link = bp_core_get_user_domain( $item_id ); 227 | } 228 | 229 | ob_start(); 230 | ?> 231 | 232 | $item_id, 'object' => $object, 'width' => $avatar_size ) ); ?> 233 | 234 | 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | * @license http://www.opensource.org/licenses/mit-license.php 27 | * @author Josh Varner 28 | */ 29 | 30 | /*globals jQuery,clearTimeout,document,navigator,setTimeout 31 | */ 32 | (function($) { 33 | 34 | /** 35 | * This is based on the jQuery UI $.widget code. I would have just made this 36 | * a $.widget but I didn't want the jQuery UI dependency. 37 | */ 38 | $.fn.achtung = function(options) 39 | { 40 | var isMethodCall = (typeof options === 'string'), 41 | args = Array.prototype.slice.call(arguments, 0), 42 | name = 'achtung'; 43 | 44 | // handle initialization and non-getter methods 45 | return this.each(function() { 46 | var instance = $.data(this, name); 47 | 48 | // prevent calls to internal methods 49 | if (isMethodCall && options.substring(0, 1) === '_') { 50 | return this; 51 | } 52 | 53 | // constructor 54 | (!instance && !isMethodCall && 55 | $.data(this, name, new $.achtung(this))._init(args)); 56 | 57 | // method call 58 | (instance && isMethodCall && $.isFunction(instance[options]) && 59 | instance[options].apply(instance, args.slice(1))); 60 | }); 61 | }; 62 | 63 | $.achtung = function(element) 64 | { 65 | var args = Array.prototype.slice.call(arguments, 0), $el; 66 | 67 | if (!element || !element.nodeType) { 68 | $el = $('
    '); 69 | return $el.achtung.apply($el, args); 70 | } 71 | 72 | this.$container = $(element); 73 | }; 74 | 75 | 76 | /** 77 | * Static members 78 | **/ 79 | $.extend($.achtung, { 80 | version: '0.3.0', 81 | $overlay: false, 82 | defaults: { 83 | timeout: 10, 84 | disableClose: false, 85 | icon: false, 86 | className: '', 87 | animateClassSwitch: false, 88 | showEffects: {'opacity':'toggle','height':'toggle'}, 89 | hideEffects: {'opacity':'toggle','height':'toggle'}, 90 | showEffectDuration: 500, 91 | hideEffectDuration: 700 92 | } 93 | }); 94 | 95 | /** 96 | * Non-static members 97 | **/ 98 | $.extend($.achtung.prototype, { 99 | $container: false, 100 | closeTimer: false, 101 | options: {}, 102 | 103 | _init: function(args) 104 | { 105 | var o, self = this; 106 | 107 | args = $.isArray(args) ? args : []; 108 | 109 | 110 | args.unshift($.achtung.defaults); 111 | args.unshift({}); 112 | 113 | o = this.options = $.extend.apply($, args); 114 | 115 | if (!$.achtung.$overlay) { 116 | $.achtung.$overlay = $('
    ').appendTo(document.body); 117 | } 118 | 119 | if (!o.disableClose) { 120 | $('x') 121 | .click(function () { self.close(); }) 122 | .hover(function () { $(this).addClass('achtung-close-button-hover'); }, 123 | function () { $(this).removeClass('achtung-close-button-hover'); }) 124 | .prependTo(this.$container); 125 | } 126 | 127 | this.changeIcon(o.icon, true); 128 | 129 | if (o.message) { 130 | this.$container.append($('' + o.message + '')); 131 | } 132 | 133 | (o.className && this.$container.addClass(o.className)); 134 | (o.css && this.$container.css(o.css)); 135 | 136 | this.$container 137 | .addClass('achtung') 138 | .appendTo($.achtung.$overlay); 139 | 140 | if (o.showEffects) { 141 | this.$container.animate(o.showEffects, o.showEffectDuration); 142 | } else { 143 | this.$container.show(); 144 | } 145 | 146 | if (o.timeout > 0) { 147 | this.timeout(o.timeout); 148 | } 149 | }, 150 | 151 | timeout: function(timeout) 152 | { 153 | var self = this; 154 | 155 | if (this.closeTimer) { 156 | clearTimeout(this.closeTimer); 157 | } 158 | 159 | this.closeTimer = setTimeout(function() { self.close(); }, timeout * 1000); 160 | this.options.timeout = timeout; 161 | }, 162 | 163 | /** 164 | * Change the CSS class associated with this message, using 165 | * a transition if available (not availble in Safari/Webkit). 166 | * If no transition is available, the switch is immediate. 167 | * 168 | * #LATER Check if this has been corrected in Webkit or jQuery UI 169 | * #TODO Make transition time configurable 170 | * @param newClass string Name of new class to associate 171 | */ 172 | changeClass: function(newClass) 173 | { 174 | var self = this; 175 | 176 | if (this.options.className === newClass) { 177 | return; 178 | } 179 | 180 | this.$container.queue(function() { 181 | if (!self.options.animateClassSwitch || 182 | /webkit/.test(navigator.userAgent.toLowerCase()) || 183 | !$.isFunction($.fn.switchClass)) { 184 | self.$container.removeClass(self.options.className); 185 | self.$container.addClass(newClass); 186 | } else { 187 | self.$container.switchClass(self.options.className, newClass, 500); 188 | } 189 | 190 | self.options.className = newClass; 191 | self.$container.dequeue(); 192 | }); 193 | }, 194 | 195 | changeIcon: function(newIcon, force) 196 | { 197 | var self = this; 198 | 199 | if ((force !== true || newIcon === false) && this.options.icon === newIcon) { 200 | return; 201 | } 202 | 203 | if (force || this.options.icon === false) { 204 | this.$container.prepend($('')); 205 | this.options.icon = newIcon; 206 | return; 207 | } else if (newIcon === false) { 208 | this.$container.find('.achtung-message-icon').remove(); 209 | this.options.icon = false; 210 | return; 211 | } 212 | 213 | this.$container.queue(function() { 214 | var $span = $('.achtung-message-icon', self.$container); 215 | 216 | if (!self.options.animateClassSwitch || 217 | /webkit/.test(navigator.userAgent.toLowerCase()) || 218 | !$.isFunction($.fn.switchClass)) { 219 | $span.removeClass(self.options.icon); 220 | $span.addClass(newIcon); 221 | } else { 222 | $span.switchClass(self.options.icon, newIcon, 500); 223 | } 224 | 225 | self.options.icon = newIcon; 226 | self.$container.dequeue(); 227 | }); 228 | }, 229 | 230 | 231 | changeMessage: function(newMessage) 232 | { 233 | this.$container.queue(function() { 234 | $('.achtung-message', $(this)).html(newMessage); 235 | $(this).dequeue(); 236 | }); 237 | }, 238 | 239 | 240 | update: function(options) 241 | { 242 | (options.className && this.changeClass(options.className)); 243 | (options.css && this.$container.css(options.css)); 244 | (typeof(options.icon) !== 'undefined' && this.changeIcon(options.icon)); 245 | (options.message && this.changeMessage(options.message)); 246 | (options.timeout && this.timeout(options.timeout)); 247 | }, 248 | 249 | close: function() 250 | { 251 | var o = this.options, $container = this.$container; 252 | 253 | if (o.hideEffects) { 254 | this.$container.animate(o.hideEffects, o.hideEffectDuration); 255 | } else { 256 | this.$container.hide(); 257 | } 258 | 259 | $container.queue(function() { 260 | $container.removeData('achtung'); 261 | $container.remove(); 262 | 263 | if ($.achtung.$overlay && $.achtung.$overlay.is(':empty')) { 264 | $.achtung.$overlay.remove(); 265 | $.achtung.$overlay = false; 266 | } 267 | 268 | $container.dequeue(); 269 | }); 270 | } 271 | }); 272 | 273 | })(jQuery); --------------------------------------------------------------------------------