Skip to content

Commit

Permalink
Merge pull request #1800 from lift/migration-script
Browse files Browse the repository at this point in the history
Migration script/docs

Few things here:

 - Quick migration script that highlights things that
   aren't marked as deprecated in Lift 2.6 but behave
   significantly differently in Lift 3.0, as well as giving
   some instructions on how to port.
 - Fix up CSS selector transform docs, since they are
   relevant to the above migration (from bind to CSS
   selector transforms, specifically).
 - Add a quick LiftScreen migration doc for 2.6 to 3.0.
  • Loading branch information
Shadowfiend committed Jun 17, 2016
2 parents 4b0c2d2 + 3faec80 commit be37ed5
Show file tree
Hide file tree
Showing 3 changed files with 238 additions and 30 deletions.
63 changes: 33 additions & 30 deletions docs/css-selectors.adoc
Expand Up @@ -24,13 +24,14 @@ transforms it according to a set of rules, producing a final `NodeSeq` with all
of the transformations applied. This means a CSS Selector Transform is
ultimately simply a function with signature `(NodeSeq)=>NodeSeq`. CSS Selector
Transforms consist of three main components:

- The selector
- The subnode modification rule
- The transformation function

///
Nice to have: graphic that shows a selector transform pointing to each
///
////////////////////////////////////////////////////////////////////////////
// Nice to have: graphic that shows a selector transform pointing to each //
////////////////////////////////////////////////////////////////////////////

The details of each are provided below, but first let's look at some simple
examples of transforms that you can write with links. For all of these examples,
Expand Down Expand Up @@ -154,6 +155,7 @@ Benedict Cumberbatch
====

These examples show a few options:

- You can select by element name or by class name. More available selectors are
in the section below on <<available-selectors>>.
- You can set the body of an element, an attribute of an element, or even
Expand Down Expand Up @@ -184,8 +186,8 @@ Name selector: `@field-name`::
`<input name="username">`.

Element selector: `element-name`::
The element selector matches any element of type `element-name`. For example,
you can use `input` to match an element `<input type="text">`.
The element selector matches any element with node name `element-name`. For
example, you can use `input` to match an element `<input type="text">`.

Attribute selector: `an-attribute=a-value`::
The attribute selector matches any element whose attribute named
Expand All @@ -196,7 +198,7 @@ Universal selector: `*`::
The universal selector matches any element.

Root selector: `^`::
The root selector matches elements at the root level of the NodeSeq being
The root selector matches elements at the root level of the `NodeSeq` being
transformed. For example, you can use `^` to match both the `header`
and `ul` elements in the HTML `<header id="page-header">...</header><ul
ng-model="user">...</ul>`.
Expand All @@ -206,8 +208,8 @@ Root selector: `^`::
In addition to the above base selectors, a few selectors are provided that are
useful shortcuts for special attributes:

Data name attribute selector: `;name-data`::
The data name attribute selector matches any element that has `name-data` as
Data name attribute selector: `;custom-name`::
The data name attribute selector matches any element that has `custom-name` as
the value of its `data-name` attribute. For example, you can use `;user-info`
to match an element `<ul data-name="user-info">...</ul>`.

Expand All @@ -229,7 +231,7 @@ Set children rule: `*`::
example, `^ *` will set the children of all root elements to the results of
the transformation.

Append to children rule: `*<` or `*+`::
Append to children rule: `\*<` or `*+`::
The transformation result will be appended to the children of the matched
element(s). For example, `^ *+` will append the results of the transformation
to the end of the content of all root elements.
Expand Down Expand Up @@ -348,12 +350,12 @@ box by Lift:
fact, there is a `ClearNodes` function defined in `net.liftweb.util` that does
exactly this.]. Because CSS Selector Transforms are themselves
`NodeSeq=>NodeSeq` functions, you can nest them this way. For example, you
can say `".user" #> { ".name *" #> user.name }`. With the markup
`<li class="user"><p class="name">Person</p></li>`, this will first select
the `li`, then pass it to the second transform which will select the `p`
and set its value to the user's name. Then the second transform will return
the `li` with the user's name set up, and the top-level transform will replace
the original, unbound `li` with the new one.
can say `".user" #> { ".name *" #> user.name }`. Given the markup `<li
class="user"><p class="name">Person</p></li>`, this will first select the
`li`, then pass it to the second transform which will select the `p` and set
its value to the user's name. Then the second transform will return the `li`
with the user's name set up, and the top-level transform will replace the
original, unbound `li` with the new one.

`CanBind[Iterable[T]]`::
This is defined for most `T` values that `CanBind` is also defined for, and
Expand All @@ -377,10 +379,11 @@ Lift's selectors are not identical to CSS selectors. They're designed for speed
rather than for being featureful, and designed in the context of a full-featured
language rather than a limited language like CSS. One key difference is in how
you combine them. In CSS, you can use `>` to select direct children, `+` for
direct siblings, etc. Lift only provides one combinator, the space: ` `. It
works just like in CSS, applying to all descendants. So you can set up a selector
`.user-form input [value]` and it will for setting the `href` attribute of all
`input` elements that have some ancestorwith class `user-form` .
direct siblings, etc. Lift only provides one combinator, the space. It works
just like in CSS, checking all descendants of the elements matched by the
select to the left against the selector on the right. So you can set up a
selector `.user-form input [value]` and it will set the `href` attribute of all
`input` elements that have some ancestor with class `user-form`.

Notably, you cannot select `form.user input [href]`, because you cannot check
multiple selectors on a single element. In practice, this is rarely needed for
Expand Down Expand Up @@ -425,19 +428,19 @@ should be applied and then applying them. So, you can do:
```

Beware, however, as `&` is not the same as `andThen`. To do this trickery, Lift
will only transform a part of a node once, and it won't revisit it. Two
transformations that apply to the same attribute for the same element, for
example, will not both be applied. Additionally, if your transformation applies
to the body of an element, like `a *`, the new children of the element will
_not_ be transformed. Additionally, if you replace the element itself, e.g.
with the selector `a`, none of the other transforms for that element will run.
will only transform a part of a node once, and it won't revisit it. Specifically,
two transformations that apply directly to the same element (not its descendants
or attributes). Additionally, if your transformation applies to the body of an
element, like `a *`, the new children of the element will _not_ be transformed.
Additionally, if you replace the element itself, e.g. with the selector `a`,
none of the other transforms for that element will run.

Thus, you will occasionally find yourself using `&` together with `andThen`; in
general you should default to `&` and switch to `andThen` when you need to in
order to apply a transform to the results of the previous one.

== Macros and Strings

Lift's CSS Selector Transforms can be used in two modes. Most basically, you
can create a `String` with the appropriate selector and then specify the
transformation you want to apply to matching blocks
//== Macros and Strings
//
//Lift's CSS Selector Transforms can be used in two modes. Most basically, you
//can create a `String` with the appropriate selector and then specify the
//transformation you want to apply to matching blocks
167 changes: 167 additions & 0 deletions docs/migration/2.6-to-3.0-lift-screen.adoc
@@ -0,0 +1,167 @@
:idprefix:
:idseparator: -
:toc: right
:toclevels: 2

= Migrating `LiftScreen` from Lift 2.6 to Lift 3.0

The 2.x series of Lift brought a lot of change and innovation. In particular,
while it started with an approach based on the `bind` helper that transformed
namespaced XHTML elements into the values that the developer wanted to display,
it progressed to an HTML5-based approach built around CSS selector transforms.
As of Lift 3.0, CSS selector transforms are the only supported transforms, so
as to keep the core of the framework relatively lean and encourage proper HTML
usage.

One of the Lift components that leveraged the `bind`-style transforms heavily
was `LiftScreen`. As of Lift 3.0, it's been replaced with what in Lift 2.6 was
named `CssBoundLiftScreen`, which is a version of `LiftScreen` that uses CSS
selector transforms instead of `bind`-style transforms. Following is a
breakdown of the things you need to do if you were using `LiftScreen` and want
to upgrade to Lift 3.0.

== `formName`

In Lift 3.0, you need to provide a `formName` to your screen. For the most
straightforward compatibility with the current form implementation, you should
be able to simply set it to "":

[.lift-30]
```scala
val formName = ""
```

// Something more about what formName is for would be good here.

== Bind Points

In the old `LiftScreen`, bind points were elements with the namespace `prefix`
and various names, e.g. `wizard:fields` for the container of all fields. Lift
3.0 instead looks for certain CSS classes in elements. Here's a mapping from
old `wizard:*` elements to CSS classes:

.Lift 2.6 wizard element to Lift 3.0 CSS class mapping
|=========================
| Lift 2.6 Element | Lift 3.0 CSS Class

| `wizard:screen_info` | `screenInfo`

| `wizard:screen_number` | `screenNumber`

| `wizard:total_screens` | `totalScreens`

| `wizard:wizard_top` | `wizardTop`

| `wizard:screen_top` | `screenTop`

| `wizard:errors` | `globalErrors`

| `wizard:item` (within `errors`) | `error`

| `wizard:fields` | `fields`

| `wizard:line` | `fieldContainer`

| `wizard:label` | `label`

| `wizard:for` | unneeded (label is automatically given a `for` attribute)

| `wizard:help` | `help`

| `wizard:field_errors` | `errors`

| `wizard:error` | `error`

| `wizard:form` | `value`

| `wizard:prev` | `prev`

| `wizard:cancel` | `cancel`

| `wizard:next` | `next`

| `wizard:wizard_bottom` | `wizardBottom`

| `wizard:screen_bottom` | `screenBottom`

| `wizard:bind` | unnecessary (contents are put into the elements with appropriate classes)
|=========================

Generally speaking, you can annotate the container element or the element that
will have a given value directly with the class of the content it should
contain, rather than needing an extra container with the class like the old
`wizard:*` elements. For example, where before you had:

[.lift-26]
.Lift 2.6 global error markup
```html
<wizard:errors>
<div>
<ul>
<wizard:item>
<li><wizard:bind></wizard:bind></li>
</wizard:item>
</ul>
</div>
</wizard:errors>
```

In Lift 3.0, you can remove all the `wizard:*` elements and instead put the
classes directly on the remaining elements:

[.lift-30]
.Lift 3.0 global error markup
```html
<div class="globalErrors">
<ul>
<li class="error">
placeholder text, will be replaced by the error message
</li>
</ul>
</div>
```

In fact, you can even eliminate the top-level `div`, if you'd like, by putting
the `globalErrors` class on the `ul`:

[.lift-30]
```html
<ul class="globalErrors">
<li class="error">
placeholder text, will be replaced by the error message
</li>
</ul>
```

If you don't like these class names, you can customize them by overriding the
`cssClassBinding` that you want to use in your `LiftScreen` subclass and
returning a new instance of `CssClassBinding` with the appropriate CSS classes
set up:

[.lift-30]
.Dasherize class names
```scala
protected override lazy val cssClassBinding = new CssClassBinding {
override val screenInfo = "screen-info"
override val screenNumber = "screen-number"
override val totalScreens = "total-screens"

override val wizardTop = "wizard-top"
override val screenTop = "screen-top"
override val wizardBottom = "wizard-bottom"
override val screenBottom = "screen-bottom"

override val globalErrors = "global-errors"
override val fieldContainer = "field-container"

}
```

Above, we create a new version of `CssClassBinding` that uses dashes instead of
camel-case between words.

== Further Help

That's it! If you run into any issues porting your screen over to Lift 3.0's
`LiftScreen`, please ask on the Lift mailing list and you should find willing
helpers.
38 changes: 38 additions & 0 deletions scripts/check-2.6-to-3.0-migration.sh
@@ -0,0 +1,38 @@
#!/bin/bash
LIFT_SCREEN_TEMPLATE=`find ./ -name "wizard-all.html"`
LIFT_SCREEN_EXTENDS=`grep -E "extends +LiftScreen"`
LIFT_SCREEN_WITH=`grep -E "with +LiftScreen"`

if [[ -n "$LIFT_SCREEN_TEMPLATE" ]]; then
echo "You're likely using an outdated base LiftScreen template at:"
echo "$LIFT_SCREEN_TEMPLATE"
echo "Assuming you haven't changed it, you can replace it with the lift_basic version for"
echo "exactly the same result:"
echo "https://github.com/lift/lift_30_sbt/blob/master/lift_basic/src/main/webapp/templates-hidden/wizard-all.html"
echo "----------------------------------------------------------------------------------"
fi

if [[ -n $LIFT_SCREEN_EXTENDS ]] || [[ -n $LIFT_SCREEN_WITH ]]; then
echo "You're extending LiftScreen. LiftScreen as of Lift 3.0 is the equivalent of 2.6's"
echo "CssBoundLiftScreen. This means it binds using CSS selector transforms instead of"
echo "the Lift 2.x series's \`bind\` function, which no longer exists. See this document"
echo "for porting instructions:"
echo "https://github.com/lift/framework/docs/migration/2.6-to-3.0-lift-screen.adoc"
echo "Here are the uses of LiftScreen we found:"
[[ -n $LIFT_SCREEN_EXTENDS ]] && echo "$LIFT_SCREEN_EXTENDS"
[[ -n $LIFT_SCREEN_WITH ]] && echo "$LIFT_SCREEN_WITH"
echo "----------------------------------------------------------------------------------"
fi

BIND_USES=`grep -E "bind\("`

if [[ -n $BIND_USES ]]; then
echo "You seem to be using Lift's bind helpers. These have been removed from Lift 3.0,"
echo "superseded by Lift's CSS selector transforms. You can port your application to CSS"
echo "selector transforms piecewise while still on Lift 2.6, as they are supported in"
echo "both versions. For a primer on CSS selector transforms, look at this document:"
echo "https://github.com/lift/framework/blob/master/docs/css-selectors.adoc"
echo ""
echo "If you find yourself with additional questions, please ask on the Lift mailing list"
echo "and you should find willing helpers."
fi

0 comments on commit be37ed5

Please sign in to comment.