'. t('Shoutbox') .''; $help .= '

'. t('The shoutbox gives your team a space to microblog.') .'

'; $help .= ''; return $help; } } /** * Implementation of hook_menu() */ function atrium_shoutbox_menu() { $items = array(); $items['shoutbox'] = array( 'title' => 'Shoutbox', 'title callback' => 'atrium_shoutbox_title', 'page callback' => 'atrium_shoutbox_page', 'access callback' => module_exists('spaces') ? 'spaces_access_feature' : 'user_access', 'access arguments' => module_exists('spaces') ? array('view', 'atrium_shoutbox') : array('access comments'), 'type' => MENU_NORMAL_ITEM, 'menu_name' => 'features', 'options' => array( 'fragment' => 'block-atrium_shoutbox-shoutbox', 'attributes' => array( 'id' => 'atrium-shoutbox-launcher', 'class' => 'palette-toggle' ), ), ); $items['shoutbox/js'] = array( 'description' => 'Shoutbox AJAX submission callback.', 'page callback' => 'atrium_shoutbox_ajax', 'access arguments' => array('post comments'), 'type' => MENU_CALLBACK, ); return $items; } /** * Implementation of hook_menu_alter(). */ function atrium_shoutbox_menu_alter(&$items) { // Remove shoutbox node add page. if (isset($items['node/add/shoutbox'])) { unset($items['node/add/shoutbox']); } } /** * Shoutbox menu item title callback. */ function atrium_shoutbox_title($title) { $title = t($title); if (($shoutbox = atrium_shoutbox_get_shoutbox()) && !empty($shoutbox['count'])) { $title .= " ({$shoutbox['count']})"; } return $title; } /** * Implementation of hook_block() */ function atrium_shoutbox_block($op = 'list', $delta = 0) { switch ($op) { case 'list': return array('shoutbox' => array('info' => t('Shoutbox'))); case 'view': $access = module_exists('spaces') ? spaces_access_feature('view', 'atrium_shoutbox') : user_access('access comments'); if ($delta == 'shoutbox' && $access && !context_isset('context', 'shoutbox_og')) { if ($shoutbox = atrium_shoutbox_get_shoutbox()) { $space = module_exists('spaces') ? spaces_get_space() : FALSE; if (($space && $space->type === 'og') || !module_exists('spaces_og')) { $link = l(t('Full view'), 'shoutbox'); $output = drupal_get_form('atrium_shoutbox_shoutform', $shoutbox['node'], $shoutbox['view'], $shoutbox['rendered']); $output .= ""; return array( 'subject' => !empty($space->group) ? filter_xss_admin($space->group->title) : t('Shoutbox'), 'content' => $output ); } else { return array( 'subject' => t('Shoutbox'), 'content' => $shoutbox['rendered'] ); } } } break; } } /** * Implementation of hook_nodeapi(). */ function atrium_shoutbox_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { if ($node->type == 'shoutbox') { switch ($op) { case 'load': $node->shoutbox = $node->nid; unset($node->comment); break; case 'view': $node->content = array('shoutbox' => array('#value' => atrium_shoutbox_page())); break; } } } /** * Implementation of hook_context_links_alter(). * Yank out button for creating new shoutboxes. */ function atrium_shoutbox_context_links_alter(&$links) { if (isset($links['shoutbox'])) { unset($links['shoutbox']); } } /** * Page callback for spaces shoutbox feature. */ function atrium_shoutbox_page() { $shoutbox = atrium_shoutbox_get_shoutbox(); if ($shoutbox && $shoutbox['node']) { $view = views_get_view('shoutbox_shouts'); $rendered = $view->execute_display('page_1'); return drupal_get_form('atrium_shoutbox_shoutform', $shoutbox['node'], $view, $rendered); } return $shoutbox ? $shoutbox['rendered'] : ''; } /** * Generate the shoutbox for the current space and/or situation along with user * unread count calculations. This behaves as a singleton for the page load so * that it can be used at several points (menu title callback, block, etc.). */ function atrium_shoutbox_get_shoutbox($reset = FALSE) { // Admin killswitch. if (arg(0) === 'admin') { return FALSE; } static $shoutbox; if (!isset($shoutbox) || $reset) { // Add shoutbox js and current server timestamp. Note that we don't // use the client side timestamp (via JS) because the cookie timestamp // is compared with shout times. We avoid bad client clocks and // inconsistencies using this method. drupal_add_js(drupal_get_path('module', 'admin') . '/includes/jquery.cookie.js'); drupal_add_js(drupal_get_path('module', 'atrium_shoutbox') . '/atrium_shoutbox.js'); drupal_add_js(array('atrium_shoutbox' => array('timestamp' => time())), 'setting'); $shoutbox = array(); $space = module_exists('spaces') ? spaces_get_space() : FALSE; if (($space && $space->type === 'og') || !module_exists('spaces_og')) { if ($view = views_get_view('shoutbox_shoutboxes')) { $view->execute_display('default'); // Shoutboxes exist for our current request, use the first. if (is_array($view->result) && count($view->result)) { $node = node_load($view->result[0]->nid); } // No shoutboxes exist yet. Lazy instantiate one. else { global $user; $node = (object) array( 'title' => isset($space->group) ? $space->group->title : t('Shoutbox'), 'body' => '', 'name' => isset($space->group) ? $space->group->name : $user->name, 'type' => 'shoutbox', ); node_save($node); } // Get the view and pass it to the form, as we will want access to the // raw view resultset ourselves. if (node_access('view', $node) && $view = views_get_view('shoutbox_shouts')) { $shoutbox['node'] = $node; $shoutbox['view'] = $view; } } } else { $view = views_get_view('shoutbox_shouts'); $shoutbox['node'] = FALSE; $shoutbox['view'] = $view; } // Execute/render shoutbox & count unread shouts for the current user. if (!empty($shoutbox)) { global $user; $shoutbox['count'] = 0; $shoutbox['rendered'] = $shoutbox['view']->execute_display('default'); if (!empty($shoutbox['view']->result) && !empty($_REQUEST['AtriumShoutbox'])) { $user_last_viewed = $_REQUEST['AtriumShoutbox']; foreach ($shoutbox['view']->result as $row) { // Only tally shouts that occurred after this user's last view. // The user's shouts don't count. if ( isset($row->comments_timestamp, $row->comments_uid) && $row->comments_timestamp >= $user_last_viewed && $row->comments_uid !== $user->uid ) { $shoutbox['count']++; } } } } } return $shoutbox; } /** * Shoutbox AJAX callback */ function atrium_shoutbox_ajax($op = 'shout') { // Disable any devel output global $user, $devel_shutdown; $devel_shutdown = FALSE; switch ($op) { case 'full': // Requested full comment case 'shout': // Submitted shout default: $form_state = array('values' => $_POST); $text = trim($form_state['values']['shout']); $nid = $form_state['values']['nid']; if (!empty($nid) && !empty($text)) { atrium_shoutbox_shout($nid, array('text' => $text, 'uid' => $user->uid)); } // Update the shout view. list($view_name, $view_display) = explode(':', $form_state['values']['view']); $output = views_embed_view($view_name, $view_display); print drupal_to_js(array('status' => TRUE, 'data' => $output)); break; } exit(); } /** * Save shoutbox as comment * * Store the whole comment but trim the subject to a shorter text */ function atrium_shoutbox_shout($nid, $shout) { $comment = $shout; $comment['nid'] = $nid; // See comment_save() for the thread building code. $max = db_result(db_query('SELECT MAX(thread) FROM {comments} WHERE nid = %d', $nid)); $max = rtrim($max, '/'); $thread = int2vancode(vancode2int($max) + 1) .'/'; $comment += array( 'nid' => $nid, 'comment' => $shout['text'], 'timestamp' => time(), 'uid' => 0, // Defaults to anonymous 'status' => COMMENT_NOT_PUBLISHED, 'thread' => $thread, ); // Retrieve the username to store with the comment if (!empty($comment['uid']) && ($account = user_load(array('uid' => $comment['uid'])))) { $comment['name'] = $account->name; } // The body may be in any format, so we: // 1) Filter it into HTML // 2) Strip out all HTML tags // 3) Convert entities back to plain-text. // Note: format is checked by check_markup(). if (trim($shout['subject']) == '') { $subject = decode_entities(strip_tags(filter_xss($shout['text'], array()))); $subject = truncate_utf8($subject, 63, TRUE, FALSE); $comment['subject'] = $subject; } drupal_write_record('comments', $comment); // Invoke hooks. comment_invoke_comment($comment, 'insert'); } /** * New shoutbox form. * * @param $form_state * The FAPI form state array. * @param $shoutbox * The shoutbox node object to which shouts will be related. * @param $view * The view for rendered shouts. Needed to AJAX update the view in question. * @param $rendered * A rendered list of shouts to display. */ function atrium_shoutbox_shoutform($form_state, $shoutbox, $view, $rendered) { $wrapper = 'atrium-shoutbox-wrapper-'. $shoutbox->nid; $form = array( '#attributes' => array('class' => 'shoutform'), '#theme' => 'atrium_shoutbox_shoutform' ); $form['nid'] = array( '#type' => 'hidden', '#value' => $shoutbox->nid ); $form['view'] = array( '#type' => 'hidden', '#value' => "{$view->name}:{$view->current_display}", '#attributes' => array('class' => 'atrium-shoutbox-shoutform-view') ); $form['shout'] = array( '#type' => 'textarea', '#resizable' => FALSE, '#rows' => 2, '#access' => user_access('post comments'), ); $form['shoutbox_submit'] = array( '#type' => 'submit', '#value' => t('Shout'), '#ahah' => array( 'path' => 'shoutbox/js/shout', 'wrapper' => $wrapper, 'method' => 'replace', 'effect' => 'none', ), '#access' => user_access('post comments'), ); $form['wrapper'] = array( '#type' => 'markup', '#value' => "
{$rendered}
", ); return $form; } /** * Form submission, in case there's no js */ function atrium_shoutbox_shoutform_submit($form, $form_state) { global $user; $text = trim($form_state['values']['shout']); $nid = $form_state['values']['nid']; if (!empty($nid) && !empty($text)) { atrium_shoutbox_shout($nid, array('text' => $text, 'uid' => $user->uid)); } } /** * Implementation of hook_theme(). */ function atrium_shoutbox_theme() { return array('atrium_shoutbox_shoutform' => array()); } /** * Shoutbox form theme function. */ function theme_atrium_shoutbox_shoutform($form) { drupal_add_js(drupal_get_path('module', 'atrium_shoutbox') .'/atrium_shoutbox.js'); $input = drupal_render($form['shout']) . drupal_render($form['shoutbox_submit']); $output = "
{$input}
"; $output .= drupal_render($form); return $output; }