Skip to content

Commit

Permalink
working on tour add form
Browse files Browse the repository at this point in the history
  • Loading branch information
mutantsan committed Jul 23, 2023
1 parent 3b6e0b3 commit a9942b1
Show file tree
Hide file tree
Showing 18 changed files with 409 additions and 16 deletions.
28 changes: 28 additions & 0 deletions ckanext/tour/assets/css/style.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ckanext/tour/assets/css/style.css.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions ckanext/tour/assets/js/tour-htmx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* A hack script to properly load CKAN modules on an AJAX loaded HTML
*/
ckan.module("tour-htmx", function ($) {
return {
initialize: function () {
$.proxyAll(this, /_on/);
console.log('loaded');
document.addEventListener('htmx:beforeRequest', this._onHTMXbeforeRequest);
document.addEventListener('htmx:afterSettle', this._onHTMXafterSettle);
document.addEventListener('htmx:pushedIntoHistory', this._onHTMXpushedIntoHistory);
},

_onHTMXbeforeRequest: function (e) {
$(e.detail.target).find("[data-module]").unbind()

for (const [key, _] of Object.entries(ckan.module.instances)) {
ckan.module.instances[key] = null;
}
},

_onHTMXafterSettle: function (e) {
const doNotInitialize = ["tour-htmx"]

if (e.detail.pathInfo.requestPath === "/admin_panel/config/tour/add_step") {
var newStep = $(".tour-steps__steps .tour-step").last();

newStep.find("[data-module]").each(function (_, element) {
const moduleName = $(element).attr("data-module");

if (!doNotInitialize.includes(moduleName)) {
ckan.module.initializeElement(element);
}
})
}

},
};
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
this.ckan.module('init-tour', function (jQuery) {
this.ckan.module('tour-init', function (jQuery) {
return {
/* An object of module options */
options: {
template: [
'<a id="intro-switch" href="#" class="btn btn-sm question"><i class="fa fa-lg fa-question-circle"></i></a>',
Expand Down
73 changes: 73 additions & 0 deletions ckanext/tour/assets/js/tour-steps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* A script to manage multiple steps fieldsets
*/
ckan.module("tour-steps", function ($) {
return {
initialize: function () {
$.proxyAll(this, /_on/);
var self = this;

// this vars
this.addStepBtn = $(".add-step");

// add event listeners
$(document).on('click', '.add-step', this._onAddStep);
$(document).on('click', '.remove-step', this._onRemoveStep);

// HTMX events
document.body.addEventListener('htmx:afterSwap', function (e) {
let requestPath = e.detail.pathInfo.requestPath;

if (requestPath === "/admin_panel/config/tour/add_step") {
self._toggleRemoveBtns();
self._updateLastStepId();
}
});

this._toggleRemoveBtns();
this._updateLastStepId();
},

_onAddStep: function (e) {
//
},

/**
* Triggered on remove step
*
* @param {event} e
*/
_onRemoveStep: function (e) {
e.preventDefault();

var stepId = $(e.target).closest(".tour-step").data("stepId");

$(`#step_${stepId}`).remove();

this._toggleRemoveBtns();
this._updateLastStepId();
},

/**
* Should be at least 1 step for a tour. Disable remove step button if
* only 1 left.
*/
_toggleRemoveBtns: function () {
var steps = $(".tour-steps__steps .tour-step");
$(".remove-step").toggleClass("disabled", steps.length == 1)
},

/**
* Update the stepId we are sending to a server when adding a new step
*/
_updateLastStepId: function () {
var steps = $(".tour-steps__steps .tour-step");

this.addStepBtn.attr("hx-vals", JSON.stringify({
stepId: steps.last().data("step-id") + 1
}))


}
};
});
1 change: 1 addition & 0 deletions ckanext/tour/assets/js/vendor/htmx.min.js

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion ckanext/tour/assets/webassets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,19 @@ tour-js:
contents:
- js/vendor/intro.min.js
- js/vendor/mobile-detect.min.js
- js/init-tour.js
- js/tour-init.js
- js/tour-steps.js
- js/tour-htmx.js

tour-htmx:
filter: rjsmin
output: ckanext-tour/%(version)s-tour-htmx.js
contents:
- js/vendor/htmx.min.js

tour-css:
filter: cssrewrite
output: ckanext-tour/%(version)s-tour.css
contents:
- css/vendor/introjs.min.css
- css/style.css
18 changes: 11 additions & 7 deletions ckanext/tour/helpers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
from ckanext.tour.model import TourStep

def tour_hello():
return "Hello, tour!"


def get_helpers():
return {
"tour_hello": tour_hello,
}
def tour_get_position_options():
return [
{"value": step, "text": step}
for step in (
TourStep.Position.bottom,
TourStep.Position.top,
TourStep.Position.right,
TourStep.Position.left,
)
]
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def upgrade():
op.create_table(
"tour",
sa.Column("id", sa.Text, primary_key=True, unique=True),
sa.Column("title", sa.Text, nullable=False),
sa.Column("state", sa.Text, nullable=False, server_default="active"),
sa.Column("anchor", sa.Text, nullable=False),
sa.Column("page", sa.Text, nullable=True),
Expand Down
4 changes: 3 additions & 1 deletion ckanext/tour/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class State:

id = Column(Text, primary_key=True, default=make_uuid)

title = Column(Text, nullable=False)
state = Column(Text, nullable=False, default=State.active)
author_id = Column(ForeignKey(model.User.id, ondelete="CASCADE"), primary_key=True)
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
Expand All @@ -36,7 +37,7 @@ class State:
user = relationship(model.User)

def __repr__(self):
return f"Tour(id={self.id!r} author_id={self.author_id!r}"
return f"Tour(title={self.title}"

@classmethod
def create(cls, data_dict) -> Self:
Expand All @@ -50,6 +51,7 @@ def create(cls, data_dict) -> Self:
def dictize(self, context):
return {
"id": self.id,
"title": self.title,
"author_id": self.author_id,
"state": self.state,
"created_at": self.created_at.isoformat(),
Expand Down
5 changes: 3 additions & 2 deletions ckanext/tour/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def register_config_sections(
configs=[
ConfigurationItem(
name="Global settings",
blueprint="tour.list",
blueprint="tour.config",
info="Global configuration for a tour"
),
ConfigurationItem(
name="Manage tours",
Expand All @@ -42,7 +43,7 @@ def register_config_sections(
),
ConfigurationItem(
name="Add tour",
blueprint="user.index",
blueprint="tour.add",
info="Add new tour",
),
],
Expand Down
2 changes: 1 addition & 1 deletion ckanext/tour/templates/base.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% ckan_extends %}

{% block head_extras %}
<span class="hidden" data-module="init-tour"></span>
<span class="hidden" data-module="tour-init"></span>
{% endblock %}

{% block scripts %}
Expand Down
65 changes: 65 additions & 0 deletions ckanext/tour/templates/tour/tour_add.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{% extends 'admin_panel/base.html' %}

{% import 'macros/form.html' as form %}

{% block breadcrumb_content %}
<li>{% link_for _("Tour add"), named_route='tour.add' %}</li>
{% endblock breadcrumb_content %}

{% block ap_content %}
<h1>{{ _("Tour add") }}</h1>

<h1>Tour add form:</h1>
<form action="{{ h.url_for("tour.add") }}" method="POST">
{% call form.input("title", label=_("Tour title"), value=data.title, attrs={'required': 1, 'class': 'form-control'}) %}
{{ form.info(_("A tour title to explain what is it for")) }}
{% endcall %}

{% call form.input("anchor", label=_("Query anchor"), value=data.anchor) %}
{{ form.info(_('An anchor element query that will trigger the tour. Could be a tooltip, button or any HTML element.', classes=['info-help-tight'])) }}
{% endcall %}

{% call form.input("page", label=_("Page anchor"), value=data.page) %}
{{ form.info(_('Optional. A path to a page, where tour will be applied. Note, that a page tour will be triggered automatically.', classes=['info-help-tight'])) }}
{% endcall %}

<h3>{{ _("Tour steps:") }}</h3>

<div
class="tour-steps"
data-module="tour-steps tour-htmx">

<div class="tour-steps__steps">
{% for step in data.steps %}
{% snippet 'tour/tour_step.html', step=step %}
{% else %}
{% snippet 'tour/tour_step.html', step={} %}
{% endfor %}
</div>

<div class="form-actions js-form-wrapper form-wrapper">
<button
class="add-step btn btn-success"
hx-trigger="click"
hx-post="{{ h.url_for('tour.add_step') }}"
hx-vals=''
hx-swap="beforeend"
hx-target=".tour-steps__steps"
>
{{ _("Add step") }}
<i class="fa fa-plus"></i>
</button>
</div>
</div>

<div class="form-actions js-form-wrapper form-wrapper">
<button class="btn btn-primary" type="submit">{{ _("Create tour") }}</button>
</div>
</form>
{% endblock ap_content %}

{% block scripts %}
{{ super() }}

{% asset 'tour/tour-htmx' %}
{% endblock %}
59 changes: 59 additions & 0 deletions ckanext/tour/templates/tour/tour_image_upload.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{% from 'macros/form/input.html' import input %}
{% from 'macros/form/checkbox.html' import checkbox %}

{#
Builds a file upload for input

Example
{% import 'macros/form.html' as form %}
{{ form.image_upload(data, errors, is_upload_enabled=true) }}

#}
{% macro image_upload(data, errors, field_url='image_url', field_upload='image_upload', field_clear='clear_upload',
is_url=false, is_upload=false, is_upload_enabled=false, placeholder=false,
url_label='', upload_label='', field_name='image_url') %}
{% set placeholder = placeholder if placeholder else _('http://example.com/my-image.jpg') %}
{% set url_label = url_label or _('Image URL') %}
{% set upload_label = upload_label or _('Image') %}
{% set previous_upload = data['previous_upload'] %}

{% if field_url == 'url' and field_upload == 'upload' %}
{# backwards compatibility for old resource forms that still call the `forms.image_upload()` macro, eg ckanext-scheming #}
{% snippet 'package/snippets/resource_upload_field.html',
data=data,
errors=errors,
is_url=is_url,
is_upload=is_upload,
is_upload_enabled=is_upload_enabled,
url_label=url_label,
upload_label=upload_label,
placeholder=placeholder %}
{% else %}
{% if is_upload_enabled %}
<div class="image-upload"
data-module="image-upload"
data-module-is_url="{{ 'true' if is_url else 'false' }}"
data-module-is_upload="{{ 'true' if is_upload else 'false' }}"
data-module-field_url="{{ field_url }}"
data-module-field_upload="{{ field_upload }}"
data-module-field_clear="{{ field_clear }}"
data-module-upload_label="{{ upload_label }}"
data-module-field_name="{{ field_name }}"
data-module-previous_upload="{{ 'true' if previous_upload else 'false' }}">
{% endif %}


{{ input(field_url, label=url_label, id='field-image-url', type='url', placeholder=placeholder, value=data.get(field_url), error=errors.get(field_url), classes=['control-full']) }}


{% if is_upload_enabled %}
{{ input(field_upload, label=upload_label, id='field-image-upload', type='file', placeholder='', value='', error='', classes=['control-full']) }}
{% if is_upload %}
{{ checkbox(field_clear, label=_('Clear Upload'), id='field-clear-upload', value='true', error='', classes=['control-full']) }}
{% endif %}
{% endif %}

{% if is_upload_enabled %}</div>{% endif %}
{% endif %}

{% endmacro %}
Loading

0 comments on commit a9942b1

Please sign in to comment.