Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve documentation #1124

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/developer/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Developer documentation

- [Patternslib overview](overview.md)
- [The structure of a pattern](patterns.md)
- [Configuring a pattern](patterns-configuration.md)
- [Styleguide](styleguide.md)
196 changes: 42 additions & 154 deletions docs/developer/patterns.rst
Original file line number Diff line number Diff line change
@@ -1,138 +1,66 @@
Creating a new pattern
======================
The structure of a pattern
==========================

Patterns are implemented as javascript objects that are registered with the
patterns library. Below is a minimal skeleton for a pattern.
Patterns are implemented as JavaScript classes that are registered with the patterns registry.
Below is a minimalistic skeleton for a pattern with explanations as inline comments.

.. code-block:: javascript
:linenos:

define([
'require'
'../registry'
], function(require, registry) {
var pattern_spec = {
name: "mypattern",
};

registry.register(pattern_spec);
});

This skeleton does several things:

* lines 1-4 use `RequireJS <http://requirejs.org/>`_ to load the patterns
registry.
* lines 5-7 create an object which defines this pattern's specifications.
* line 9 registers the pattern.


Markup patterns
---------------

Most patterns deal with markup: they are activated for content that matches
a specific CSS selector. This is handled by adding two items to the
pattern specification: a ``trigger`` and an ``init`` function.

.. code-block:: javascript
:linenos:

var pattern_spec = {
name: "mypattern",
trigger: ".tooltip, [data-tooltip]",

init: function($el) {
...
},

destroy: function($el) {
...
}
};

The trigger specified on line 3 is a CSS selector which tells the pattern
framework which elements this pattern is interested in. If new items are
discovered in the DOM that match this pattern, the ``init`` function will be
called with a jQuery wrapper around the element.

While not required patterns are encouraged to include a ``destroy`` function
that undos the pattern initialisation. After calling ``destroy`` it should be
possible to call ``init`` again to reactivate the pattern.

Methods must always return ``this`` to facilitate their use as jQuery widgets.

jQuery plugins
--------------

Patterns can also act as jQuery plugins. This can be done by providing a
``jquery_plugin`` option in the pattern specification.

.. code-block:: javascript
:linenos:
:emphasize-lines: 3

var pattern_spec = {
name: "mypattern",
jquery_plugin: true,

init: function($el) {
...
},

destroy: function($el) {
...
},

othermethod: function($el, options) {
...
}
};
import { BasePattern } from "@patternslib/patternslib/src/core/basepattern";
import Parser from "@patternslib/patternslib/src/core/parser";
import registry from "@patternslib/patternslib/src/core/registry";

export const parser = new Parser("test-pattern");
// Define an argument with a default value. You can configure the value via
// data-attributes.
parser.addArgument("example-option", "Hollareidulio");

Line 3 tells the patterns framework that this pattern can be used as a jQuery
plugin named ``patMypattern``. You can then interact with it using the
standard jQuery API:

.. code-block:: javascript

// Initialize mypattern for #title
$("#title").patMypattern();

// Invoke othermethod for the pattern
$("#title").patMypattern("othermethod", {option: "value"});
class Pattern extends BasePattern {

// Define a name for the pattern which is used as key in the pattern
// registry.
static name = "test-pattern";

// Define a CSS selector. The pattern will be initialized on elements
// matching this selector.
static trigger = ".pat-test-pattern";

Injection actions
-----------------
// The parser instance from above.
static parser = parser;

The injection mechanism supports invoking arbitrary actions after loading new
content. This is handled through *injection actions*. These are handled by an
``inject`` method on a pattern.
init() {
import("./test-pattern.scss");

.. code-block:: javascript
:linenos:
:emphasize-lines: 3
// Try to avoid jQuery, but here is how to import it, asynchronously.
// eslint-disable-next-line no-unused-vars
const $ = (await import("jquery")).default;

var pattern_spec = {
name: "mypattern",
// The options are automatically created, if parser is defined.
const example_option = this.options.exampleOption;
this.el.innerHTML = `
<p>${example_option}, this is the ${this.name} pattern!</p>
`;
}
}

inject: function($trigger, content) {
...
}
};
// Register Pattern class in the global pattern registry and make it usable there.
registry.register(Pattern);

The inject methods gets a number of parameters:

* ``$trigger`` is the element that triggered the injection.
* ``content`` is an array containing the loaded content.
// Export Pattern as default export.
// You can import it as ``import AnyName from "./{{{ pattern.name }}}";``
export default Pattern;
// Export BasePattern as named export.
// You can import it as ``import { Pattern } from "./{{{ pattern.name }}}";``
export { Pattern };



Pattern configuration
---------------------

The configuration of a pattern is generally based on three components: the
default settings, configuration set on a DOM element via a data-attribute, and,
if the jQuery API is used, via options passed in via the jQuery plugin API.
default settings, configuration set on a DOM element via a data-attribute.
The init method for patterns should combine these settings. Let's update our
example pattern to do this:

Expand Down Expand Up @@ -163,43 +91,3 @@ parser instance and add our options with their default values. In the init
method we use the parser to parse the ``data-mypattern`` attribute for the
element. Finally we combine that with the options that might have been
provided through the jQuery plugin API.

Creating a JavaScript API
-------------------------

Sometimes you may want to create a JavaScript API that is not tied to DOM
elements, so exposing it as a jQuery plugin does not make sense. This can
be done using the standard RequireJS mechanism by creating and returning an
API object.

.. code-block:: javascript
:linenos:
:emphasize-lines: 13-17

define([
'require',
'../registry'
], function(require, registry) {
var pattern_spec = {
init: function($el) {
...
};
};

registry.register(pattern_spec);

var public_api = {
method1: function() { .... },
method2: function() { .... }
};
return public_api;
});


You can then use the API by using require to retrieve the API object for
the pattern:

.. code-block:: javascript

var pattern_api = require("patterns/mypattern");
pattern_api.method1();
12 changes: 8 additions & 4 deletions src/core/basepattern.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Also see: https://github.com/Patternslib/pat-PATTERN_TEMPLATE
import registry from "@patternslib/patternslib/src/core/registry";

export const parser = new Parser("test-pattern");
parser.addArgument("example-option", "Stranger");
parser.addArgument("example-option", "Hollareidulio");

class Pattern extends BasePattern {
static name = "test-pattern";
Expand All @@ -33,14 +33,18 @@ Also see: https://github.com/Patternslib/pat-PATTERN_TEMPLATE
// The options are automatically created, if parser is defined.
const example_option = this.options.exampleOption;
this.el.innerHTML = `
<p>hello, ${example_option}, this is pattern ${this.name} speaking.</p>
<p>${example_option}, this is the ${this.name} pattern!</p>
`;
}
}

// Register Pattern class in the global pattern registry
// Register Pattern class in the global pattern registry and make it usable there.
registry.register(Pattern);

// Make it available
// Export Pattern as default export.
// You can import it as ``import AnyName from "./{{{ pattern.name }}}";``
export default Pattern;
// Export BasePattern as named export.
// You can import it as ``import { Pattern } from "./{{{ pattern.name }}}";``
export { Pattern };