From 0e70bc499b1566f8fe00afe77ff1ef2330b4517d Mon Sep 17 00:00:00 2001 From: Matthew Brambilla Date: Fri, 28 Oct 2022 15:51:00 -0400 Subject: [PATCH 1/4] CSL-2041: Popover tours --- src/frontend/js/frontend.js | 31 +++ src/frontend/js/tour.js | 63 +++-- src/frontend/scss/site/_box.scss | 10 + src/frontend/scss/site/_button.scss | 21 +- src/frontend/scss/site/_content.scss | 26 +- src/frontend/scss/site/_tooltip.scss | 9 + src/library/templates/library/library.html | 6 - src/library/templates/library/resources.html | 6 - src/library/views.py | 15 +- src/pages/templates/pages/dashboard.html | 7 - .../dashboard_panel_popular_reads.html | 4 + src/pages/templates/pages/reader.html | 6 - src/pages/templates/pages/wordbank.html | 6 - src/pages/templatetags/list_helpers.py | 29 ++ src/pages/views.py | 26 +- src/roster/templates/roster/manage.html | 8 +- src/roster/views.py | 10 +- src/shared/templates/shared/base.html | 16 +- .../shared/partial/popover_tour.html | 252 +++++------------- .../shared/partial/popover_tour_footer.html | 34 +++ .../shared/partial/sidebar_bottom_end.html | 10 + .../templates/shared/partial/tooltip_tip.html | 9 +- src/tips/fixtures/tiptypes.json | 40 +-- src/tips/models.py | 24 ++ 24 files changed, 362 insertions(+), 306 deletions(-) create mode 100644 src/pages/templatetags/list_helpers.py create mode 100644 src/shared/templates/shared/partial/popover_tour_footer.html create mode 100644 src/shared/templates/shared/partial/sidebar_bottom_end.html diff --git a/src/frontend/js/frontend.js b/src/frontend/js/frontend.js index 2ad8e212b..6c9960709 100644 --- a/src/frontend/js/frontend.js +++ b/src/frontend/js/frontend.js @@ -1298,6 +1298,36 @@ function setUpDeferredLoadOfCompDetails() { }); } +function dialogMediaStop() { + 'use strict'; + + function dialogTarget(evt) { + if (evt.namespace.includes('popover')) { + return $(evt.target).data('cfw.popover').$target[0]; + } + if (evt.namespace.includes('modal')) { + return $(evt.target).data('cfw.modal').$target[0]; + } + return null; + } + + $(document.body).on('beforeHide.cfw.popover beforeHide.cfw.modal', function(evt) { + if (evt.isDefaultPrevented()) { return; } + + var target = dialogTarget(evt); + if (target === null) { return; } + + var $iframes = $(target).find('iframe[src]'); + $iframes.each(function() { + var source = this.src; + if (source.includes('youtube.com') || source.includes('sproutvideo.com')) { + this.src = ''; + this.src = source; + } + }); + }); +} + $(window).ready(function() { 'use strict'; @@ -1328,6 +1358,7 @@ $(window).ready(function() { shareForm(); dashboardStudentReadingViewButtons(); toolboxHandleUpdate(); + dialogMediaStop(); var settingFontSize = document.querySelector('#set-size'); if (settingFontSize !== null) { diff --git a/src/frontend/js/tour.js b/src/frontend/js/tour.js index ee21401d1..09e99ea15 100644 --- a/src/frontend/js/tour.js +++ b/src/frontend/js/tour.js @@ -3,6 +3,7 @@ var SELECTOR_CONTAINER = '#tourContainer'; var SELECTOR_TOUR_VISIBLE = '.popover-tour:visible'; + var CLASS_TOUR = 'touring'; var tourModule = function() { // placeholder @@ -10,26 +11,41 @@ tourModule.prototype = { // Initialize tour popover item - // `selector` - the trigger for the popover to initialize - prepare : function(selector) { - if (selector) { - var control = $(selector); - var target = control.attr('data-cfw-popover-target'); - if ((typeof target === 'undefined' || target === false) && control.is('[data-clusive-tip-id]')) { - target = '#tour_' + control.attr('data-clusive-tip-id'); - } - var placement = control.attr('data-cfw-popover-placement'); - control.CFW_Popover({ - container: SELECTOR_CONTAINER, - viewport: 'window', - trigger: 'manual', - target: target, - placement: placement ? placement : 'right auto', - popperConfig: { - positionFixed: true - } - }); + // `name` - name (via data attribute) trigger for the popover to initialize + prepare : function(name) { + var $control = $('[data-clusive-tip-id="' + name + '"]'); + if (!$control.length) { return; } + + var target = $control.attr('data-cfw-popover-target'); + if ((typeof target === 'undefined' || target === false) && $control.is('[data-clusive-tip-id]')) { + target = '#tour_' + $control.attr('data-clusive-tip-id'); } + var placement = $control.attr('data-cfw-popover-placement'); + $control.CFW_Popover({ + container: SELECTOR_CONTAINER, + viewport: 'window', + trigger: 'manual', + target: target, + placement: placement ? placement : 'right auto', + popperConfig: { + positionFixed: true + } + }); + }, + + // Show a singleton from the tour + singleton: function(name) { + var $control = $('[data-clusive-tip-id="' + name + '"]'); + if (!$control.length) { return; } + + document.body.classList.remove(CLASS_TOUR); + $control.one('afterShow.cfw.popover', function() { + document.querySelector('#tour_' + name).focus(); + window.parent.clusiveEvents.addTipViewToQueue(name); + }); + setTimeout(function() { + $control.CFW_Popover('show'); + }, 2000); }, // Chain animations for tour items together @@ -38,13 +54,18 @@ var $curr = $(document).find(SELECTOR_TOUR_VISIBLE); var $next = $(selector); + // Hide tip/tour tooltip if showing + $('#tip').CFW_Tooltip('hide'); + if ($curr.length) { // Wait until hide animation is complete before callling show $curr.CFW_Popover('hide').CFW_transition(null, function() { + document.body.classList.add(CLASS_TOUR); $next.CFW_Popover('show'); $next[0].focus(); }); } else { + document.body.classList.add(CLASS_TOUR); $next.CFW_Popover('show'); $next[0].focus(); } @@ -61,9 +82,11 @@ if ($curr.length) { // Wait until hide animation is complete before focusing $curr.CFW_Popover('hide').CFW_transition(null, function() { + document.body.classList.remove(CLASS_TOUR); $next[0].focus(); }); } else { + document.body.classList.remove(CLASS_TOUR); $next[0].focus(); } @@ -72,4 +95,4 @@ }; window.tour = tourModule.prototype; -}(jQuery)); +}(jQuery)); \ No newline at end of file diff --git a/src/frontend/scss/site/_box.scss b/src/frontend/scss/site/_box.scss index 5130cd008..4d4bcb74d 100644 --- a/src/frontend/scss/site/_box.scss +++ b/src/frontend/scss/site/_box.scss @@ -83,6 +83,16 @@ background-repeat: no-repeat; background-size: contain; } + + .tip-mascot { + position: absolute; + top: calc(var(--CT_boxMascotSize) * -.375); + left: calc(1rem + var(--CT_boxMascotSize)); + display: block; + width: 1px; + height: 1px; + content: ""; + } } .clusive-reduced-motion { diff --git a/src/frontend/scss/site/_button.scss b/src/frontend/scss/site/_button.scss index 7ede3c7e5..7a4ba940a 100644 --- a/src/frontend/scss/site/_button.scss +++ b/src/frontend/scss/site/_button.scss @@ -6,7 +6,8 @@ .btn-nav, .btn-setting, .btn-tool, -.btn-tts { +.btn-tts, +.btn-mascot-tipped { display: inline-flex; align-items: center; justify-content: center; @@ -135,3 +136,21 @@ @include font-size($tag-font-size); font-weight: $tag-font-weight; } + +.btn-mascot-tipped { + position: relative; + + &::before { + position: absolute; + top: 50%; + left: 50%; + display: block; + width: 1.75rem; + height: calc(1.75rem * #{$img-ratio-mascot-tipped}); + content: ""; + background-image: var(--CT_imgMascotTipped); + background-repeat: no-repeat; + background-size: contain; + transform: translate(-50%, -50%); + } +} \ No newline at end of file diff --git a/src/frontend/scss/site/_content.scss b/src/frontend/scss/site/_content.scss index dd4efcb75..ddcab3b50 100644 --- a/src/frontend/scss/site/_content.scss +++ b/src/frontend/scss/site/_content.scss @@ -542,19 +542,13 @@ h2, } .feature-context { position: absolute; - //top: 33%; - //left: 50%; - top: 66%; - left: $sidebar-width; + top: 25%; + left: 50%; margin-right: ($grid-gutter-width / -2); margin-left: ($grid-gutter-width / -2); pointer-events: none; outline: 0; @include sr-only(); - - @include media-breakpoint-up(md) { - left: $sidebar-md-width; - } } .feature-list { @@ -720,3 +714,19 @@ h2, animation-duration: $loader-circle-animation-speed * 2; } } + +// stylelint-disable selector-no-qualifying-type +// Conditionally show/hide content in tour popovers depending on if +// state is singleton (auto-shown) or part of the tour started from +// the tour/mascot button +body:not(.touring) { + .touring-on { + display: none; + } +} +body.touring { + .touring-off { + display: none; + } +} +// stylelint-enable selector-no-qualifying-type diff --git a/src/frontend/scss/site/_tooltip.scss b/src/frontend/scss/site/_tooltip.scss index ba513765d..a847ec366 100644 --- a/src/frontend/scss/site/_tooltip.scss +++ b/src/frontend/scss/site/_tooltip.scss @@ -97,3 +97,12 @@ .tooltip-step { margin-right: auto; } + +.tooltip-tour { + .tooltip-body { + max-width: 15.5rem; + } + .tooltip-action { + justify-content: space-between; + } +} diff --git a/src/library/templates/library/library.html b/src/library/templates/library/library.html index 89c674cde..2e287f3bf 100644 --- a/src/library/templates/library/library.html +++ b/src/library/templates/library/library.html @@ -54,11 +54,5 @@

Library

{% include "shared/partial/modal_vocab_check.html" %} -{% for tour in tours %} -{% include "shared/partial/popover_tour.html" with tour_name=tour.name tour_robust=tour.robust %} -{% endfor %} -{% if tip_name %} -{% include "shared/partial/tooltip_tip.html" %} -{% endif %} {% include "shared/partial/modal_confirm.html" %} {% endblock %} diff --git a/src/library/templates/library/resources.html b/src/library/templates/library/resources.html index 5b16b53fa..ecd2e1d15 100644 --- a/src/library/templates/library/resources.html +++ b/src/library/templates/library/resources.html @@ -42,10 +42,4 @@

{{ cat.name }}

{% endfor %} -{% for tour in tours %} -{% include "shared/partial/popover_tour.html" with tour_name=tour.name tour_robust=tour.robust %} -{% endfor %} -{% if tip_name %} -{% include "shared/partial/tooltip_tip.html" %} -{% endif %} {% endblock %} diff --git a/src/library/views.py b/src/library/views.py index 30b32cfd1..8a273b85c 100644 --- a/src/library/views.py +++ b/src/library/views.py @@ -34,7 +34,7 @@ get_access_keys, is_organization_sponsor, is_organization_member from pages.views import ThemedPageMixin, SettingsPageMixin from roster.models import ClusiveUser, Period, LibraryViews, LibraryStyles, check_valid_choice -from tips.models import TipHistory +from tips.models import TipHistory, TourList logger = logging.getLogger(__name__) @@ -385,17 +385,15 @@ def dispatch(self, request, *args, **kwargs): def get(self, request, *args, **kwargs): self.tip_shown = TipHistory.get_tip_to_show(request.clusive_user, 'Library') + self.tours = TourList(request.clusive_user, page='Library') return super().get(request, *args, **kwargs) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['search_form'] = self.search_form - # BEGIN: Sample Tour - # Sample tour with single item list context['tip_name'] = None - context['tours'] = [{'name': self.tip_shown.name, 'robust': True }] if self.tip_shown else None - # END: Sample Tour - context['tip_shown'] = self.tip_shown + context['tip_shown'] = self.tip_shown.name if self.tip_shown else None + context['tours'] = self.tours context['has_teacher_resource'] = False context['has_bookshare_account'] = has_bookshare_account(self.request) return context @@ -425,12 +423,13 @@ class ResourcesPageView(LoginRequiredMixin, ThemedPageMixin, SettingsPageMixin, def get(self, request, *args, **kwargs): self.tip_shown = TipHistory.get_tip_to_show(request.clusive_user, self.page_name) + self.tours = TourList(request.clusive_user, page=self.page_name) self.extra_context = { 'categories': EducatorResourceCategory.objects.all() .prefetch_related(Prefetch('resources', queryset=Book.objects.order_by('resource_sort_order'))), 'tip_name': None, - 'tours': [{'name': self.tip_shown.name, 'robust': True }] if self.tip_shown else None, - 'tip_shown': self.tip_shown, + 'tip_shown': self.tip_shown.name if self.tip_shown else None, + 'tours': self.tours, 'has_teacher_resource': False, # "Learn more" link is circular in this case. 'clusive_user': request.clusive_user, } diff --git a/src/pages/templates/pages/dashboard.html b/src/pages/templates/pages/dashboard.html index 980727b2a..537dcd9d9 100644 --- a/src/pages/templates/pages/dashboard.html +++ b/src/pages/templates/pages/dashboard.html @@ -66,12 +66,5 @@

Dashboard

{% include "shared/partial/modal_vocab_check.html" %} -{% for tour in tours %} -{% include "shared/partial/popover_tour.html" with tour_name=tour.name tour_robust=tour.robust %} -{% endfor %} -{% if tip_name %} -{% include "shared/partial/tooltip_tip.html" %} -{% endif %} {% include "shared/partial/modal_confirm.html" %} - {% endblock %} diff --git a/src/pages/templates/pages/partial/dashboard_panel_popular_reads.html b/src/pages/templates/pages/partial/dashboard_panel_popular_reads.html index 18b176db3..700864981 100644 --- a/src/pages/templates/pages/partial/dashboard_panel_popular_reads.html +++ b/src/pages/templates/pages/partial/dashboard_panel_popular_reads.html @@ -1,4 +1,8 @@
+ {% if tip_name == "tour" %} + + {% endif %} + {% if is_teacher %}

Student reading

{% else %} diff --git a/src/pages/templates/pages/reader.html b/src/pages/templates/pages/reader.html index 7c8f1d843..00d7da37c 100644 --- a/src/pages/templates/pages/reader.html +++ b/src/pages/templates/pages/reader.html @@ -388,11 +388,5 @@
{% include "shared/partial/modal_toc.html" %} -{% for tour in tours %} -{% include "shared/partial/popover_tour.html" with tour_name=tour.name tour_robust=tour.robust %} -{% endfor %} -{% if tip_name %} -{% include "shared/partial/tooltip_tip.html" %} -{% endif %} {% include "shared/partial/popover_simplify.html" %} {% endblock %} diff --git a/src/pages/templates/pages/wordbank.html b/src/pages/templates/pages/wordbank.html index 99e0ac253..6349e3cf2 100644 --- a/src/pages/templates/pages/wordbank.html +++ b/src/pages/templates/pages/wordbank.html @@ -79,10 +79,4 @@

Rate some words!

-{% for tour in tours %} -{% include "shared/partial/popover_tour.html" with tour_name=tour.name tour_robust=tour.robust %} -{% endfor %} -{% if tip_name %} -{% include "shared/partial/tooltip_tip.html" %} -{% endif %} {% endblock %} diff --git a/src/pages/templatetags/list_helpers.py b/src/pages/templatetags/list_helpers.py new file mode 100644 index 000000000..bc032f7da --- /dev/null +++ b/src/pages/templatetags/list_helpers.py @@ -0,0 +1,29 @@ +from django import template +from django.template.defaultfilters import stringfilter + +register = template.Library() + +@register.filter(is_safe=True) +def list_index(sequence, position): + try: + return sequence[position] + except: + return None + +@register.filter(is_safe=True) +def list_index_prev(sequence, position): + if 0 >= position: + return None + try: + return sequence[int(position) - 1] + except: + return None + +@register.filter(is_safe=True) +def list_index_next(sequence, position): + if len(sequence) - 1 == position: + return None + try: + return sequence[int(position) + 1] + except: + return None \ No newline at end of file diff --git a/src/pages/views.py b/src/pages/views.py index 3ebf69420..3fe300d4f 100644 --- a/src/pages/views.py +++ b/src/pages/views.py @@ -28,7 +28,7 @@ from library.models import Book, BookVersion, Paradata, Annotation, BookTrend, \ Customization, BookAssignment from roster.models import ClusiveUser, Period, Roles, UserStats, Preference -from tips.models import TipHistory, CTAHistory, CompletionType +from tips.models import TipHistory, CTAHistory, CompletionType, TourList from translation.util import TranslateApiManager logger = logging.getLogger(__name__) @@ -128,6 +128,7 @@ def get(self, request, *args, **kwargs): self.dashboard_popular_view = self.clusive_user.dashboard_popular_view self.tip_shown = TipHistory.get_tip_to_show(self.clusive_user, page='Dashboard') + self.tours = TourList(self.clusive_user, page='Dashboard') # Decision-making data user_stats = UserStats.objects.get(user=request.clusive_user) @@ -224,12 +225,10 @@ def get_context_data(self, **kwargs): context['panels'] = self.panels context['data'] = self.data context['clusive_user'] = self.clusive_user - # BEGIN: Sample Tour - # Sample tour with single item list - context['tip_name'] = None - context['tours'] = [{'name': self.tip_shown.name, 'robust': True }] if self.tip_shown else None - # END: Sample Tour - context['tip_shown'] = self.tip_shown + # 'tour' is a special case and uses the older tooltip functionality + context['tip_name'] = 'tour' if self.tip_shown and self.tip_shown.name == 'tour' else None # tour tooltip + context['tip_shown'] = self.tip_shown.name if self.tip_shown and self.tip_shown.name != 'tour' else None # Singleton tour item + context['tours'] = self.tours context['has_teacher_resource'] = self.clusive_user.role == Roles.TEACHER or self.clusive_user.role == Roles.PARENT return context @@ -691,6 +690,7 @@ def get(self, request, *args, **kwargs): # See if there's a Tip that should be shown self.tip_shown = TipHistory.get_tip_to_show(clusive_user, page=self.page_name, version_count=len(versions)) + self.tours = TourList(clusive_user, page=self.page_name, version_count=len(versions)) # See if there's a custom question customizations = Customization.objects.filter(book=book, periods=clusive_user.current_period) \ @@ -718,12 +718,9 @@ def get(self, request, *args, **kwargs): 'annotations': annotationList, 'cuelist': json.dumps(cuelist), 'hide_cues': hide_cues, - # BEGIN: Sample Tour - # Sample tour with single item list 'tip_name': None, - 'tours': [{'name': self.tip_shown.name, 'robust': True }] if self.tip_shown else None, - # END: Sample Tour - 'tip_shown': self.tip_shown, + 'tip_shown': self.tip_shown.name if self.tip_shown else None, + 'tours': self.tours, 'has_teacher_resource': True, 'customization': customizations[0] if customizations else None, 'starred': pdata.starred, @@ -748,13 +745,14 @@ def get(self, request, *args, **kwargs): # Check for Tip clusive_user = request.clusive_user tip_shown = TipHistory.get_tip_to_show(clusive_user, page='Wordbank') + tours = TourList(clusive_user, page='Wordbank') self.extra_context = { 'words': WordModel.objects.filter(user=request.clusive_user, interest__gt=0).order_by('word'), 'clusive_user': clusive_user, 'tip_name': None, - 'tours': [{'name': tip_shown.name, 'robust': True }] if tip_shown else None, - 'tip_shown': tip_shown, + 'tip_shown': tip_shown.name if tip_shown else None, + 'tours': tours, 'has_teacher_resource': False, } return super().get(request, *args, **kwargs) diff --git a/src/roster/templates/roster/manage.html b/src/roster/templates/roster/manage.html index a47a6f32b..1d6b02b5d 100644 --- a/src/roster/templates/roster/manage.html +++ b/src/roster/templates/roster/manage.html @@ -87,13 +87,7 @@

If you have made changes to your Google Classroom class roster (e.g., you added or removed a student), use this option to update your class list in Clusive.

- {% endif %} + {% endif %} {% endif %} -{% for tour in tours %} -{% include "shared/partial/popover_tour.html" with tour_name=tour.name tour_robust=tour.robust %} -{% endfor %} -{% if tip_name %} -{% include "shared/partial/tooltip_tip.html" %} -{% endif %} {% endblock %} diff --git a/src/roster/views.py b/src/roster/views.py index 0249bc2de..6f4ce2224 100644 --- a/src/roster/views.py +++ b/src/roster/views.py @@ -49,7 +49,7 @@ from roster.models import ClusiveUser, Period, PreferenceSet, Roles, ResearchPermissions, MailingListMember, \ RosterDataSource from roster.signals import user_registered -from tips.models import TipHistory +from tips.models import TipHistory, TourList logger = logging.getLogger(__name__) @@ -472,6 +472,7 @@ def get(self, request, *args, **kwargs): user = request.clusive_user # See if there's a Tip that should be shown self.tip_shown = TipHistory.get_tip_to_show(user, page="Manage") + self.tours = TourList(user, page="Manage") if not user.can_manage_periods: self.handle_no_permission() return super().get(request, *args, **kwargs) @@ -481,12 +482,9 @@ def get_context_data(self, **kwargs): if self.current_period is not None: context['people'] = self.make_people_info_list(self.request.user) context['period_name_form'] = PeriodNameForm(instance=self.current_period) - # BEGIN: Sample Tour - # Sample tour with single item list context['tip_name'] = None - context['tours'] = [{'name': self.tip_shown.name, 'robust': True }] if self.tip_shown else None - # END: Sample Tour - context['tip_shown'] = self.tip_shown + context['tip_shown'] = self.tip_shown.name if self.tip_shown else None + context['tours'] = self.tours context['has_teacher_resource'] = False # "Learn more" link would be circular context['clusive_user'] = self.request.clusive_user return context diff --git a/src/shared/templates/shared/base.html b/src/shared/templates/shared/base.html index a501711a8..a8a3a5adf 100644 --- a/src/shared/templates/shared/base.html +++ b/src/shared/templates/shared/base.html @@ -50,7 +50,10 @@ {% block sidebar_bottom_start %} {% include "shared/partial/sidebar_bottom_start.html" with show_reading_feedback=False %} {% endblock%} + + @@ -68,15 +71,18 @@ {% endif %} + {% if tours %} + {% include "shared/partial/popover_tour.html" %} + {% endif %} + {% if tip_name %} + {% include "shared/partial/tooltip_tip.html" %} + {% endif %} +
{% comment %}{% endcomment %}
-
-
-
- -
+
diff --git a/src/shared/templates/shared/partial/popover_tour.html b/src/shared/templates/shared/partial/popover_tour.html index e657c326c..fceeafe5c 100644 --- a/src/shared/templates/shared/partial/popover_tour.html +++ b/src/shared/templates/shared/partial/popover_tour.html @@ -1,11 +1,8 @@ {% load i18n %} +{% for tour_name in tours %}
- {% if tour_robust %} - {% if tours|length > 1 %} - - {% else %} - - {% endif %} + +
{% if tour_name == "settings" %} @@ -67,7 +64,6 @@
- {% endif %}
{% if tour_name == "settings" %} @@ -75,74 +71,38 @@

Change the font, colors, and more! Settings let you choose the look, supports, and reading tools to make Clusive all your own.

-
-
- {% if has_teacher_resource %} - {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} - Learn more about settings - {% endif %} - {% endif %} -
-
- -
-
+ {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} + {% include "shared/partial/popover_tour_footer.html" with resource_id="SSETTINGS" resource_name="settings" %} + {% else %} + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} + {% endif %} {% elif tour_name == "readaloud" %}

Click the page read aloud icon to hear the entire page. Select text and click read aloud in the context menu to hear a smaller selection or a single word read aloud.

-
-
- {% if has_teacher_resource %} - {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} - - - {% endif %} - {% endif %} -
-
- -
-
+ + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} {% elif tour_name == "wordbank" %}

The Word bank collects words you’ve looked up or rated. Check out how you’ve rated words. Change ratings as your word knowledge grows. Get back to your previous page by clicking on the back button.

-
-
- {% if has_teacher_resource %} - {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} - - - {% endif %} - {% endif %} -
-
- -
-
+ + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} {% elif tour_name == "switch" %}

Switch gives three challenge options for some texts. Open Switch, check out the vocabulary in each version, and choose to stay, or change challenge levels. It’s up to you!

-
-
- {% if has_teacher_resource %} - {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} - Learn more about switch - {% endif %} - {% endif %} -
-
- -
-
+ {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} + {% include "shared/partial/popover_tour_footer.html" with resource_id="SWITCH" resource_name="switch" %} + {% else %} + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} + {% endif %} {% elif tour_name == "context" %}
@@ -155,38 +115,16 @@
  • Translate or simplify
  • Hear the words read aloud
  • -
    -
    - {% if has_teacher_resource %} - {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} - - - {% endif %} - {% endif %} -
    -
    - -
    -
    + + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} {% elif tour_name == "view" %}

    View the Clusive library by all readings, or in smaller groupings like class readings, readings you’ve starred, public readings, or readings you’ve uploaded.

    -
    -
    - {% if has_teacher_resource %} - {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} - - - {% endif %} - {% endif %} -
    -
    - -
    -
    + + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} {% elif tour_name == "book_actions" %} {% if clusive_user.role == 'TE' %} @@ -195,18 +133,11 @@
    {% endif %}

    Click “More actions” (three dots) to assign or customize any book, and for books you uploaded to Clusive, to edit information or delete a book.

    -
    -
    - {% if has_teacher_resource %} - {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} - Learn more about book actions - {% endif %} - {% endif %} -
    -
    - -
    -
    + {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} + {% include "shared/partial/popover_tour_footer.html" with resource_id="CREAD" resource_name="book actions" %} + {% else %} + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} + {% endif %} {% elif tour_name == "activity" %} {% if clusive_user.role == 'TE' %} @@ -216,18 +147,11 @@ {% endif %}

    Get a quick overview of student activity. Hover over active reading time bars for titles and reading time. Click a bar to see readings students have in common. Triangles show readings you have assigned.

    Select timeframe and sort by hours, books, or student name.

    -
    -
    - {% if has_teacher_resource %} - {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} - Learn more about student activities data - {% endif %} - {% endif %} -
    -
    - -
    -
    + {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} + {% include "shared/partial/popover_tour_footer.html" with resource_id="READDTL" resource_name="student activities data" %} + {% else %} + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} + {% endif %} {% elif tour_name == "student_reactions" %} {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} @@ -241,18 +165,11 @@

    Click on a reaction word and see Clusive readings that inspired you and others to react with that word.

    {% endif %} -
    -
    - {% if has_teacher_resource %} - {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} - Learn more about students' reactions - {% endif %} - {% endif %} -
    -
    - -
    -
    + {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} + {% include "shared/partial/popover_tour_footer.html" with resource_id="SREACT" resource_name="students' reactions" %} + {% else %} + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} + {% endif %} {% elif tour_name == "reading_data" %} {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} @@ -266,31 +183,18 @@

    See assigned readings your recent readings, and popular readings to check out. Go to the library to find more things to read. Have a document you want to upload? Click Upload a new reading to get started!

    {% endif %} -
    -
    - {% if has_teacher_resource %} - {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} - Learn more about students' reactions - {% endif %} - {% endif %} -
    -
    - -
    -
    + {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} + {% include "shared/partial/popover_tour_footer.html" with resource_id="SREADP" resource_name="student reading data" %} + {% else %} + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} + {% endif %} {% elif tour_name == "thoughts" %}

    Reflect on how a reading made you feel, answer questions your teacher has posted, and mark how much you’ve learned. Your thoughts on how the reading made you feel are collected on your student dashboard.

    -
    -
    -
    -
    - -
    -
    + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} {% elif tour_name == "manage" %} {% if clusive_user.role == 'TE' %} @@ -299,18 +203,11 @@ {% endif %}

    Import, add or edit classes and student information in Clusive.

    -
    -
    - {% if has_teacher_resource %} - {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} - Learn more about manage - {% endif %} - {% endif %} -
    -
    - -
    -
    + {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} + {% include "shared/partial/popover_tour_footer.html" with resource_id="CCLASS" resource_name="manage" %} + {% else %} + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} + {% endif %} {% elif tour_name == "resources" %} {% if clusive_user.role == 'TE' %} @@ -319,66 +216,41 @@ {% endif %}

    Get tips, resources and videos for getting you and your students started in Clusive, and for building teaching skills with Clusive tools and features.

    -
    -
    - {% if has_teacher_resource %} - {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} - Learn more about resources - {% endif %} - {% endif %} -
    -
    - -
    -
    + {% if clusive_user.role == 'TE' or clusive_user.role == 'PA' %} + {% include "shared/partial/popover_tour_footer.html" with resource_id="RESOURCES" resource_name="resources" %} + {% else %} + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} + {% endif %} {% elif tour_name == "filters" %}

    Use filters to find readings based on topics, reading levels, and word count. Click on one or more topics or filters and get readings that match any of your selections.

    -
    -
    -
    -
    - -
    -
    + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} {% elif tour_name == "search" %}

    Search for readings by part of all of a title, author name, publisher, even words that are included in the descriptions on reading tiles. Looking for topic or subject areas? Use the Library filters instead!.

    -
    -
    -
    -
    - -
    -
    + {% include "shared/partial/popover_tour_footer.html" with resource_id=None %} {% endif %} {% if tour_name != "context" and tour_name != "activity" %}
    {% endif %} +{% endfor %} +{% if tours %} +{% endif %} diff --git a/src/shared/templates/shared/partial/popover_tour_footer.html b/src/shared/templates/shared/partial/popover_tour_footer.html new file mode 100644 index 000000000..e9800270b --- /dev/null +++ b/src/shared/templates/shared/partial/popover_tour_footer.html @@ -0,0 +1,34 @@ +{% load i18n %} +{% load list_helpers %} + +
    +
    + {% if has_teacher_resource and resource_id %} + {% if resource_id == 'RESOURCES' %} + Learn more about {{ resource_name }} + {% else %} + Learn more about {{ resource_name }} + {% endif %} + {% endif %} +
    + {% if tours|list_index_prev:forloop.counter0 %} +
    + +
    + {% endif %} + {% if tours|length > 1 %} +
    + {{ forloop.counter }}/{{ tours|length }} +
    + {% endif %} +
    + {% if tours|list_index_next:forloop.counter0 %} + + {% else %} + + {% endif %} +
    +
    + +
    +
    \ No newline at end of file diff --git a/src/shared/templates/shared/partial/sidebar_bottom_end.html b/src/shared/templates/shared/partial/sidebar_bottom_end.html new file mode 100644 index 000000000..8f726147e --- /dev/null +++ b/src/shared/templates/shared/partial/sidebar_bottom_end.html @@ -0,0 +1,10 @@ +{% load list_helpers %} + diff --git a/src/shared/templates/shared/partial/tooltip_tip.html b/src/shared/templates/shared/partial/tooltip_tip.html index f60f17563..f35f9c49d 100644 --- a/src/shared/templates/shared/partial/tooltip_tip.html +++ b/src/shared/templates/shared/partial/tooltip_tip.html @@ -1,5 +1,6 @@ {% load i18n %} -
    +{% load list_helpers %} +
    {% if tip_name == "settings" %}

    Settings: Change the font, colors, and more!

    @@ -71,6 +72,12 @@
    Previous
    +
    + {% elif tip_name == "tour" %} +

    To get a tour of this page, click on me in the lower right anytime!

    +
    + +
    {% endif %} diff --git a/src/tips/fixtures/tiptypes.json b/src/tips/fixtures/tiptypes.json index 1c1324d4e..ff2409b1c 100644 --- a/src/tips/fixtures/tiptypes.json +++ b/src/tips/fixtures/tiptypes.json @@ -4,7 +4,7 @@ "pk": 1, "fields": { "name": "settings", - "priority": 1, + "priority": 2, "max": 3, "interval": "7 00:00:00" } @@ -14,7 +14,7 @@ "pk": 2, "fields": { "name": "readaloud", - "priority": 2, + "priority": 3, "max": 3, "interval": "7 00:00:00" } @@ -24,7 +24,7 @@ "pk": 3, "fields": { "name": "context", - "priority": 3, + "priority": 4, "max": 3, "interval": "7 00:00:00" } @@ -34,7 +34,7 @@ "pk": 4, "fields": { "name": "switch", - "priority": 4, + "priority": 5, "max": 3, "interval": "7 00:00:00" } @@ -44,7 +44,7 @@ "pk": 5, "fields": { "name": "wordbank", - "priority": 5, + "priority": 6, "max": 3, "interval": "7 00:00:00" } @@ -54,7 +54,7 @@ "pk": 6, "fields": { "name": "view", - "priority": 6, + "priority": 7, "max": 3, "interval": "7 00:00:00" } @@ -64,7 +64,7 @@ "pk": 7, "fields": { "name": "book_actions", - "priority": 7, + "priority": 8, "max": 3, "interval": "7 00:00:00" } @@ -74,7 +74,7 @@ "pk": 8, "fields": { "name": "activity", - "priority": 8, + "priority": 9, "max": 3, "interval": "7 00:00:00" } @@ -84,7 +84,7 @@ "pk": 9, "fields": { "name": "student_reactions", - "priority": 9, + "priority": 10, "max": 3, "interval": "7 00:00:00" } @@ -94,7 +94,7 @@ "pk": 10, "fields": { "name": "reading_data", - "priority": 10, + "priority": 11, "max": 3, "interval": "7 00:00:00" } @@ -104,7 +104,7 @@ "pk": 11, "fields": { "name": "thoughts", - "priority": 11, + "priority": 12, "max": 3, "interval": "7 00:00:00" } @@ -114,7 +114,7 @@ "pk": 12, "fields": { "name": "manage", - "priority": 12, + "priority": 13, "max": 3, "interval": "7 00:00:00" } @@ -124,7 +124,7 @@ "pk": 13, "fields": { "name": "resources", - "priority": 13, + "priority": 14, "max": 3, "interval": "7 00:00:00" } @@ -134,7 +134,7 @@ "pk": 14, "fields": { "name": "filters", - "priority": 14, + "priority": 15, "max": 3, "interval": "7 00:00:00" } @@ -144,7 +144,17 @@ "pk": 15, "fields": { "name": "search", - "priority": 15, + "priority": 16, + "max": 3, + "interval": "7 00:00:00" + } + }, + { + "model": "tips.tiptype", + "pk": 16, + "fields": { + "name": "tour", + "priority": 1, "max": 3, "interval": "7 00:00:00" } diff --git a/src/tips/models.py b/src/tips/models.py index 6428752c2..43053c875 100644 --- a/src/tips/models.py +++ b/src/tips/models.py @@ -19,6 +19,7 @@ # The order of popovers for a given page matches the tour order. See: # https://castudl.atlassian.net/browse/CSL-2040?focusedCommentId=36802 DASHBOARD_TIPS = [ + 'tour', 'student_reactions', 'reading_data', 'activity', @@ -349,3 +350,26 @@ def available_ctas(cls, user: ClusiveUser, page: str): return [h for h in histories if h.type.can_show(page) and h.ready_to_show(user_stats)] + + +def TourList(user: ClusiveUser, page: str, version_count=0): + # See rules in TipType.can_show() + full = PAGE_TIPS_MAP[page] + available = [] + + for name in full: + # Tooltip version of tips are not part of tour + if name == 'tour': + continue + # Teacher/parent-only tips + if user.role == Roles.STUDENT and name in TEACHER_ONLY_TIPS: + continue + # Switch TipType requires multiple versions + if name == 'switch' and not version_count > 1: + continue + # Thoughts TipType is only for students + if name == 'thoughts' and user.role != Roles.STUDENT: + continue + available.append(name) + + return available if len(available) > 1 else None \ No newline at end of file From 7f6058f113f3c21509c33cc50a24b7bec015591a Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Fri, 28 Oct 2022 18:24:31 -0400 Subject: [PATCH 2/4] CSL-2041: Add manage command to increment TipType priorities --- src/tips/fixtures/tiptypes.json | 20 +++++++++--------- .../commands/decrementpriorities.py | 21 +++++++++++++++++++ .../commands/incrementpriorities.py | 20 ++++++++++++++++++ 3 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 src/tips/management/commands/decrementpriorities.py create mode 100644 src/tips/management/commands/incrementpriorities.py diff --git a/src/tips/fixtures/tiptypes.json b/src/tips/fixtures/tiptypes.json index ff2409b1c..1522d38f8 100644 --- a/src/tips/fixtures/tiptypes.json +++ b/src/tips/fixtures/tiptypes.json @@ -1,4 +1,14 @@ [ + { + "model": "tips.tiptype", + "pk": 16, + "fields": { + "name": "tour", + "priority": 1, + "max": 3, + "interval": "7 00:00:00" + } + }, { "model": "tips.tiptype", "pk": 1, @@ -148,15 +158,5 @@ "max": 3, "interval": "7 00:00:00" } - }, - { - "model": "tips.tiptype", - "pk": 16, - "fields": { - "name": "tour", - "priority": 1, - "max": 3, - "interval": "7 00:00:00" - } } ] diff --git a/src/tips/management/commands/decrementpriorities.py b/src/tips/management/commands/decrementpriorities.py new file mode 100644 index 000000000..240f284b2 --- /dev/null +++ b/src/tips/management/commands/decrementpriorities.py @@ -0,0 +1,21 @@ +import logging + +from django.core.management import call_command +from django.core.management.base import BaseCommand, CommandError + +from tips.models import TipType + +logger = logging.getLogger(__name__) + +class Command(BaseCommand): + help = 'Beginnig with the TipType with the least priority, loop\n' \ + 'through all TipTypes decreassing their priority by 1 (one).\n' \ + 'Only do this if you have prefiously increased the priority.\n' \ + + def handle(self, *args, **options): + tip_types = TipType.objects.all().order_by('priority') + for tip in tip_types: + tip.priority -= 1 + tip.save() + logger.debug(f"Updated {tip}'s priority to {tip.priority}") + logger.debug("Done") diff --git a/src/tips/management/commands/incrementpriorities.py b/src/tips/management/commands/incrementpriorities.py new file mode 100644 index 000000000..6e3cc44f8 --- /dev/null +++ b/src/tips/management/commands/incrementpriorities.py @@ -0,0 +1,20 @@ +import logging + +from django.core.management import call_command +from django.core.management.base import BaseCommand, CommandError + +from tips.models import TipType + +logger = logging.getLogger(__name__) + +class Command(BaseCommand): + help = 'Beginnig with the TipType with the greatest priority, loop\n' \ + 'through all TipTypes increasing their priority by 1 (one).\n' + + def handle(self, *args, **options): + tip_types = TipType.objects.all().order_by('priority').reverse() + for tip in tip_types: + tip.priority += 1 + tip.save() + logger.debug(f"Updated {tip}'s priority to {tip.priority}") + logger.debug("Done") From 0b05766502d12551098dd51b04585560c8a648b2 Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Mon, 31 Oct 2022 15:21:37 -0400 Subject: [PATCH 3/4] CSL-2041: Fix typos --- src/tips/management/commands/decrementpriorities.py | 7 ++++--- src/tips/management/commands/incrementpriorities.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tips/management/commands/decrementpriorities.py b/src/tips/management/commands/decrementpriorities.py index 240f284b2..0e4c3bd45 100644 --- a/src/tips/management/commands/decrementpriorities.py +++ b/src/tips/management/commands/decrementpriorities.py @@ -8,9 +8,10 @@ logger = logging.getLogger(__name__) class Command(BaseCommand): - help = 'Beginnig with the TipType with the least priority, loop\n' \ - 'through all TipTypes decreassing their priority by 1 (one).\n' \ - 'Only do this if you have prefiously increased the priority.\n' \ + help = 'This acts as a reset to reverse the situation due to running the' \ + '`incrementpriorities` command.\n' \ + 'Beginning with the TipType with the least priority, loop\n' \ + 'through all TipTypes decreasing their priority by 1 (one).\n' \ def handle(self, *args, **options): tip_types = TipType.objects.all().order_by('priority') diff --git a/src/tips/management/commands/incrementpriorities.py b/src/tips/management/commands/incrementpriorities.py index 6e3cc44f8..b1f3a3ea0 100644 --- a/src/tips/management/commands/incrementpriorities.py +++ b/src/tips/management/commands/incrementpriorities.py @@ -8,7 +8,7 @@ logger = logging.getLogger(__name__) class Command(BaseCommand): - help = 'Beginnig with the TipType with the greatest priority, loop\n' \ + help = 'Beginning with the TipType with the greatest priority, loop\n' \ 'through all TipTypes increasing their priority by 1 (one).\n' def handle(self, *args, **options): From 548298aa0e27bf8fa9053c7ff058320d43ad6672 Mon Sep 17 00:00:00 2001 From: Joseph Scheuhammer Date: Wed, 9 Nov 2022 16:34:29 -0500 Subject: [PATCH 4/4] CSL-2041: Have log messages as type 'INFO' --- src/tips/management/commands/decrementpriorities.py | 4 ++-- src/tips/management/commands/incrementpriorities.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tips/management/commands/decrementpriorities.py b/src/tips/management/commands/decrementpriorities.py index 0e4c3bd45..bab0eefc2 100644 --- a/src/tips/management/commands/decrementpriorities.py +++ b/src/tips/management/commands/decrementpriorities.py @@ -18,5 +18,5 @@ def handle(self, *args, **options): for tip in tip_types: tip.priority -= 1 tip.save() - logger.debug(f"Updated {tip}'s priority to {tip.priority}") - logger.debug("Done") + logger.info(f"Updated {tip}'s priority to {tip.priority}") + logger.info("Done") diff --git a/src/tips/management/commands/incrementpriorities.py b/src/tips/management/commands/incrementpriorities.py index b1f3a3ea0..351804142 100644 --- a/src/tips/management/commands/incrementpriorities.py +++ b/src/tips/management/commands/incrementpriorities.py @@ -16,5 +16,5 @@ def handle(self, *args, **options): for tip in tip_types: tip.priority += 1 tip.save() - logger.debug(f"Updated {tip}'s priority to {tip.priority}") - logger.debug("Done") + logger.info(f"Updated {tip}'s priority to {tip.priority}") + logger.info("Done")