[Bps-public-commit] rt-extension-inlinehelp branch master updated. 09f5efdd8cce1fe2b353e271f48fb1d32b75e8b4

BPS Git Server git at git.bestpractical.com
Thu Sep 30 22:14:11 UTC 2021


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "rt-extension-inlinehelp".

The branch, master has been updated
       via  09f5efdd8cce1fe2b353e271f48fb1d32b75e8b4 (commit)
       via  d1c81ac9800185d0da64f34095357ce738fed1a7 (commit)
       via  3871c595ab1a1dc593127d32a88cce85c815e940 (commit)
       via  57dd0356c6afd7fe7f7fa99eb27f724531d1f04b (commit)
       via  99a63b84793a7545b7a9cdba6de753c2d0a39d1b (commit)
       via  e458395b978807702fa99901c832ee8183b15164 (commit)
       via  3ea936512827881470bcebe9f28448a3eab6b9fb (commit)
       via  0ca837a9c7629156f4141ec8aea471699ddf08ef (commit)
       via  01b43e39d86cb3e6523092ef272bc8503150068c (commit)
       via  85da59d87b8c27d106916f892766c4a9398c4261 (commit)
       via  377c2d614e4bc451e048c3e2a827ef655224360d (commit)
       via  f4b4ae31743b5f4fb6a041bcc9d48cf078fe5452 (commit)
      from  69f54a7f992e7cd5cb1768323fd25430b83dd145 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 09f5efdd8cce1fe2b353e271f48fb1d32b75e8b4
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Oct 1 05:06:25 2021 +0800

    Update autogenerated package files

diff --git a/META.yml b/META.yml
index 42c2ee1..dbd7e8f 100644
--- a/META.yml
+++ b/META.yml
@@ -16,7 +16,10 @@ meta-spec:
 name: RT-Extension-InlineHelp
 no_index:
   directory:
+    - etc
+    - html
     - inc
+    - static
 requires:
   perl: 5.10.1
 resources:
diff --git a/README b/README
index 81fc5af..719c2f9 100644
--- a/README
+++ b/README
@@ -27,11 +27,518 @@ INSTALLATION
 
             Plugin('RT::Extension::InlineHelp');
 
+        To show InlineHelp by default:
+
+            Set($ShowInlineHelp, 1);
+
     Clear your mason cache
             rm -rf /opt/rt5/var/mason_data/obj
 
     Restart your webserver
 
+OVERVIEW
+    This extension adds help icons to various elements on pages throughout
+    the application. When the user hovers over the help icon, a popup dialog
+    will display useful information related to that element.
+
+    It can be used by extension authors to provide help for their extensions
+    in a uniform fashion.
+
+  How it works
+    Help content is managed as a collection of Articles in
+    specially-designated Classes. If a Class has the special "Inline Help"
+    custom field set to "yes" then that Articles in that Class are eligible
+    to participate in the lookup of help topics. A second custom field
+    called "Locale" will identify the language used by Articles in that
+    Class.
+
+    When asked to display help for a particular topic, it will look for a
+    Class that has been tagged as "Inline Help" and has a "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.
+
+  Sync vs Async
+    There are basically two modes of operation for the InlineHelp:
+    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 hovers over the help icon is the help
+    content dynamically retrieved from the server and displayed in the popup
+    dialog. See "Async" for more details.
+
+    Both modes can be used interchangeably on the same page.
+
+USAGE
+    The InlineHelp can be used at render time on the server. For example, in
+    a Mason template, you might use the PopupHelp to annotate a form field:
+
+        <div class="form-row">
+          <div class="label col-3">
+            <span>Ticket Id</span>
+            <& /Elements/PopupHelp, Title => 'My Topic' &>:
+          </div>
+          <div class="value col-9">
+            <input class="form-control" type="text" name="ticketId" />
+          </div>
+        </div>
+
+    The InlineHelp 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>
+
+REFERENCE
+    There are three primary ways to use the Inline Help:
+
+    *   "Mason Templates"
+
+    *   "HTML Attributes"
+
+    *   "JavaScript"
+
+    Of course, you are also free to use the lower-level contsructs as well.
+
+    *   "Programmatic API"
+
+  Mason Templates
+    Add a /Elements/PopupHelp component anywhere in a Mason template
+
+        <& /Elements/PopupHelp, Title => "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;"
+        ></span>
+
+    which will be picked up and processed on page load by the default
+    "helpification" rule when all of the accumulated rules are executed when
+    renderPopupHelpItems is called (for example, in the Elements/Footer
+    component in the page footer).
+
+    If no valid help article named My Help Topic is found, (see "OVERVIEW")
+    or the ShowInlineHelp setting/user-preference is falsy the <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 hover.
+
+   Example
+    To add help to a form field, a Mason template might create a help tag
+    directly,
+
+        <div class="form-row">
+          <div class="label col-3">
+            <span>Ticket Id</span>
+            <& /Elements/PopupHelp, Title => 'My Topic' &>:
+          </div>
+          <div class="value col-9">
+            <input class="form-control" type="text" name="ticketId" />
+          </div>
+        </div>
+
+    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, Title => $ctgy &>
+        % }
+
+  HTML Attributes
+    Add data-help="My Topic" and (optionally) data-content="The help
+    content" attributes to any HTML elements.
+
+    *   data-help Required. The name of the help topic. If data-content is
+        omitted, content will come from an Article with this Name. Used as
+        the title of the popup dialog if data-title is not supplied or if in
+        asynchronous mode. See "Async".
+
+    *   data-title Optional. The title to use for the popup dialog box. If
+        omitted, data-help will be used.
+
+    *   data-content Optional. The help content. If omitted, asynchronous
+        mode will be used to dynamically retrieve the help content. See
+        "Async".
+
+    *   data-action Optional. The action to use when adding the help icon to
+        the DOM. Defaults to "append". See "Help Selector Rules" section for
+        more details.
+
+   Example
+    A Mason template might add the 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="after">Save</button>
+
+    Or we could omit the data-content altogether to have RT return the help
+    content from the matching "List Sprockets" Article when the user hovers
+    over the help icon
+
+        <button data-help="List Sprockets" data-action="after">List</button>
+
+  JavaScript
+    Call addPopupHelpItems to add one or more rules to the list of help
+    topics on a page that should be decorated with help icons.
+
+    The addPopupHelpItems function populates the pagePopupHelpItems array
+    with a list of declarative rules that define elements in the DOM that
+    should have associated help icons. If a rule's selector key matches one
+    or more elements, its action key will determine where a help icon should
+    be added to the DOM with help content corresponding to the content key
+    or from a valid help article with the same name as the title key.
+
+    Any rules thus added will be picked up and processed on page load when
+    all of the accumulated rules are executed when renderPopupHelpItems is
+    called (for example, in the Elements/Footer component in the page
+    footer).
+
+    This includes the default rule
+
+        { selector: "[data-help]", action: helpify }
+
+    which matches anything with a data-help attribute and therefore powers
+    the "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 *one place*
+    (e.g. in a page callback somewhere) so they do *not* need to overlay
+    virtually every template in RT just to add help icons throughout.
+
+    Note that renderPopupHelpItems does not consider the 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
+    /Elements/PopupHelp component) if ShowInlineHelp was unset.
+
+   Help Selector Rules
+    A help selector rule is a JavaScript object with the following keys
+
+    *   selector - *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.
+
+        *   *String* A JQuery selector string that defines the matching DOM
+            elements
+
+        *   *Function*
+
+            A JavaScript function that will be passed an instance of the
+            JQuery object and should return a JQuery collection of matching
+            DOM elements. That is, the function signature is function(
+            jQuery ) { ... }
+
+    *   title - *String | Array(String) | Function*
+
+        Optional. The help topic(s) that should be associated with the
+        element(s) matching the selector
+
+        *   *String* The name of the help topic that should be matched
+            against the Article Name. If the 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.
+
+        *   *Array(String)* An array of help topic names. They will be
+            applied in order corresponding to the elements returned by the
+            selector
+
+        *   *Function* A JavaScript function that will be called with the
+            elements matched by the selector that should return the help
+            topic for that element. That is, the function signagure is
+            function( $els ) { ... }
+
+    *   content - *String | Array(String)*
+
+        Optional. The help content to be displayed in the popup when the
+        user hovers over the help icon.
+
+        If missing, asynchronous mode is automatically triggered (see
+        "Async")
+
+        *   *String* The help content. May contain HTML. Will be applied for
+            all elements matched by selector.
+
+        *   *Array(String)* Each member of the array will be applied to each
+            corresponding member of the array of elements matched by
+            selector.
+
+    *   action - *String | Function*
+
+        Optional. The action that should be taken with each help icon that
+        results from the application of 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, "after" is the default.
+
+        *   *String* A shortcut method for referencing a number of
+            predefined action functions. The following values are supported:
+
+            *   *before* The help icon will be prepended to the DOM *before*
+                the element(s) matched by selector
+
+            *   *after* Default. The help icon will be appended to the DOM
+                *after* the element(s) matched by selector
+
+            *   *append* The help icon will be appended to the end of the
+                DOM element(s) matched by selector
+
+            *   *prepend* The help icon will be prepended to the beginning
+                of the DOM element(s) matched by selector
+
+            *   *replace* The help icon will be inserted into the DOM *in
+                place of* the element(s) matched by selector. This action is
+                used, for example, by the /Elements/PopupHelp Mason
+                component.
+
+            *   *offset* The help icon will be offset from the element(s)
+                matched by selector by the amounts communicated in
+                actionArgs. Works with the JQuery offset method and takes an
+                object parameter with coordinate keys { top: 10, left: 20 }
+
+        *   *Function* A JavaScript function responsible for actually adding
+            the help icons to the DOM. Will be called for each element
+            matched by the selector. The function signature is function(
+            $el, rule, actionArgs )
+
+    *   actionArgs - Array Any additional arguments that should be passed to
+        the action function.
+
+   Examples
+    Add a help topic named "My Topic" to the DOM element with an id of
+    "ticket-id"
+
+        addPopupHelpItems(
+            {
+                selector: "#ticket-id",
+                title: "My Topic"
+            }
+        )
+
+    Add a help topic named "Phone" and custom HTML content to the DOM
+    element with an id of "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 "A Note on Submitting Forms" to every <button>
+    element of type submit.
+
+        addPopupHelpItems( { selector: "button[type='submit']", title: "A Note on Submitting Forms" } )
+
+    Find every <div> element with a "heading" class, and add a help topic
+    named "One" to the first one, "Two" to the second one, and "Three" to
+    the third one.
+
+        addPopupHelpItems( { selector: "div.heading", title: [ "One", "Two", "Three" ]} )
+
+    Use a custom selector function to match divs that have ids starting with
+    "ACME-" but only when not working locally in developer mode. Determine
+    the article title from the matching ids by stripping off the "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( $els, rule, options ) {
+            $els.each(function(i,el) {
+                const $el = jQuery(el)
+                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
+            }
+        )
+
+  Programmatic API
+    The following functions are part of, and used by, the Inline Help. You
+    can also call them directly from your code.
+
+   RT::Interface::Web::GetInlineHelpClass( locales )
+    Given a list of locales, find the best article class that has been
+    associated with the "Inline Help" custom field. Locales are searched in
+    order. The first Class with an "Inline Help" custom field and matching
+    "Locale" custom field will be returned.
+
+   RT::Interface::Web::GetHelpArticleContent( class_id, article_name )
+    Returns the raw, unscrubbed and unescaped Content of an Article of the
+    given Class. Often, the class_id will come from GetInlineHelpClass, but
+    it does not have to.
+
+  Async
+    In asynchronous mode, only the help topic is supplied when the page is
+    rendered. Only when the user hovers over 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 <html> tag, for example.
+
+    The AJAX call will be a request to /Helpers/HelpTopic?key=MyTopic which
+    will return the raw contents of the MyTopic Article, which may contain
+    HTML. It will not be sanitized. If no valid MyTopic help article exists
+    (see "OVERVIEW"),
+
+        <div class="text-danger">No help was found for 'MyTopic'.</div>
+
+    will be returned instead.
+
+    The /Helpers/HelpTopic component does not consider the ShowInlineHelp
+    setting/user-preference. However, if 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 hovered over 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.
+
+NAMING
+    Since the InlineHelp uses the help topic as the key to find a
+    corresponding Article, it helps to have a somewhat predictable naming
+    convention for help topics.
+
+  RT objects
+    In general, help topics for builtin RT functionality will be prefixed by
+    "RT-"
+
+    *   RT-{The Name}
+
+    *   RT-{Context}-{The Name}
+
+    *   RT-{Path/To/Page}-{The Name}
+
+    *   RT-MainMenu-{}-{}-...
+
+    *   RT-PageMenu-{}-{}-...
+
+  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
+
+    *   User-Dashboard-{The Name}
+
+    *   System-Dashboard-{The Name}
+
+    *   CustomRole-{The Name}
+
+    *   SystemRole-{The Name}
+
+    *   CustomField-{The Name}
+
+    *   User-SavedSearch-{The Name}
+
+    *   {Group Name}-SavedSearch-{The Name}
+
+    *   System-SavedSearch-{The Name}
+
+DESIGN CONSIDERATIONS
+    Choosing synchronous vs asynchronous mode involves several tradeoffs
+    already discussed in "Async".
+
+    In synchronous mode, there are also tradeoffs in choosing whether to
+    provide content directly via the data-content attribute or the 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.
+
+INTERNATIONALIZATION
+    The InlineHelp works with multiple languages by using Articles in
+    Classes. Each Class should have a different value for its Locale Custom
+    Field. All of the articles in that Class should be in that language.
+
+  Adding a new language
+    *   Add a Class (for example, via Admin > Articles > Classes > Create).
+        You can name the Class whatever you want, but something like "Help -
+        <language>" is probaby a good idea for clarity.
+
+    *   Set "Inline Help" field of the Class to "yes".
+
+    *   Set "Locale" of the Class to the language you want.
+
+    *   Add articles to your new Class
+
 AUTHOR
     Best Practical Solutions, LLC <modules at bestpractical.com>
 
commit d1c81ac9800185d0da64f34095357ce738fed1a7
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Oct 1 04:44:53 2021 +0800

    Update docs according to the latest behavior

diff --git a/lib/RT/Extension/InlineHelp.pm b/lib/RT/Extension/InlineHelp.pm
index 8d97445..c0ed0a9 100644
--- a/lib/RT/Extension/InlineHelp.pm
+++ b/lib/RT/Extension/InlineHelp.pm
@@ -165,42 +165,30 @@ To show InlineHelp by default:
 
 =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.
+This extension adds help icons to various elements on pages throughout the
+application.  When the user hovers over 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
+It can be used by extension authors to provide help for their extensions in
+a uniform fashion.
 
 =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
+If a Class has the special C<"Inline Help"> 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.
+When asked to display help for a particular topic, it will look for a Class
+that has been tagged as C<"Inline Help"> 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
+There are basically two modes of operation for the InlineHelp: synchronous and
 asynchronous.
 
 In synchronous mode, all of the help content is either retrieved or supplied directly on
@@ -208,16 +196,15 @@ the server side when the initial page is rendered. This means that the help cont
 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
+the user hovers over 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
+The InlineHelp can be used at render time on the server. For example, in
+a Mason template, you might use the C<PopupHelp> to annotate a form field:
 
     <div class="form-row">
       <div class="label col-3">
@@ -229,7 +216,7 @@ form field
       </div>
     </div>
 
-The RT help system can also be used at runtime on the client. For example,
+The InlineHelp 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
 
@@ -241,7 +228,7 @@ query. The following would associate a help topic to a specific button
 
 =head1 REFERENCE
 
-There are three primary ways to use the RT Help System:
+There are three primary ways to use the Inline Help:
 
 =over
 
@@ -270,7 +257,7 @@ L</Programmatic API>
 
 Add a C</Elements/PopupHelp> component anywhere in a Mason template
 
-    <& /Elements/PopupHelp, key => "My Topic" &>
+    <& /Elements/PopupHelp, Title => "My Topic" &>
 
 This will render an empty HTML span element
 
@@ -290,7 +277,7 @@ 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.
+the help popup following a user hover.
 
 =head3 Example
 
@@ -350,7 +337,7 @@ with some static help content that includes custom HTML
             data-action="after">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
+matching C<"List Sprockets"> Article when the user hovers over the help icon
 
     <button data-help="List Sprockets" data-action="after">List</button>
 
@@ -436,7 +423,8 @@ C<function( $els ) { ... }>
 
 =item * C<content> - I<String | Array(String)>
 
-Optional. The help content to be displayed in the popup when the user clicks the help icon.
+Optional. The help content to be displayed in the popup when the user hovers
+over the help icon.
 
 If missing, asynchronous mode is automatically triggered (see L</Async>)
 
@@ -595,24 +583,24 @@ help content, using the field text as the help topic.
 
 =head2 Programmatic API
 
-The following functions are part of, and used by, the RT Help System. You can also call them
+The following functions are part of, and used by, the Inline Help. You can also call them
 directly from your code.
 
-=head3 RT::Interface::Web::GetSystemHelpClass( locales )
+=head3 RT::Interface::Web::GetInlineHelpClass( 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.
+C<"Inline Help"> custom field. Locales are searched in order. The first Class with an
+C<"Inline Help"> 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.
+Often, the class_id will come from C<GetInlineHelpClass>, 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
+the user hovers over 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.
@@ -631,13 +619,13 @@ 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
+slight lag when the help icon is hovered over 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
+Since the InlineHelp 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
@@ -713,7 +701,7 @@ use case.
 
 =head1 INTERNATIONALIZATION
 
-The RT help system works with multiple languages by using Articles in Classes. Each Class should
+The InlineHelp 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.
 
@@ -726,16 +714,10 @@ Add a Class (for example, via B<Admin E<gt> Articles E<gt> Classes E<gt> Create>
 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
+Set "Inline Help" field of the Class to "yes".
 
 =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
+Set "Locale" of the Class to the language you want.
 
 =item *
 Add articles to your new Class
commit 3871c595ab1a1dc593127d32a88cce85c815e940
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Oct 1 04:54:10 2021 +0800

    Rename "RT Help System" to "Inline Help"

diff --git a/etc/initialdata b/etc/initialdata
index 3f964bf..6395187 100644
--- a/etc/initialdata
+++ b/etc/initialdata
@@ -14,8 +14,8 @@ foreach my $lang ( map { s/:://; s/_/-/g; $_ } grep {/^\w+::$/} keys %RT::I18N::
 @lang = sort { $lang_to_desc{$a} cmp $lang_to_desc{$b} } keys %lang_to_desc;
 
 our @CustomFields = (
-    {   Name        => 'RT Help System',
-        Description => 'RT Help System',
+    {   Name        => 'Inline Help',
+        Description => 'Inline Help',
         LookupType  => 'RT::Class',
         Type        => 'Select',
         MaxValues   => 1,
diff --git a/html/Elements/PopupHelp b/html/Elements/PopupHelp
index 57a1877..18864bb 100644
--- a/html/Elements/PopupHelp
+++ b/html/Elements/PopupHelp
@@ -55,7 +55,7 @@ my $help_title;
 if ($Title) {
     my $lh = $session{'CurrentUser'}->LanguageHandle;
     my @locs = ( $lh->language_tag(), $lh->fallback_languages() );
-    my $help_class = GetSystemHelpClass( \@locs );
+    my $help_class = GetInlineHelpClass( \@locs );
     if ($help_class && $help_class->Id) {
         $help_title = GetHelpArticleTitle( $help_class->id, $Title ) || $Title;
         $help_content = GetHelpArticleContent( $help_class->Id, $Title );
diff --git a/html/Helpers/HelpTopic b/html/Helpers/HelpTopic
index 83038cd..e383878 100644
--- a/html/Helpers/HelpTopic
+++ b/html/Helpers/HelpTopic
@@ -57,7 +57,7 @@ my %result;
 if ($title) {
     my $lh = $session{'CurrentUser'}->LanguageHandle;
     my @locs = ( $lh->language_tag(), $lh->fallback_languages() );
-    my $help_class = GetSystemHelpClass( \@locs );
+    my $help_class = GetInlineHelpClass( \@locs );
     $result{content} = GetHelpArticleContent( $help_class->Id, $title ) || "<div class='text-danger'>No help was found for '$title'.</div>";
     $result{title} = GetHelpArticleTitle( $help_class->id, $title ) || $title;
 }
diff --git a/lib/RT/Extension/InlineHelp.pm b/lib/RT/Extension/InlineHelp.pm
index ff8f95d..8d97445 100644
--- a/lib/RT/Extension/InlineHelp.pm
+++ b/lib/RT/Extension/InlineHelp.pm
@@ -23,25 +23,25 @@ $RT::Config::META{ShowInlineHelp} = {
     use RT::Interface::Web;
     package HTML::Mason::Commands;
 
-    # GetSystemHelpClass locales
+    # GetInlineHelpClass locales
     #
     # Given a list of locales, find the best article class that has been associated with the
-    # 'RT Help System' custom field. Locales are searched in order. The first Class with an
-    # 'RT Help System' custom field and matching 'Locale' custom field will be returned.
+    # 'Inline Help' custom field. Locales are searched in order. The first Class with an
+    # 'Inline Help' custom field and matching 'Locale' custom field will be returned.
 
-    sub GetSystemHelpClass {
+    sub GetInlineHelpClass {
         my $locales = shift || ['en'];
 
-        # Find the custom field that indicates a Class is participating in the RT Help System
+        # Find the custom field that indicates a Class is participating in the Inline Help
         my $cf = RT::CustomField->new( RT->SystemUser );
-        my ( $ret, $msg ) = $cf->Load("RT Help System");
+        my ( $ret, $msg ) = $cf->Load("Inline Help");
         unless ( $ret and $cf->Id ) {
-            RT::Logger->warn("Could not find custom field for 'RT Help System' $msg");
+            RT::Logger->warn("Could not find custom field for 'Inline Help' $msg");
             return;
         }
 
         # Loop over the supplied locales in order. Return the first Class that is participating
-        # in the RT Help System that also has a matching Locale custom field value
+        # in the Inline Help that also has a matching Locale custom field value
         my $Classes = RT::Classes->new( RT->SystemUser );
         ( $ret, $msg ) = $Classes->LimitCustomField( CUSTOMFIELD => $cf->Id, OPERATOR => "=", VALUE => "yes" );
         if ($ret) {
@@ -65,7 +65,7 @@ $RT::Config::META{ShowInlineHelp} = {
     # GetHelpArticleTitle class_id, article_name
     #
     # Returns the value of the C<"Display Name"> Custom Field of an Article of the given Class.
-    # Often, the class_id will come from GetSystemHelpClass, but it does not have to.
+    # Often, the class_id will come from GetInlineHelpClass, but it does not have to.
 
     sub GetHelpArticleTitle {
         my $class_id     = shift || return '';    # required
@@ -86,7 +86,7 @@ $RT::Config::META{ShowInlineHelp} = {
     # GetHelpArticleContent class_id, article_name
     #
     # Returns the raw, unscrubbed and unescaped Content of an Article of the given Class.
-    # Often, the class_id will come from GetSystemHelpClass, but it does not have to.
+    # Often, the class_id will come from GetInlineHelpClass, but it does not have to.
 
     sub GetHelpArticleContent {
         my $class_id     = shift || return '';    # required
commit 57dd0356c6afd7fe7f7fa99eb27f724531d1f04b
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Oct 1 04:35:30 2021 +0800

    Move the usage doc to main module

diff --git a/docs/help-system.pod b/docs/help-system.pod
deleted file mode 100644
index 84ecf27..0000000
--- a/docs/help-system.pod
+++ /dev/null
@@ -1,592 +0,0 @@
-=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
-
-    <div class="form-row">
-      <div class="label col-3">
-        <span>Ticket Id</span>
-        <& /Elements/PopupHelp, Title => 'My Topic' &>:
-      </div>
-      <div class="value col-9">
-        <input class="form-control" type="text" name="ticketId" />
-      </div>
-    </div>
-
-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;"
-    ></span>
-
-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,
-
-    <div class="form-row">
-      <div class="label col-3">
-        <span>Ticket Id</span>
-        <& /Elements/PopupHelp, Title => 'My Topic' &>:
-      </div>
-      <div class="value col-9">
-        <input class="form-control" type="text" name="ticketId" />
-      </div>
-    </div>
-
-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, Title => $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. If C<data-content>
-is omitted, content will come from an Article with this Name.
-Used as the title of the popup dialog if C<data-title> is not supplied or if in
-asynchronous mode. See L</Async>.
-
-=item * C<data-title>
-Optional. The title to use for the popup dialog box. If omitted, C<data-help> will
-be used.
-
-=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="after">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="after">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 with the elements matched by the C<selector> that
-should return the help topic for that element. That is, the function signagure is
-C<function( $els ) { ... }>
-
-=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<"after"> 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<before>
-The help icon will be prepended to the DOM I<before> the element(s) matched by C<selector>
-
-=item * I<after>
-Default. The help icon will be appended to the DOM I<after> the element(s) matched by C<selector>
-
-=item * I<append>
-The help icon will be appended to the end of the DOM element(s) matched by C<selector>
-
-=item * I<prepend>
-The help icon will be prepended to the beginning of the DOM 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 action 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( $els, rule, options ) {
-        $els.each(function(i,el) {
-            const $el = jQuery(el)
-            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
diff --git a/lib/RT/Extension/InlineHelp.pm b/lib/RT/Extension/InlineHelp.pm
index cb181da..ff8f95d 100644
--- a/lib/RT/Extension/InlineHelp.pm
+++ b/lib/RT/Extension/InlineHelp.pm
@@ -163,6 +163,585 @@ To show InlineHelp by default:
 
 =back
 
+=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
+
+    <div class="form-row">
+      <div class="label col-3">
+        <span>Ticket Id</span>
+        <& /Elements/PopupHelp, Title => 'My Topic' &>:
+      </div>
+      <div class="value col-9">
+        <input class="form-control" type="text" name="ticketId" />
+      </div>
+    </div>
+
+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;"
+    ></span>
+
+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,
+
+    <div class="form-row">
+      <div class="label col-3">
+        <span>Ticket Id</span>
+        <& /Elements/PopupHelp, Title => 'My Topic' &>:
+      </div>
+      <div class="value col-9">
+        <input class="form-control" type="text" name="ticketId" />
+      </div>
+    </div>
+
+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, Title => $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. If C<data-content>
+is omitted, content will come from an Article with this Name.
+Used as the title of the popup dialog if C<data-title> is not supplied or if in
+asynchronous mode. See L</Async>.
+
+=item * C<data-title>
+Optional. The title to use for the popup dialog box. If omitted, C<data-help> will
+be used.
+
+=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="after">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="after">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 with the elements matched by the C<selector> that
+should return the help topic for that element. That is, the function signagure is
+C<function( $els ) { ... }>
+
+=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<"after"> 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<before>
+The help icon will be prepended to the DOM I<before> the element(s) matched by C<selector>
+
+=item * I<after>
+Default. The help icon will be appended to the DOM I<after> the element(s) matched by C<selector>
+
+=item * I<append>
+The help icon will be appended to the end of the DOM element(s) matched by C<selector>
+
+=item * I<prepend>
+The help icon will be prepended to the beginning of the DOM 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 action 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( $els, rule, options ) {
+        $els.each(function(i,el) {
+            const $el = jQuery(el)
+            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 AUTHOR
 
 Best Practical Solutions, LLC E<lt>modules at bestpractical.comE<gt>
commit 99a63b84793a7545b7a9cdba6de753c2d0a39d1b
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Oct 1 04:31:22 2021 +0800

    Simplify the way we get article content

diff --git a/lib/RT/Extension/InlineHelp.pm b/lib/RT/Extension/InlineHelp.pm
index 283d4ba..cb181da 100644
--- a/lib/RT/Extension/InlineHelp.pm
+++ b/lib/RT/Extension/InlineHelp.pm
@@ -97,15 +97,7 @@ $RT::Config::META{ShowInlineHelp} = {
         my ( $ret, $msg ) = $Article->LoadByCols( Name => $article_name, Class => $class_id, Disabled => 0 );
         if ( $Article and $Article->Id ) {
             RT::Logger->debug( "Found help article id: " . $Article->Id );
-            my $class = $Article->ClassObj;
-            my $cfs   = $class->ArticleCustomFields;
-            while ( my $cf = $cfs->Next ) {
-                if ( $cf->Name eq 'Content' ) {
-                    my $ocfvs = $Article->CustomFieldValues( $cf->Id );
-                    my $ocfv  = $ocfvs->First;
-                    return $ocfv->Content;    # do not escape
-                }
-            }
+            return $Article->FirstCustomFieldValue('Content');
         }
 
         # no match was found
commit e458395b978807702fa99901c832ee8183b15164
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Oct 1 04:25:43 2021 +0800

    Use RT 5 label/value layout in example

diff --git a/docs/help-system.pod b/docs/help-system.pod
index 933ed26..84ecf27 100644
--- a/docs/help-system.pod
+++ b/docs/help-system.pod
@@ -54,9 +54,15 @@ 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" />
+    <div class="form-row">
+      <div class="label col-3">
+        <span>Ticket Id</span>
+        <& /Elements/PopupHelp, Title => 'My Topic' &>:
+      </div>
+      <div class="value col-9">
+        <input class="form-control" type="text" name="ticketId" />
+      </div>
+    </div>
 
 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
@@ -125,9 +131,15 @@ the help popup following a user click.
 
 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" />
+    <div class="form-row">
+      <div class="label col-3">
+        <span>Ticket Id</span>
+        <& /Elements/PopupHelp, Title => 'My Topic' &>:
+      </div>
+      <div class="value col-9">
+        <input class="form-control" type="text" name="ticketId" />
+      </div>
+    </div>
 
 or might create help tags dynamically based on a Custom Field called Category
 
commit 3ea936512827881470bcebe9f28448a3eab6b9fb
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Oct 1 04:24:54 2021 +0800

    Fix typo in examples

diff --git a/docs/help-system.pod b/docs/help-system.pod
index ac52109..933ed26 100644
--- a/docs/help-system.pod
+++ b/docs/help-system.pod
@@ -107,7 +107,7 @@ This will render an empty HTML span element
           data-content="The article contents"
           data-action="replace"
           style="display: none;"
-    />
+    ></span>
 
 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
@@ -133,7 +133,7 @@ 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 &>
+    <h1><% $ticket->Subject %></h1><& /Elements/PopupHelp, Title => $ctgy &>
     % }
 
 =head2 HTML Attributes
commit 0ca837a9c7629156f4141ec8aea471699ddf08ef
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Oct 1 04:12:13 2021 +0800

    Show localized article name(Display Name) in JS calls too

diff --git a/html/Helpers/HelpTopic b/html/Helpers/HelpTopic
index b340e35..83038cd 100644
--- a/html/Helpers/HelpTopic
+++ b/html/Helpers/HelpTopic
@@ -51,12 +51,17 @@ $title => ''
 <%init>
 my $help_class;
 my $help_content;
+$r->content_type( 'application/json; charset=utf-8' );
+my %result;
+
 if ($title) {
     my $lh = $session{'CurrentUser'}->LanguageHandle;
     my @locs = ( $lh->language_tag(), $lh->fallback_languages() );
     my $help_class = GetSystemHelpClass( \@locs );
-    $help_content = GetHelpArticleContent( $help_class->Id, $title ) || "<div class='text-danger'>No help was found for '$title'.</div>";
-    $m->print($help_content);
+    $result{content} = GetHelpArticleContent( $help_class->Id, $title ) || "<div class='text-danger'>No help was found for '$title'.</div>";
+    $result{title} = GetHelpArticleTitle( $help_class->id, $title ) || $title;
 }
+
+$m->out( JSON( \%result ) );
 $m->abort;
 </%init>
diff --git a/static/js/inlinehelp.js b/static/js/inlinehelp.js
index 6e6fb04..bbe8c56 100644
--- a/static/js/inlinehelp.js
+++ b/static/js/inlinehelp.js
@@ -144,11 +144,15 @@ const popupHelpAjax = function() {
         if (isAsync) {
             const tmpId = "tmp-id-" + jQuery.now()
             jQuery.ajax({
-                url: buildUrl(title), dataType: "html",
-                dataType: "html",
+                url: buildUrl(title),
+                dataType: "json",
                 success: function(response, statusText, xhr) {
-                    jQuery("#" + tmpId).html(xhr.responseText)
-                    $el.data('content', xhr.responseText);
+                    jQuery("#" + tmpId).html(response.content)
+                    $el.data('content', response.content);
+                    $el.attr('data-original-title', response.title);
+                    if ( response.content && title != response.title ) {
+                        $el.popover('show');
+                    }
                 },
                 error: function(e) {
                     jQuery("#" + tmpId).html("<div class='text-danger'>Error loading help for '" + title + "': " + e)
commit 01b43e39d86cb3e6523092ef272bc8503150068c
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Oct 1 03:37:46 2021 +0800

    Cache article content to avoid fetching it every time we hover to it

diff --git a/static/js/inlinehelp.js b/static/js/inlinehelp.js
index 45007fb..6e6fb04 100644
--- a/static/js/inlinehelp.js
+++ b/static/js/inlinehelp.js
@@ -148,6 +148,7 @@ const popupHelpAjax = function() {
                 dataType: "html",
                 success: function(response, statusText, xhr) {
                     jQuery("#" + tmpId).html(xhr.responseText)
+                    $el.data('content', xhr.responseText);
                 },
                 error: function(e) {
                     jQuery("#" + tmpId).html("<div class='text-danger'>Error loading help for '" + title + "': " + e)
commit 85da59d87b8c27d106916f892766c4a9398c4261
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Oct 1 03:34:05 2021 +0800

    Update data-trigger to "hover" accordingly
    
    We changed to "hover" in popover call(in 842b979976), but missed this
    HTML attribute.

diff --git a/static/js/inlinehelp.js b/static/js/inlinehelp.js
index bab6d37..45007fb 100644
--- a/static/js/inlinehelp.js
+++ b/static/js/inlinehelp.js
@@ -107,7 +107,7 @@ function helpify($els, item={}, options={}) {
 
 function buildPopupHelpHtml(title, content) {
 	const contentAttr = content ? ' data-content="' + content + '" ' : ''
-	return '<a class="popup-help" tabindex="0" role="button" data-toggle="popover" title="' + title + '" data-trigger="focus" ' + contentAttr + '><span class="far fa-question-circle fa-lg"></span></a>'
+	return '<a class="popup-help" tabindex="0" role="button" data-toggle="popover" title="' + title + '" data-trigger="hover" ' + contentAttr + '><span class="far fa-question-circle fa-lg"></span></a>'
 }
 
 function applyPopupHelpAction( entry, $els ) {
commit 377c2d614e4bc451e048c3e2a827ef655224360d
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Oct 1 03:21:49 2021 +0800

    Switch to "title" for "/Helpers/HelpTopic" too for consistency

diff --git a/html/Helpers/HelpTopic b/html/Helpers/HelpTopic
index 7e304eb..b340e35 100644
--- a/html/Helpers/HelpTopic
+++ b/html/Helpers/HelpTopic
@@ -46,16 +46,16 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 <%args>
-$key => '',
+$title => ''
 </%args>
 <%init>
 my $help_class;
 my $help_content;
-if ($key) {
+if ($title) {
     my $lh = $session{'CurrentUser'}->LanguageHandle;
     my @locs = ( $lh->language_tag(), $lh->fallback_languages() );
     my $help_class = GetSystemHelpClass( \@locs );
-    $help_content = GetHelpArticleContent( $help_class->Id, $key ) || "<div class='text-danger'>No help was found for '$key'.</div>";
+    $help_content = GetHelpArticleContent( $help_class->Id, $title ) || "<div class='text-danger'>No help was found for '$title'.</div>";
     $m->print($help_content);
 }
 $m->abort;
diff --git a/static/js/inlinehelp.js b/static/js/inlinehelp.js
index 7252115..bab6d37 100644
--- a/static/js/inlinehelp.js
+++ b/static/js/inlinehelp.js
@@ -124,7 +124,7 @@ function applyPopupHelpAction( entry, $els ) {
 // popover() method, which is its primary purpose
 const popupHelpAjax = function() {
     const isDefined = function(x) { return typeof x !== "undefined" }
-    const buildUrl = function(key) { return RT.Config.WebHomePath + "/Helpers/HelpTopic?key=" + encodeURIComponent(key) }
+    const buildUrl = function(title) { return RT.Config.WebHomePath + "/Helpers/HelpTopic?title=" + encodeURIComponent(title) }
     const boolVal = function(str) {
         try {
             return !!JSON.parse(str)
@@ -135,7 +135,7 @@ const popupHelpAjax = function() {
     }
 
     const $el = jQuery(this)
-    const key = $el.data("help") || $el.data("title") || $el.data("originalTitle")
+    const title = $el.data("help") || $el.data("title") || $el.data("originalTitle")
     var content = $el.data("content")
     if (content) {
         return content
@@ -144,18 +144,18 @@ const popupHelpAjax = function() {
         if (isAsync) {
             const tmpId = "tmp-id-" + jQuery.now()
             jQuery.ajax({
-                url: buildUrl(key), dataType: "html",
+                url: buildUrl(title), dataType: "html",
                 dataType: "html",
                 success: function(response, statusText, xhr) {
                     jQuery("#" + tmpId).html(xhr.responseText)
                 },
                 error: function(e) {
-                    jQuery("#" + tmpId).html("<div class='text-danger'>Error loading help for '" + key + "': " + e)
+                    jQuery("#" + tmpId).html("<div class='text-danger'>Error loading help for '" + title + "': " + e)
                 }
             })
             return "<div id='" + tmpId + "'>Loading...</div>"
         } else {
-            return "<div class='text-danger'>No help content available for '" + key + "'.</div>"
+            return "<div class='text-danger'>No help content available for '" + title + "'.</div>"
         }
     }
 }
commit f4b4ae31743b5f4fb6a041bcc9d48cf078fe5452
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Oct 1 03:17:41 2021 +0800

    Add initialdata to create CustomFields needed

diff --git a/etc/initialdata b/etc/initialdata
new file mode 100644
index 0000000..3f964bf
--- /dev/null
+++ b/etc/initialdata
@@ -0,0 +1,37 @@
+use strict;
+use warnings;
+
+require RT::I18N;
+require I18N::LangTags::List;
+my ( @lang, %lang_to_desc );
+foreach my $lang ( map { s/:://; s/_/-/g; $_ } grep {/^\w+::$/} keys %RT::I18N:: ) {
+    next if $lang =~ /i-default|en-us/;
+    my $desc = I18N::LangTags::List::name($lang);
+    next                          unless ($desc);
+    $desc =~ s/(.*) (.*)/$2 ($1)/ unless ( $desc =~ /.* \(.*\)/ );
+    $lang_to_desc{$lang} = $desc;
+}
+ at lang = sort { $lang_to_desc{$a} cmp $lang_to_desc{$b} } keys %lang_to_desc;
+
+our @CustomFields = (
+    {   Name        => 'RT Help System',
+        Description => 'RT Help System',
+        LookupType  => 'RT::Class',
+        Type        => 'Select',
+        MaxValues   => 1,
+        Values      => [ map { { Name => $_ } } qw/yes no/ ],
+    },
+    {   Name        => 'Locale',
+        Description => 'Locale',
+        LookupType  => 'RT::Class',
+        Type        => 'Select',
+        MaxValues   => 1,
+        Values      => [ map { { Name => $_, Description => $lang_to_desc{$_} } } @lang ],
+    },
+    {   Name        => 'Display Name',
+        Description => 'Localized article name',
+        LookupType  => 'RT::Class-RT::Article',
+        Type        => 'Freeform',
+        MaxValues   => 1,
+    },
+);
-----------------------------------------------------------------------

Summary of changes:
 META.yml                       |   3 +
 README                         | 507 +++++++++++++++++++++++++++++++++++
 docs/help-system.pod           | 580 ----------------------------------------
 etc/initialdata                |  37 +++
 html/Elements/PopupHelp        |   2 +-
 html/Helpers/HelpTopic         |  15 +-
 lib/RT/Extension/InlineHelp.pm | 591 +++++++++++++++++++++++++++++++++++++++--
 static/js/inlinehelp.js        |  21 +-
 8 files changed, 1143 insertions(+), 613 deletions(-)
 delete mode 100644 docs/help-system.pod
 create mode 100644 etc/initialdata


hooks/post-receive
-- 
rt-extension-inlinehelp


More information about the Bps-public-commit mailing list