/ src / views / elements / GroupbarElement.php
<?php
/**
 * SeekQuarry/Yioop --
 * Open Source Pure PHP Search Engine, Crawler, and Indexer
 *
 * Copyright (C) 2009 - 2026  Chris Pollett chris@pollett.org
 *
 * LICENSE:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * END LICENSE
 *
 * @author Chris Pollett chris@pollett.org
 * @license https://www.gnu.org/licenses/ GPL3
 * @link https://www.seekquarry.com/
 * @copyright 2009 - 2026
 * @filesource
 */
namespace seekquarry\yioop\views\elements;

use seekquarry\yioop as B;
use seekquarry\yioop\configs as C;
use seekquarry\yioop\library as L;
/**
 * Element used to draw the navigation bar on group feed and wiki pages.
 *
 * @author Chris Pollett
 */
class GroupbarElement extends Element
{
    /**
     * Used to draw the navigation bar on the group feed and wiki page portion
     * of the yioop website
     *
     * @param array $data contains antiCSRF token, as well as data on
     *     used to initialize title for group or wiki page
     */
    public function render($data)
    {
        if (isset($data["HEAD"]['page_type']) &&
            $data["HEAD"]['page_type'] == 'presentation' &&
            ($data['MODE'] ?? 'read') == 'read' ) {
            /* A presentation being read is a slide deck taking the whole
               screen, so it carries no bar. Somebody who may edit the
               page still needs the way in, and the way to its
               discussion, so those two are drawn on their own in the
               corner, held there while the deck moves under them. */
            $this->renderPresentationCorner($data);
            return;
        }
        $logo = $this->view->helper("logo")->renderResponsive($data,
            $this->view->logo_alt_text ?? "");
        $logged_in = !empty($data["ADMIN"]);
        $is_browse = (!$logged_in || isset($data['SUBSCRIBE_LINK']) ||
            !empty($data["NOT_MEMBER"]));
        $is_wiki = isset($data['ELEMENT']) && $data['ELEMENT'] == 'wiki';
        $token_string = ($logged_in) ? C\p('CSRF_TOKEN') . "=" .
            $data[C\p('CSRF_TOKEN')]
            : "";
        /* A page has a copy in each language, so a link that does not
           say which one reaches the copy the site is written in. The
           language the reader is looking at rides with the token on
           every link below, which is how the wiki view names it. */
        if (!empty($data['CURRENT_LOCALE_TAG'])) {
            $token_string .= ($token_string === "") ? "" : "&";
            $token_string .= "page_locale=" .
                urlencode($data['CURRENT_LOCALE_TAG']);
        }
        $alt_base_query = B\feedsUrl("",
            "", true, $data['CONTROLLER']) . $token_string;
        $base_query = ($is_wiki) ? htmlentities(B\wikiUrl("", true,
            $data['CONTROLLER'],
                ($data["GROUP"]["GROUP_ID"] ?? 0))) : $alt_base_query;
        $admin_url = htmlentities(B\controllerUrl('admin', true));
        /* controllerUrl leaves a url ready for the first thing in its
           query, the same as wikiUrl does, so the token when there is one
           is that first thing and what follows needs a separator; with
           nobody signed in there is no token and what follows is itself
           the first thing. */
        $admin_query = $admin_url . $token_string;
        if ($token_string !== "") {
            $admin_query .= "&";
        }
        ?><div class="none" >[<a href="#center-container"><?=
        tl('groupbar_element_skip_nav')
        ?>]</a></div><div id='nav-bar' class="nav-bar">
            <div class='inner-bar'><?php
            $this->view->helper("hamburger")->render($logged_in);
            if (!empty($data['ACTIVITY_METHOD']) &&
                $data['ACTIVITY_METHOD'] == 'wiki') {
                $this->renderWikiNavButtons($data);
            }
            ?>
        <div class="title-block">
        <h1><a href="<?=C\SHORT_BASE_URL ?><?php
            if ($logged_in) {
                e("?$token_string");
            }
            ?>"><?php e($logo); ?></a></h1>
            <div class='nav-span'> - <?php
        if (!empty($data['ACTIVITY_METHOD']) &&
            $data['ACTIVITY_METHOD'] == 'wiki') {
            $group_url = $this->getGroupUrl(
                ($data['GROUP']['GROUP_NAME'] ?? ''),
                $token_string, $is_browse);
            $wiki_page_list_url = rtrim(htmlentities(B\wikiUrl(
                "pages", true, $data['CONTROLLER'],
                ($data["GROUP"]["GROUP_ID"] ?? 0))) . $token_string, "?");
            $this->view->helper("iconlink")->renderButton(
                $admin_query . "a=manageAccounts", "account_home");
            $page_name = str_replace("_", " ", ($data['PAGE_NAME'] ?? '')?? "");
            if ($page_name == "Main") {
                $page_name = tl('groupbar_element_wiki');
            }
            $is_page_list = false;
            if (($data['MODE'] ?? 'read') == 'pages') {
                /* A list narrowed to one category is that category's own
                   page, so the bar names the category rather than the
                   whole of a group's pages. */
                $page_name = empty($data["LIST_CATEGORY"]) ?
                    tl('groupbar_element_page_list') :
                    $data["LIST_CATEGORY"];
                $is_page_list = true;
            }
            ?><a class="bar-item" href="<?=$group_url ?>"><?=
            urldecode(($data['GROUP']['GROUP_NAME'] ?? '')) ?></a>:<?php
            $colon = "";
            if (!$is_page_list) {
                $this->view->helper("iconlink")->renderButton(
                    $wiki_page_list_url, "pages");
                $colon = ":";
            }
            if (($data['PAGE_NAME'] ?? '') != "Main" && in_array(
                ($data['MODE'] ?? 'read'), ['read', 'edit', 'source'])) {
                $colon = ":";
                $wiki_main_url = htmlentities(B\wikiUrl(
                    "Main", true, $data['CONTROLLER'],
                    ($data["GROUP"]["GROUP_ID"] ?? 0))) . $token_string;
                $this->view->helper("iconlink")->renderButton(
                    $wiki_main_url, "wiki");
            }
            e($colon);
            if (($data['MODE'] ?? 'read') == 'read' &&
                ($_REQUEST['repo_view'] ?? "") == 'issues') {
                $read_url = htmlentities(B\wikiUrl(($data['PAGE_NAME'] ?? ''),
                    true, $data['CONTROLLER'],
                    ($data["GROUP"]["GROUP_ID"] ?? 0))) . $token_string;
                ?><a class="bar-item" href='<?=$read_url ?>'><?=
                    urldecode($page_name)?></a><?php
            } else if (($data['MODE'] ?? 'read') == 'read') {
                ?><div class="bar-item"><?=urldecode($page_name)?></div><?php
            } else if (($data['MODE'] ?? 'read') == 'pages') {
                ?><div class="wide-bar-item"><?=
                urldecode($page_name)?></div><?php
            } else {
                $wiki_base_url = htmlentities(B\wikiUrl(
                    ($data['PAGE_NAME'] ?? ''), true, $data['CONTROLLER'],
                    ($data["GROUP"]["GROUP_ID"] ?? 0))) . $token_string;
                ?><a class="bar-item" href='<?=$wiki_base_url
                    ?>'  target='preview'><?=urldecode($page_name); ?></a><?php
                /* The bar says which view of the page is open, so a
                   reader can see where they are. The history is a mode
                   of its own; the settings and the resources are views
                   of the editing screen, marked by their own flags, and
                   each is named here the same way. */
                if (($data['MODE'] ?? 'read') == 'history') {
                    ?>:<?=tl('groupbar_element_history');?><?php
                } else if (!empty($data['settings']) &&
                    $data['settings'] != "false") {
                    ?>:<?=tl('groupbar_element_settings');?><?php
                } else if (!empty($data['resources']) &&
                    $data['resources'] != "false" &&
                    empty($data['PAGE_LISTS_FILES'])) {
                    ?>:<?php
                    $this->renderResourcesCrumb($data);
                } else if (!empty($data['RESOURCE_NAME'])) {
                    ?>:<?php
                    if (empty($data['PAGE_LISTS_FILES'])) {
                        $this->renderResourcesCrumb($data);
                        ?>:<?php
                    }
                    ?><?=$data['RESOURCE_NAME']?><?php
                }
            }
        } else if (($data['SUBTITLE'] ?? "") == C\PERSONAL_GROUP_PREFIX) {?>
                <?=
                $this->view->helper("iconlink")->renderButton(
                $admin_query . "a=manageAccounts",
                "account_home");?> <?=
                (($data['ACTIVITY_METHOD'] ?? "") == 'userMail') ?
                tl('groupbar_element_mail') :
                tl('groupbar_element_messages') ?><?php
        } else {
            $this->view->helper("iconlink")->renderButton(
                $admin_query . "a=manageAccounts", "account_home");
            e(" ");
            if (!empty($data['JUST_THREAD']) &&
                !empty($data['WIKI_PAGE_NAME'])) {
                    $group_name = $data['GROUP_NAME'] ??
                        $data['PAGES'][0][L\CrawlConstants::SOURCE_NAME]
                        ?? "";
                    $group_url = $this->getGroupUrl($group_name,
                        $token_string, $is_browse);
                    $group_id = $data["GROUP_ID"] ??
                        $data['PAGES'][0]["GROUP_ID"] ?? "";
                    $wiki_base_url = htmlentities(B\wikiUrl(
                        $data['WIKI_PAGE_NAME'], true, $data['CONTROLLER'],
                        $group_id)) . $token_string;?>
                    <a class="bar-item" href='<?=$group_url ?>' ><?=$group_name
                    ?></a>:<a class="bar-item" href='<?=$wiki_base_url ?>' ><?=
                    $data['WIKI_PAGE_NAME'] ?></a>:<div class="bar-item"><?=
                    tl('groupbar_element_talk');?></div><?php
            } else if (!empty($data['JUST_GROUP_ID'])) {
                $group_url = $this->getGroupUrl($data['SUBTITLE'],
                    $token_string, $is_browse); ?>
                <a class="wide-bar-item" href='<?=$group_url ?>' ><?=
                urldecode($data['SUBTITLE']);
                ?></a>:<div class="bar-item"><?=
                tl('groupbar_element_talk');?></div><?php
            } else if (!empty($data['JUST_USER_ID'])) {
                if (empty($data['PAGES'][0]["USER_NAME"])) {
                    e(tl("groupbar_element_no_path_info"));
                } else {?>
                    <div class="wide-bar-item" ><?=
                        tl("groupbar_element_userfeed",
                        urldecode($data['PAGES'][0]["USER_NAME"]))?></div><?php
                }
            } else if (!empty($data['JUST_THREAD'])) {
                if (!empty($data['GROUP_NAME'])) {
                    $group_url = $this->getGroupUrl($data['GROUP_NAME'],
                        $token_string, $is_browse);
                    ?><a class="bar-item" href='<?=$group_url?>'><?=
                        urldecode($data['GROUP_NAME'])
                    ?></a>:<a class="bar-item" href='<?=htmlentities(
                        B\feedsUrl("group", $data["GROUP_ID"],
                        true, 'group')) . $token_string?>' ><?=
                        tl("groupbar_element_talk")
                        ?></a>:<div class="bar-item"><?=
                        urldecode($data['SUBTITLE'])?></div><?php
                } else {
                    e(urldecode($data['SUBTITLE']));
                }
                if (!empty($data['SHOW_THREAD_FOLLOW'])) {
                    $follow_base = B\feedsUrl("thread",
                        $data['JUST_THREAD'], true, "group") .
                        C\p('CSRF_TOKEN') . "=" . $data[C\p('CSRF_TOKEN')];
                    if (!empty($data['THREAD_FOLLOWED'])) {
                        $follow_url = $follow_base .
                            "&arg=togglethreadmail&follow=0";
                        $follow_type = "thread_followed";
                    } else {
                        $follow_url = $follow_base .
                            "&arg=togglethreadmail&follow=1";
                        $follow_type = "thread_unfollowed";
                    }
                    $this->view->helper("iconlink")->renderButton(
                        $follow_url, $follow_type);
                }
            } else if (!empty($data['VIEW_MODE']) &&
                $data['VIEW_MODE'] == "ungrouped") {
                e(tl('groupbar_element_discussions'));
            } else {
                e(tl('groupbar_element_my_groups'));
            }
        }?></div>
        </div>
        </div>
        </div>
        <?php
    }
    /**
     * Computes the url  to show one group in the
     * already belong to the group ($is_browse == false) and the
     * just looking at group ($is_browse == true) setting.
     *
     * @param string $group_name name of single group to show
     * @param string $token_string CSRF token to show legitimately logged in
     * @param bool $is_browse whether already belong to group (false) or not.
     * @return string url to either My Groups or Join Groups pages for group
     */
    public function getGroupUrl($group_name, $token_string, $is_browse)
    {
        /* controllerUrl leaves the url ready for the first thing in its
           query, so the token when there is one is that first thing and
           needs a separator after it; with nobody signed in there is no
           token and what follows is itself the first thing. */
        $token_query = ($token_string === "") ? "" :
            $token_string . "&";
        if ($is_browse) {
            $group_url = htmlentities(B\controllerUrl('admin', true)) .
                $token_query . "a=manageGroups&context=group" .
                "&group_filter=%3D$group_name&browse=true";
        } else {
            $group_url = htmlentities(B\controllerUrl('group', true)) .
                $token_query . "group_filter=%3D$group_name";
        }
        return $group_url;
    }
    /**
     * Draws navigation controls in the GroupBar when on Wiki pages
     * (floated to opposite side of current reading direction) allowing
     * a user depending on the access to the group to edit or view source of a
     * page and to see the pages discussion thread.
     *
     * @param array $data associative array of data from the controller/
     *   SocialComponent used to draw th enav buttons.
     */
    /**
     * renderPresentationCorner draws the way into editing a presentation
     * and the way to its discussion, for a reader who may edit it. A
     * presentation being read fills the screen with its slides and shows
     * no bar, so these two would otherwise have nowhere to stand and a
     * writer would have no way back to the page's source. The marks
     * themselves are the ones the bar draws for any wiki page, asked for
     * here and held in a corner of the window rather than placed in the
     * page, so the deck can move under them.
     *
     * @param array $data fields the controller prepared for the page,
     *     read for who may edit, the page's name and group, and the
     *     thread its discussion lives in
     */
    public function renderPresentationCorner($data)
    {
        if (empty($data["ADMIN"]) || empty($data["CAN_EDIT"])) {
            return;
        }
        e("<div class='presentation-corner'>");
        $this->renderWikiNavButtons($data);
        e("</div>");
    }
    /**
     * renderResourcesCrumb draws the mark in the bar standing for the
     * list of files kept with a page, which is also the way back to that
     * list. It is drawn where the reader is looking at that list or at
     * one file from it.
     *
     * @param array $data fields the controller prepared for the page,
     *     read for the page's name and group and the token
     */
    public function renderResourcesCrumb($data)
    {
        $token_string = empty($data[C\p('CSRF_TOKEN')]) ? "" :
            C\p('CSRF_TOKEN') . "=" . $data[C\p('CSRF_TOKEN')];
        $list_url = htmlentities(B\wikiUrl(($data['PAGE_NAME'] ?? ''),
            true, $data['CONTROLLER'],
            ($data["GROUP"]["GROUP_ID"] ?? 0))) . $token_string;
        if ($token_string !== "") {
            $list_url .= "&";
        }
        $list_url .= "arg=edit&resources=true";
        $this->view->helper("iconlink")->renderButton($list_url,
            "resources");
    }
    /**
     * renderWikiNavButtons draws navigation controls in the GroupBar when
     * on Wiki pages, floated to the opposite side of the current reading
     * direction, allowing a user, depending on their access to the group,
     * to edit or view the source of a page and to see the page's
     * discussion thread.
     *
     * @param array $data associative array of data from the controller
     *   and SocialComponent used to draw the nav buttons.
     */
    public function renderWikiNavButtons($data)
    {
        $read_mode = in_array(($data['MODE'] ?? 'read'), ['read', 'ballot-init',
            'count-ballots', 'ballot-concluded']);
        $logged_in = !empty($data["ADMIN"]);
        $token_string = ($logged_in) ? C\p('CSRF_TOKEN') . "=" .
            $data[C\p('CSRF_TOKEN')]
            : "";
        /* A page has a copy in each language, so a link that does not
           say which one reaches the copy the site is written in. The
           language the reader is looking at rides with the token on
           every link below, which is how the wiki view names it. */
        if (!empty($data['CURRENT_LOCALE_TAG'])) {
            $token_string .= ($token_string === "") ? "" : "&";
            $token_string .= "page_locale=" .
                urlencode($data['CURRENT_LOCALE_TAG']);
        }
        $can_edit = $logged_in && !empty($data["CAN_EDIT"]);
        $public_source = empty($data['NO_HISTORY_SOURCE']);
        $wiki_base_url = htmlentities(B\wikiUrl(
            ($data['PAGE_NAME'] ?? ''), true, $data['CONTROLLER'],
            ($data["GROUP"]["GROUP_ID"] ?? 0))) . $token_string;
        /* wikiUrl leaves a url ready for the first thing in its query, so
           the token, when there is one, is that first thing and what
           follows it needs a separator of its own. Nobody signed in
           carries no token, and then what follows is itself the first
           thing and needs no separator; writing one anyway is what put a
           stray ampersand straight after the question mark. */
        if ($token_string !== "") {
            $wiki_base_url .= "&";
        }
        $page_type = $data["HEAD"]['page_type'] ??
            ($data['page_type'] ?? "");
        $is_git_repository = ($page_type == 'git_repository');
        $issues_url = $wiki_base_url . "arg=read&repo_view=issues";
        $discuss_url = (!empty($data['DISCUSS_THREAD']) &&
            ($can_edit|| $public_source)) ?
            htmlentities(B\feedsUrl("thread",
            $data['DISCUSS_THREAD'], true, "group")) . $token_string : "";
        e("<div class='float-opposite medium-margin'>");
        /* The settings, the resources and the history are ways of
           looking at a page while editing it, so the way back from each
           is the editing screen rather than the read screen. Each used
           to carry a close control of its own for that, which this
           replaces. */
        $beside_editing = (!empty($data['settings']) &&
            $data['settings'] != "false") ||
            (!empty($data['resources']) &&
            $data['resources'] != "false") ||
            ($data['MODE'] ?? 'read') == 'history';
        $editing_one_file = !empty($data['RESOURCE_NAME']) &&
            (empty($data['resources']) || $data['resources'] == "false");
        $page_lists_files = !empty($data['PAGE_LISTS_FILES']);
        if (($beside_editing || $editing_one_file) && $can_edit) {
            $edit_url = $wiki_base_url . "arg=edit";
            if ($editing_one_file && !$page_lists_files) {
                $edit_url .= "&resources=true";
            }
            if (!empty($data['SUB_PATH'])) {
                $edit_url .= "&sf=".urlencode($data['SUB_PATH']);
            }
            $this->view->helper("iconlink")->renderButton(
                $edit_url, "view_edit");
        } else if (!$read_mode) {
            $read_url = $wiki_base_url . "arg=read";
            if (!empty($data['SUB_PATH'])) {
                $read_url .= "&sf=".urlencode($data['SUB_PATH']);
            }
            $this->view->helper("iconlink")->renderButton(
                $read_url, "view_read");
        } else if ($can_edit) {
            $edit_url = $wiki_base_url . "arg=edit";
            $media_file = $data['MEDIA_NAME'] ?? "";
            $media_ext = strtolower(pathinfo($media_file,
                PATHINFO_EXTENSION));
            if ($media_file !== "" &&
                (in_array($media_ext, C\EDITABLE_RESOURCE_EXTENSIONS) ||
                in_array($media_ext, C\EDITABLE_IMAGE_EXTENSIONS))) {
                $edit_url .= "&n=" . urlencode($media_file);
            }
            if (!empty($data['SUB_PATH'])) {
                $edit_url .= "&sf=".urlencode($data['SUB_PATH']);
            }
            $this->view->helper("iconlink")->renderButton(
                $edit_url, "edit");
        } else if ($public_source) {
            $source_url = $wiki_base_url . "arg=source";
            if (!empty($data['SUB_PATH'])) {
                $source_url .= "&sf=".urlencode($data['SUB_PATH']);
            }
            $this->view->helper("iconlink")->renderButton(
                $source_url, "view_source");
        }
        if ($is_git_repository) {
            e("<div id='discuss-button'>");
            $this->view->helper("iconlink")->renderButton(
                $issues_url, "issue_tracker");
            e("</div>");
        } else if (!empty($discuss_url)) {
            e("<div id='discuss-button'>");
            $this->view->helper("iconlink")->renderButton(
                $discuss_url, "discuss_page");
            e("</div>");
        }
        e("</div>");
    }
}
X