[Rt-commit] rt branch, 5.0/help-basics, updated. rt-5.0.1-451-g4f21360f23

Steve Burr steve at bestpractical.com
Fri Jun 18 08:40:51 EDT 2021


The branch, 5.0/help-basics has been updated
       via  4f21360f23360541a1c24185881862503e30afb0 (commit)
       via  783f4ffa304cd7077309c636b28b185cb8d3420a (commit)
       via  87a3ffe38bf790139b198c2564aba8c9a4a533db (commit)
       via  9d21873df79c4e105afca2767365e5bfce687d36 (commit)
       via  aceb564affe64c585262e8fc0e493e880419ee58 (commit)
       via  60afb5441f58043c97c3569a2d9176b9a6eba5cc (commit)
      from  b2dcd5b085a0cf813a33651b428d41469d959b10 (commit)

Summary of changes:
 devel/docs/help-system.pod     | 565 +++++++++++++++++++++++++++++++++++++++++
 lib/RT/Interface/Web.pm        |   1 -
 share/html/Elements/PopupHelp  |  46 ++++
 share/html/Search/Results.html |  13 +-
 4 files changed, 623 insertions(+), 2 deletions(-)
 create mode 100644 devel/docs/help-system.pod

- Log -----------------------------------------------------------------
commit 9d21873df79c4e105afca2767365e5bfce687d36
Merge: b2dcd5b085 aceb564aff
Author: Steven Burr <steve at bestpractical.com>
Date:   Mon Jun 14 10:21:36 2021 -0400

    Merge branch '5.0-trunk' into 5.0/help-basics


commit 87a3ffe38bf790139b198c2564aba8c9a4a533db
Author: Steven Burr <steve at bestpractical.com>
Date:   Thu Jun 17 09:00:50 2021 -0400

    Add help system documentation

diff --git a/devel/docs/help-system.pod b/devel/docs/help-system.pod
new file mode 100644
index 0000000000..3837504f67
--- /dev/null
+++ b/devel/docs/help-system.pod
@@ -0,0 +1,565 @@
+=head1 OVERVIEW
+
+RT adds help icons to various elements on pages throughout the application.
+When the user clicks the help icon, a popup dialog will display useful information
+related to that element.
+
+The RT Help System can be used in a number of ways:
+
+=over
+
+=item *
+It is used internally by RT for help topics that ship with RT
+
+=item *
+It can be used to modify or augment the help topics that ship with RT
+
+=item *
+It can be used by extension authors to provide help for their extensions in a uniform fashion
+
+=back
+
+=head2 How it works
+
+Help content is managed as a collection of Articles in specially-designated Classes.
+If a Class has the special C<"RT Help System"> custom field set to C<"yes"> then that Articles
+in that Class are eligible to participate in the lookup of help topics. A second custom
+field called C<"Locale"> will identify the language used by Articles in that Class.
+
+When asked to display help for a particular topic, the RT help system will look for a
+Class that has been tagged as C<"RT Help System"> and has a C<"Locale"> compatible with the
+current user's language setting.
+
+Assuming it finds such a Class, RT will look inside it for an Article with a Name matching
+the help topic.
+
+=head2 Sync vs Async
+
+There are basically two modes of operation for the RT help system: synchronous and
+asynchronous.
+
+In synchronous mode, all of the help content is either retrieved or supplied directly on
+the server side when the initial page is rendered. This means that the help content itself
+is delivered to the browser.
+
+In asynchronous mode, only the help topic is supplied when the page is rendered. Only when
+the user clicks on the help icon is the help content dynamically retrieved from the server
+and displayed in the popup dialog. See L</Async> for more details.
+
+Both modes can be used interchangeably on the same page.
+
+=head1 USAGE
+
+The RT help system can be used at render time on the server. For example,
+in a Mason template, you might use the `PopupHelp` template to annotate a
+form field
+
+    <label for="ticketId">Ticket Id</label>
+    <& /Elements/PopupHelp, key => 'My Topic' &>
+    <input type="text" name="ticketId" />
+
+The RT help system can also be used at runtime on the client. For example,
+you can also add the same help topic to every HTML element matching a certain
+query. The following would associate a help topic to a specific button
+
+    <script>
+    jQuery(document).ready(function() {
+        addPopupHelpItems( [ { "selector": "button#save-form", "title": "My Topic" } ] )
+    })
+    </script>
+
+=head1 REFERENCE
+
+There are three primary ways to use the RT Help System: 
+
+=over
+
+=item *
+L</Mason Templates>
+
+=item *
+L</HTML Attributes>
+
+=item *
+L</JavaScript>
+
+=back
+
+Of course, you are also free to use the lower-level contsructs as well.
+
+=over
+
+=item *
+L</Programmatic API>
+
+
+=back
+
+=head2 Mason Templates
+
+Add a C</Elements/PopupHelp> component anywhere in a Mason template
+
+    <& /Elements/PopupHelp, key => "My Topic" &>
+
+This will render an empty HTML span element
+
+    <span data-help="My Topic"
+          data-content="The article contents"
+          data-action="replace"
+          style="display: none;"
+    />
+
+which will be picked up and processed on page load by the default "helpification"
+rule when all of the accumulated rules are executed when C<renderPopupHelpItems> is
+called (for example, in the C<Elements/Footer> component in the page footer).
+
+If no valid help article named C<My Help Topic> is found, (see L</OVERVIEW>) or the
+C<ShowInlineHelp> setting/user-preference is falsy the C<<span>> will be suppressed
+altogether.
+
+Because the help content has already been retrieved and sent to the client,
+it will already be in the DOM and there should be virtually no delay when displaying
+the help popup following a user click.
+
+=head3 Example
+
+To add help to a form field, a Mason template might create a help tag directly,
+
+    <label for="ticketId">Ticket Id</label>
+    <& /Elements/PopupHelp, key => 'My Topic' &>
+    <input type="text" name="ticketId" />
+
+or might create help tags dynamically based on a Custom Field called Category
+
+    % while (my $ticket = $tickets->Next) {
+    %   my $ctgy = $ticket->FirstCustomFieldValue("Category")
+    <h1><% $ticket->Subject %></h1><& /Elements/PopupHelp, $key => $ctgy &>
+    % }
+
+=head2 HTML Attributes
+
+Add C<data-help="My Topic"> and (optionally) C<data-content="The help content">
+attributes to any HTML elements.
+
+=over
+
+=item * C<data-help>
+Required. The name of the help topic. Used as the title of the popup dialog. If C<data-content>
+is omitted, content will come from an Article with this Name.
+
+=item * C<data-content>
+Optional. The help content. If omitted, asynchronous mode will be used to dynamically retrieve
+the help content. See L</Async>.
+
+=item * C<data-action>
+Optional. The action to use when adding the help icon to the DOM. Defaults to C<"append">. See
+L</Help Selector Rules> section for more details.
+
+=back
+
+=head3 Example
+
+A Mason template might add the C<data-help> attribute to an element along
+with some static help content that includes custom HTML
+
+    <button data-help="Save Widget"
+            data-content='Saves the <font color="red">Widget</font> to RT'
+            data-action="append">Save</button>
+
+Or we could omit the C<data-content> altogether to have RT return the help content from the
+matching C<"List Sprockets"> Article when the user clicks the help icon
+
+    <button data-help="List Sprockets" data-action="append">List</button>
+
+=head2 JavaScript
+
+Call C<addPopupHelpItems> to add one or more rules to the list of help topics on a page that
+should be decorated with help icons.
+
+The C<addPopupHelpItems> function populates the C<pagePopupHelpItems> array with a list of
+declarative rules that define elements in the DOM that should have associated help icons. If
+a rule's C<selector> key matches one or more elements, its C<action> key will 
+determine where a help icon should be added to the DOM with help content corresponding to
+the C<content> key or from a valid help article with the same name as the C<title> key.
+
+Any rules thus added will be picked up and processed on page load when all of the accumulated
+rules are executed when C<renderPopupHelpItems> is called (for example, in the C<Elements/Footer>
+component in the page footer).
+
+This includes the default rule
+
+    { selector: "[data-help]", action: helpify }
+
+which matches anything with a C<data-help> attribute and therefore powers the L</HTML Attributes>
+method.
+
+This method of using JavaScript allows for tremendous flexibly annotating the DOM with help items,
+even after it has been rendered--perhaps by other templates altogether, making it attractive as a
+mechanism for customers to annotate aspects of RT--however it has been installed for them, including
+any and all extensions--simply by inspecting what is rendered to the browser and writing the
+appropriate rules. Importantly, these rules can usually be added to I<one place> (e.g. in a page
+callback somewhere) so they do I<not> need to overlay virtually every template in RT just to
+add help icons throughout.
+
+Note that C<renderPopupHelpItems> does not consider the C<ShowInlineHelp> setting/user-preference because
+it is assumed that the server-side logic would already have omitted the JavaScript call altogether
+(e.g. via the C</Elements/PopupHelp> component) if C<ShowInlineHelp> was unset.
+
+=head3 Help Selector Rules
+
+A help selector rule is a JavaScript object with the following keys
+
+=over
+
+=item * C<selector> - I<String | Function>
+
+Required. Defines which DOM elements should receive a help icon. Can match 0, 1, or many elements.
+Selectors matching 0 elements have no impact on the DOM.
+
+=over
+
+=item * I<String>
+A JQuery selector string that defines the matching DOM elements
+
+=item * I<Function>
+
+A JavaScript function that will be passed an instance of the C<JQuery> object and should
+return a JQuery collection of matching DOM elements. That is, the function signature
+is C<function( jQuery ) { ... }>
+
+=back
+
+=item * C<title> - I<String | Array(String) | Function>
+
+Optional. The help topic(s) that should be associated with the element(s) matching the C<selector>
+
+=over
+
+=item * I<String>
+The name of the help topic that should be matched against the Article Name. If the C<selector>
+matches exactly one element, this will be its help topic. If more than one element are
+matched, they will all get this same help topic.
+
+=item * I<Array(String)>
+An array of help topic names. They will be applied in order corresponding to the elements
+returned by the C<selector>
+
+=item * I<Function>
+A JavaScript function that will be called for each element matched by the C<selector> that
+should return the help topic for that element. That is, the function signagure is 
+C<function( $el ) { ... }>
+
+=back
+
+=item * C<content> - I<String | Array(String)>
+
+Optional. The help content to be displayed in the popup when the user clicks the help icon.
+
+If missing, asynchronous mode is automatically triggered (see L</Async>)
+
+=over
+
+=item * I<String>
+The help content. May contain HTML. Will be applied for all elements matched by C<selector>.
+
+=item * I<Array(String)>
+Each member of the array will be applied to each corresponding member of the array of 
+elements matched by C<selector>.
+
+=back
+
+=item * C<action> - I<String | Function>
+
+Optional. The action that should be taken with each help icon that results from the application
+of C<selector>. Responsible for actually adding the help icons to the DOM. This controls, for
+example, where the icon should be rendered relative to the matching DOM element.
+
+If missing, C<"replace"> is the default.
+
+=over
+
+=item * I<String>
+A shortcut method for referencing a number of predefined action functions. The following values
+are supported:
+
+=over
+
+=item * I<append>
+The help icon will be appended to the DOM I<after> the element(s) matched by C<selector>
+
+=item * I<prepend>
+The help icon will be prepended to the DOM I<before> the element(s) matched by C<selector>
+
+=item * I<replace>
+The help icon will be inserted into the DOM I<in place of> the element(s) matched by C<selector>.
+This is the default behavior. It is used, for example, by the C</Elements/PopupHelp> Mason component.
+
+=item * I<offset>
+The help icon will be offset from the element(s) matched by C<selector> by the amounts 
+communicated in C<actionArgs>. Works with the JQuery C<offset> method and takes an object
+parameter with coordinate keys C<{ top: 10, left: 20 }>
+
+=back
+
+=item * I<Function>
+A JavaScript function responsible for actually adding the help icons to the DOM. Will be called
+for each element matched by the C<selector>. The function signature is C<function( $el, rule, actionArgs )>
+
+=back
+
+=item * C<actionArgs> - Array
+Any additional arguments that should be passed to the C<action> function.
+
+=back
+
+=head3 Examples
+
+Add a help topic named C<"My Topic"> to the DOM element with an id of C<"ticket-id">
+
+    addPopupHelpItems([
+        {
+            selector: "#ticket-id",
+            title: "My Topic"
+        }
+    ])
+
+Add a help topic named C<"Phone"> and custom HTML content to the DOM element with an id of C<"phone-nbr">
+
+    addPopupHelpItems([
+        {
+            selector: "#phone-nbr",
+            title: "Phone",
+            content: "The customer phone number. This <i>MUST</i> include the country code."
+        }
+    ])
+
+Add more than one rule at a time
+
+    addPopupHelpItems([
+        { selector: "#ticket-status", title: "Status Topic" },
+        { selector: "#ticket-queue",  title: "Queue Topic"  }
+    ])
+
+Add a help topic named C<"A Note on Submitting Forms"> to every C<E<lt>buttonE<gt>> element
+of type C<submit>.
+
+    addPopupHelpItems([{ selector: "button[type='submit']", title: "A Note on Submitting Forms" }])
+
+Find every C<E<lt>divE<gt>> element with a C<"heading"> class, and add a help topic named 
+C<"One"> to the first one, C<"Two"> to the second one, and C<"Three"> to the third one.
+
+    addPopupHelpItems([{ selector: "div.heading", title: [ "One", "Two", "Three" ]}])
+
+Use a custom C<selector> function to match divs that have ids starting with C<"ACME-"> but only when 
+not working locally in developer mode. Determine the article title from the matching ids by stripping
+off the C<"ACME-"> portion
+
+    var acmeDivs = function( jQuery ) {
+        if (location.hostname != "localhost") {
+            return jQuery("div").filter(function($el) { 
+                return $el.id.startsWith("ACME-")
+            })
+        }
+    }
+
+    var makeTitle = function( $el ) {
+        return $el.id.replace("ACME-", "")
+    }
+
+    addPopupHelpItems([
+        {
+            selector: acmeDivs,
+            title:    makeTitle
+        }
+    ])
+
+Prepend help topics to all form radio buttons
+
+    addPopupHelpItems([
+        {
+            selector: "form input[type='radio']",
+            topic:    "Radio Button Help",
+            content:  "You can only select one at a time",
+            action:   "prepend"
+        }
+    ])
+
+Provide help for every field in each section on a ticket display page, but place each
+help icon in a line at the top of its respective section. Use asynchronous mode for
+help content, using the field text as the help topic.
+
+    var sectionInsert = function( $el, rule, options ) {
+        const $a = $el.closest(".titlebox").find(".titlebox-title.card-header a")
+        const fieldName = $el.text().replace(":", "")
+        $a.append( buildPopupHelpHtml( fieldName ) )
+    }
+
+    addPopupHelpItems([
+        {
+            selector: ".titlebox .card-body .form-row .label",
+            action:   sectionInsert
+        }
+    ])
+
+=head2 Programmatic API
+
+The following functions are part of, and used by, the RT Help System. You can also call them
+directly from your code.
+
+=head3 RT::Interface::Web::GetSystemHelpClass( locales )
+
+Given a list of locales, find the best article class that has been associated with the
+C<"RT Help System"> custom field. Locales are searched in order. The first Class with an
+C<"RT Help System"> custom field and matching C<"Locale"> custom field will be returned.
+
+=head3 RT::Interface::Web::GetHelpArticleContent( class_id, article_name )
+
+Returns the raw, unscrubbed and unescaped C<Content> of an Article of the given Class.
+Often, the class_id will come from C<GetSystemHelpClass>, but it does not have to.
+
+=head2 Async
+
+In asynchronous mode, only the help topic is supplied when the page is rendered. Only when
+the user clicks on the help icon is the help content dynamically retrieved from the server
+with a second AJAX request to which will attempt to fetch the given help article contents.
+The contents are returned directly as an HTML fragment--that is, they are not wrapped in 
+a C<<html>> tag, for example.
+
+The AJAX call will be a request to C</Helpers/HelpTopic?key=MyTopic> which will return
+the raw contents of the C<MyTopic> Article, which may contain HTML. It will not be sanitized.
+If no valid C<MyTopic> help article exists (see L</OVERVIEW>), 
+
+    <div class="text-danger">No help was found for 'MyTopic'.</div>
+
+will be returned instead.
+
+The C</Helpers/HelpTopic> component does not consider the C<ShowInlineHelp> setting/user-preference.
+However, if C<ShowInlineHelp> is not set, the help icon would generally not have been rendered
+anyway, so the AJAX call would never have been made.
+
+Asynchronous mode does have the benefit of reducing the number of database calls that need
+to be made to retrieve help article content on page request, but the user may experience a 
+slight lag when the help icon is clicked and the AJAX request is being made. This will need
+to be evaluated on a case-by-case basis. On a heavily used RT system, the performance of pages
+with many help topics may benefit from using asynchronous mode more generously.
+
+=head1 NAMING
+
+Since the RT help system uses the help topic as the key to find a corresponding Article, it
+helps to have a somewhat predictable naming convention for help topics.
+
+=head2 RT objects
+
+In general, help topics for builtin RT functionality will be prefixed by C<"RT-">
+
+=over
+
+=item *
+RT-{The Name}
+
+=item *
+RT-{Context}-{The Name}
+
+=item *
+RT-{Path/To/Page}-{The Name}
+
+=item *
+RT-MainMenu-{}-{}-...
+
+=item *
+RT-PageMenu-{}-{}-...
+
+=back
+
+=head2 User-defined objects
+
+When you wish to dynamically create help topics based on the name of an object that the end
+users create, the following naming conventions can serve as a guide
+
+=over
+
+=item *
+User-Dashboard-{The Name}
+
+=item *
+System-Dashboard-{The Name}
+
+=item *
+CustomRole-{The Name}
+
+=item *
+SystemRole-{The Name}
+
+=item *
+CustomField-{The Name}
+
+=item *
+User-SavedSearch-{The Name}
+
+=item *
+{Group Name}-SavedSearch-{The Name}
+
+=item *
+System-SavedSearch-{The Name}
+
+=back
+
+=head1 DESIGN CONSIDERATIONS
+
+Choosing synchronous vs asynchronous mode involves several tradeoffs already discussed in
+L</Async>.
+
+In synchronous mode, there are also tradeoffs in choosing whether to provide content directly
+via the C<data-content> attribute or the C<content> property of a JavaScript help rule. It is
+often convenient to provide the help directly, especially if it has to be constructed in order
+to do so. However, this makes it much more difficult for end users to edit or customize the
+help content (since it now lives in code instead of an Article). It also makes it more 
+difficult to support multiple locales.
+
+Help authors should choose the method that best balances these considerations for their
+use case.
+
+=head1 INTERNATIONALIZATION
+
+The RT help system works with multiple languages by using Articles in Classes. Each Class should
+have a different value for its C<Locale> Custom Field. All of the articles in that Class should
+be in that language.
+
+=head2 Adding a new language
+
+=over
+
+=item *
+Add a Class (for example, via B<Admin E<gt> Articles E<gt> Classes E<gt> Create>). You can name
+the Class whatever you want, but something like "Help - <language>" is probaby a good idea for clarity.
+
+=item *
+Associate it with the RT Help System. Find the "RT Help System" Custom Field (for example,
+B<Admin E<gt> Global E<gt> Custom Fields E<gt> Classes>) and apply it to your new Class
+
+=item *
+Associate it with a language. Find the "Locale" Custom Field (for example,
+B<Admin E<gt> Global E<gt> Custom Fields E<gt> Classes>) and apply it to your new Class
+
+=item *
+Set the language. Find your new Class (for example, B<Admin E<gt> Classes E<gt> Select>) and
+set the "Locale" to your <language> in the dropdown
+
+=item *
+Add articles to your new Class
+
+=back
+
+=head1 BUGS
+
+Please report them to rt-bugs at bestpractical.com, if you know what's
+broken and have at least some idea of what needs to be fixed.
+
+If you're not sure what's going on, start a discussion in the RT
+Developers category on the community forum at
+<https://forum.bestpractical.com> or send email to
+sales at bestpractical.com for professional assistance.
+
+=head1 SEE ALSO
+
+Devel

commit 783f4ffa304cd7077309c636b28b185cb8d3420a
Author: Steven Burr <steve at bestpractical.com>
Date:   Fri Jun 18 08:38:57 2021 -0400

    Remove debugging code

diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index aad8e626e6..4501914c08 100644
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -5233,7 +5233,6 @@ Often, the class_id will come from GetSystemHelpClass, but it does not have to.
 =cut
 
 sub GetHelpArticleContent {
-    use Data::Printer;
     my $class_id = shift || return '';      # required
     my $article_name = shift || return '';  # required
 

commit 4f21360f23360541a1c24185881862503e30afb0
Author: Steven Burr <steve at bestpractical.com>
Date:   Fri Jun 18 08:40:17 2021 -0400

    Add BPS license

diff --git a/share/html/Elements/PopupHelp b/share/html/Elements/PopupHelp
index 874e5d08ff..7eae04d716 100644
--- a/share/html/Elements/PopupHelp
+++ b/share/html/Elements/PopupHelp
@@ -1,3 +1,49 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2021 Best Practical Solutions, LLC
+%#                                          <sales at bestpractical.com>
+%#
+%# (Except where explicitly superseded by other copyright notices)
+%#
+%#
+%# LICENSE:
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work 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, write to the Free Software
+%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# CONTRIBUTION SUBMISSION POLICY:
+%#
+%# (The following paragraph is not intended to limit the rights granted
+%# to you to modify and distribute this software under the terms of
+%# the GNU General Public License and is only of importance to you if
+%# you choose to contribute your changes and enhancements to the
+%# community by submitting them to Best Practical Solutions, LLC.)
+%#
+%# By intentionally submitting any modifications, corrections or
+%# derivatives to this work, or any other work intended for use with
+%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+%# you are the copyright holder for those contributions and you grant
+%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
+%# royalty-free, perpetual, license to use, copy, create derivative
+%# works based on those contributions, and sublicense and distribute
+%# those contributions and any derivatives thereof.
+%#
 <%args>
 $key => ''
 </%args>

-----------------------------------------------------------------------


More information about the rt-commit mailing list