Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
.idea/
*.kdev4
nbproject/
.vscode/
20 changes: 18 additions & 2 deletions Announce.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ function register() {
function config() {
return array(
"manage_threshold" => MANAGER,
"display_all" => NO,
"default_dismissable" => YES,
);
}

Expand All @@ -40,8 +42,9 @@ function hooks() {
"EVENT_CORE_READY" => "api",
"EVENT_LAYOUT_RESOURCES" => "resources",
"EVENT_MENU_MANAGE" => "menu_manage",

"EVENT_LAYOUT_BODY_BEGIN" => "body_begin",
"EVENT_LAYOUT_BODY_END" => "body_end",

'EVENT_REST_API_ROUTES' => 'routes',
);
Expand Down Expand Up @@ -79,9 +82,22 @@ function menu_manage($event, $user_id) {
}

function body_begin() {
Announce::display("header", null, "announcement-header");
if (plugin_config_get( "display_all" )) {
Announce::display_all("header", null, "announcement-header");
} else {
Announce::display("header", null, "announcement-header");
}
}

function body_end() {
if (plugin_config_get( "display_all" )) {
Announce::display_all("footer", null, "announcement-footer");
} else {
Announce::display("footer", null, "announcement-footer");
}
}


function schema() {
require_once("api/install.php");

Expand Down
63 changes: 59 additions & 4 deletions api/base.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class Announce {
*/
protected static $locations = array(
'header' => null,
'footer' => null,
);

/**
Expand All @@ -31,7 +32,7 @@ public static function display($location, $project_id=null, $css_class="") {
$project_id = helper_get_current_project();
}

$message = AnnounceMessage::load_random(auth_get_current_user_id(), "header", $project_id);
$message = AnnounceMessage::load_random(auth_get_current_user_id(), $location, $project_id);

if ($message !== null) {
$css_class = string_attribute($css_class);
Expand Down Expand Up @@ -63,6 +64,59 @@ public static function display($location, $project_id=null, $css_class="") {
}
}

/**
* Generate the HTML for displaying all visible announcements.
* A div element is created with the CSS class "announcement" for each announcement.
* Dismissable announcements will include an image to hook to an AJAX call for dismissal.
*
* @param string $location Location name
* @param int|null $project_id Project ID (optional)
* @param string $css_class Additional CSS classes for styling (optional)
*/
public static function display_all($location, $project_id = null, $css_class = "") {
if (auth_is_user_authenticated()) {
if ($project_id === null) {
$project_id = helper_get_current_project();
}

// Load all visible announcements for the user
$messages = AnnounceMessage::load_visible(auth_get_current_user_id(), $location, $project_id);

if (!empty($messages)) {
$css_class = string_attribute($css_class);

foreach ($messages as $message) {
$message = AnnounceMessage::clean($message, AnnounceMessage::TARGET_VIEW);
$context = array_shift($message->contexts);

$html = sprintf(
'<span><strong>%s</strong></span><br/><span class="announcement-msg">%s<span>' . "\n",
$message->title,
$message->message
);

// Include dismiss button if dismissable
if ($context->dismissable) {
$html = sprintf(
'<img class="announcement-dismiss" src="%s" alt="Dismiss Announcement" />',
plugin_file("dismiss.png")
)
. "\n" . $html;
}

// Print the complete announcement div
printf(
'<div class="announcement noprint %s" data-id="%d" data-ttl="%d">%s</div>',
$css_class,
$context->id, $context->ttl,
$html
);
echo "\n";
}
}
}
}

/**
* Initialize the locations' names (display values).
*/
Expand Down Expand Up @@ -127,9 +181,10 @@ public static function print_location_option_list($value=null) {
self::initLocations();

if ($value === null) {
if( count(self::$locations) == 1 ) {
$value = reset( self::$locations );
} else {
// The first location is automatically selected for backward compatibility reasons.
reset( self::$locations );
$value = key( self::$locations );
if( count(self::$locations) !== 1 ) {
echo '<option value="">',
plugin_lang_get( "select_one","Announce" ),
"</option>\n";
Expand Down
5 changes: 5 additions & 0 deletions files/announce.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
display: none;
}

/* Mobile-first: Ensures text wraps normally on small screens for better readability. */
.category .small.wrap {
white-space: normal;
}

input.ttl {
width: 5em;
}
10 changes: 7 additions & 3 deletions files/announce.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,18 @@ jQuery(document).ready(function($) {
$('#threshold_warning').hide();
}
});

// Move announcement to the page's top, between navbar and breadcrumbs

var main_div = $('div.main-content');
if (!main_div.length) {
// Admin pages don't have a main-content div
main_div = $('div.main-container');
}
main_div.prepend($(announcement));
// Move header announcement to the page's top, between navbar and breadcrumbs
var announcement_header = announcement.filter('.announcement-header');
main_div.prepend($(announcement_header));
// Move footer announcement to the page's bottom, between page content and footer
var announcement_footer = announcement.filter('.announcement-footer');
main_div.append($(announcement_footer));

// Manual dismissal of announcement (user click)
$('img.announcement-dismiss').click(dismiss);
Expand Down
5 changes: 4 additions & 1 deletion lang/strings_english.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,17 @@ $s_plugin_Announce_config = 'Configuration';
$s_plugin_Announce_config_title = 'Announcement Configuration';
$s_plugin_Announce_config_manage_threshold = 'Manage Announcements';
$s_plugin_Announce_threshold_warning = 'WARNING: access level is lower than <em>$g_manage_site_threshold</em> ; users may not be able to access the management pages.';
$s_plugin_Announce_config_display_all = 'Display all announcements';
$s_plugin_Announce_config_default_dismissable = 'Dismissable is enabled by default';

$s_plugin_Announce_action_create = 'Create';
$s_plugin_Announce_action_edit = 'Edit';
$s_plugin_Announce_action_delete = 'Delete';
$s_plugin_Announce_action_delete_confirm = 'Do you really want to delete the following announcements?';
$s_plugin_Announce_action_delete_confirm = 'Do you really want to delete the following announcement?';
$s_plugin_Announce_action_update = 'Update';

$s_plugin_Announce_location_header = 'Page Header';
$s_plugin_Announce_location_footer = 'Page Footer';

$s_plugin_Announce_error_duplicate_context = 'A "%1$s" context is already defined for project "%2$s".';
$s_plugin_Announce_error_unknown_location = 'Unknown context location "%1$s".';
Expand Down
4 changes: 3 additions & 1 deletion lang/strings_hungarian.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ $s_plugin_Announce_config = 'Beállítások';
$s_plugin_Announce_config_title = 'Közlemény konfiguráció';
$s_plugin_Announce_config_manage_threshold = 'Közlemények kezelése';
$s_plugin_Announce_threshold_warning = 'FIGYELEM: a hozzáférési szint alacsonyabb, mint az <em>$g_manage_site_threshold</em>; a felhasználók nem biztos, hogy hozzáférnek a kezelőfelületekhez.';
$s_plugin_Announce_config_display_all = 'Összes közlemény megjelenítése';
$s_plugin_Announce_config_default_dismissable = 'Elvethető alapértelmezésként';

$s_plugin_Announce_action_create = 'Létrehozás';
$s_plugin_Announce_action_edit = 'Szerkesztés';
$s_plugin_Announce_action_delete = 'Törlés';
$s_plugin_Announce_action_delete_confirm = 'Valóban törölni szeretné a következő közleményeket?';
$s_plugin_Announce_action_delete_confirm = 'Valóban törölni szeretné a következő közleményt?';
$s_plugin_Announce_action_update = 'Frissítés';

$s_plugin_Announce_location_header = 'Oldal fejléc';
Expand Down
4 changes: 4 additions & 0 deletions pages/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ function maybe_set_option( $name, $value ) {

maybe_set_option("manage_threshold", gpc_get_int("manage_threshold"));

maybe_set_option("display_all", gpc_get_bool("display_all"));

maybe_set_option("default_dismissable", gpc_get_bool("default_dismissable"));

form_security_purge("plugin_Announce_config");
print_header_redirect(plugin_page("config_page", true));

20 changes: 20 additions & 0 deletions pages/config_page.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@
</select>
</td>
</tr>

<tr>
<td class="category">
<?php echo plugin_lang_get( 'config_display_all' ) ?>
</td>
<td>
<input type="checkbox" name="display_all"
<?php check_checked( (bool)plugin_config_get( "display_all" ) ) ?>/>
</td>
</tr>

<tr>
<td class="category">
<?php echo plugin_lang_get( 'config_default_dismissable' ) ?>
</td>
<td>
<input type="checkbox" name="default_dismissable"
<?php check_checked( (bool)plugin_config_get( "default_dismissable" ) ) ?>/>
</td>
</tr>
</table>

</div>
Expand Down
8 changes: 4 additions & 4 deletions pages/list.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ class="btn btn-primary btn-white btn-round">
<td class="category">
<?php echo plugin_lang_get("access") ?>
<br>
<span class="small"><?php echo plugin_lang_get("access_help") ?></span>
<span class="small wrap"><?php echo plugin_lang_get("access_help") ?></span>
</td>
<td>
<select name="access">
Expand All @@ -209,16 +209,16 @@ class="btn btn-primary btn-white btn-round">
<td class="category">
<?php echo plugin_lang_get("ttl") ?>
<br>
<span class="small"><?php echo plugin_lang_get("ttl_help") ?></span>
<span class="small wrap"><?php echo plugin_lang_get("ttl_help") ?></span>
</td>
<td>
<input name="ttl" class="ttl" type="number" value="0" min="0"/>
</td>
</tr>

<tr>
<tr>
<td class="category"><?php echo plugin_lang_get("dismissable") ?></td>
<td><input type="checkbox" name="dismissable" checked="checked"/></td>
<td><input type="checkbox" name="dismissable" <?php check_checked( (bool)plugin_config_get( "default_dismissable" ) ) ?>/></td>
</tr>
</tbody>

Expand Down
10 changes: 4 additions & 6 deletions pages/list_action_update.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,10 @@
}
}

if( !is_blank( $t_new_title ) ) {
$t_message->title = $t_new_title;
}
if( !is_blank( $t_new_message ) ) {
$t_message->message = $t_new_message;
}
// Allow saving empty values for title and message to support scenarios where
// clearing these fields is intentional (e.g., resetting or removing content).
$t_message->title = $t_new_title;
$t_message->message = $t_new_message;

$t_message->save();
}
Expand Down