gwtproject / gwt

GWT Open Source Project
http://www.gwtproject.org
1.53k stars 378 forks source link

PATCH - allow element IDs to be specified without the 'gwt-debug-' prefix #4180

Closed dankurka closed 9 years ago

dankurka commented 9 years ago

Originally reported on Google Code with ID 4179

Found in GWT Release (e.g. 1.5.3, 1.6 RC): 2.0-m2

Encountered on OS / Browser (e.g. WinXP, IE6-7, FF3): OS X

Detailed description (please be as specific as possible):

It would be good if GWT shipped with an implementation of UIObject.DebugIdImpl which
allowed IDs to be specified on Elements either via the 
ensureDebugId() method call - or via the UiBinder's debugId attribute in the XML -
without the "gwt-debug-" prefix, as having IDs in the generated 
DOM is very useful for testing via selenium etc.

For background see issue 4176.

So we should add a class like this to UIObject

{{{
  /**
   * The implementation of the setDebugId method, which sets the id of the
   * {@link Element}s in this {@link UIObject} without the 'gwt-debug-' prefix.
   */
  @SuppressWarnings("unused")
  public static class DebugIdImplEnabledNoPrefix extends DebugIdImpl {

    @Override
    public void ensureDebugId(UIObject uiObject, String id) {
        uiObject.onEnsureDebugId(id);
    }

    @Override
    public void ensureDebugId(Element elem, String baseID, String id) {
        assert baseID != null;
        baseID = (baseID.length() > 0) ? baseID + "-" : "";
        DOM.setElementProperty(elem.<com.google.gwt.user.client.Element> cast(),
                "id", baseID + id);
    }
}
}}}

Then to enable setting prefix-less IDs on elements a user would have to put this in
their gwt.xml file...

{{{
  <replace-with class="com.google.gwt.user.client.ui.UIObject.DebugIdImplEnabledNoPrefix">
    <when-type-is class="com.google.gwt.user.client.ui.UIObject.DebugIdImpl"/>
  </replace-with>
}}}

Shortest code snippet which demonstrates issue (please indicate where
actual result differs from expected result):

Workaround if you have one:

Links to relevant GWT Developer Forum posts:

Reported by james.strachan on 2009-10-29 09:59:30

dankurka commented 9 years ago
Then in UiBuilder code folks could set the IDs on some widgets via

{{{
  <g:Button ui:field="myFieldName" debugId="myElementID" text="Click Me!" />
}}}

Or in Java code

{{{
  button.ensureDebugId("myElementID");
}}}

and in the generated DOM the elements ID would really be "myElementID" - not "gwt-debug-myElementID"

Reported by james.strachan on 2009-10-29 10:04:08

dankurka commented 9 years ago
Nice James, thanks for the hint.
You only have to be careful using it in the gwt.xml file, such that it's not always
enabled as you might want to disable it.
You could do this by copying the part from the Debug.xml file:

  <replace-with
class="com.google.gwt.user.client.ui.UIObject.DebugIdImplEnabledNoPrefix">
    <when-type-is class="com.google.gwt.user.client.ui.UIObject.DebugIdImpl"/>
    <when-property-is name="gwt.enableDebugId" value="true"/>
  </replace-with>

Reported by post2edbras on 2009-12-03 17:38:05

dankurka commented 9 years ago

Reported by spoon@google.com on 2009-12-15 20:57:03

dankurka commented 9 years ago
Believe John L was talking about making this kind of customization easier.

Reported by rjrjr@google.com on 2009-12-15 21:39:07

dankurka commented 9 years ago
I would like to see a plain  

element.ensureId("myElementID");

which did not require or rely upon any configuration in gwt.xml 

It is not just during debugging that third party apps might require ids, 
mashups and CI of deployed apps for example. 

Reported by Tim.Pizey on 2010-02-22 18:33:49

dankurka commented 9 years ago
I have a different, but common use case:

For various forms, I'd like the resulted HTML to have <label for=elementId> tag.
According to this 
http://canoo.com/blog/2010/04/26/gwt-uibinder-better-web-app-separation-of-concerns/
it's not possible now, and one has to add markup into the java code instead of .ui.xml
file.

Will UiBinder be enhanced to support this use case ?

Reported by marius.andreiana on 2010-08-27 06:59:20

dankurka commented 9 years ago
See https://wave.google.com/wave/waveref/googlewave.com/w+EI8yh67GA
FYI, the attempt at "eradicating the use of IDs in UiBinder" has failed due to specific
HTML parsing rules (e.g. <table><tr>... will actually be parsed into the following
DOM tree: table->tbody->tr, and this is just one example; this makes the proposed approach
very fragile compared to using IDs).
That being said, I wonder whether the proposed "<label for='{textField}'>Booyah:</label>
<input ui:field='textField' type='text'/>" couldn't be made to work even with UiBinder
using IDs (instead of generating an ID specifically for this case, it would just have
to keep the ID it already generated for the ui:field, instead of removing it as it
does today unconditionally).

In the mean time, I'm successfully using the "What can be done now?" approach in a
project (using an interface and a generator), or when possible just using the following
construct instead:
  <label>Booyah: <input ui:field='textField' type='text'/></label>

Reported by t.broyer on 2010-08-27 08:44:42

dankurka commented 9 years ago
Thanks Thomas.

Here's another use case: have external .css files, which style elements based on id.
And I'm sure there might be more (e.g. gwt combined with jquery, and jquery accessing
elements based on ids). 

Reported by marius.andreiana on 2010-09-27 20:52:28

dankurka commented 9 years ago

Reported by rjrjr@google.com on 2011-01-13 03:10:18

dankurka commented 9 years ago
as I understand, the ensureDebugId() API ensures that given ID of an element is not
generated but set to a certain value, however, this only applies in a "debug" mode,
when inheriting the Debug GWT module, so its conditional. This in mind, one should
not worry about the debug prefix, instead its very useful because the developer or
tester knows that this id is considered for debugging purposes only.

On the other hand, if one wants to assign a real id to the element to reference to
it later in the code, he never should use a debug ID, rather assign it via DOM directly
(UiObject.getElement().setId()) or GWT could provide additional setId() method, which
will always set an ID (regardless of the GWT Debug ID module) AND resolve conflicts,
in case both IDs were set (a real ID has precedence over debug ID).

Actually, its not a good idea to use #IDs for styling (CSS), there is no real usecase
in GWT environment to use IDs on elements. html:label (and maybe some more html tags)
is unfortunately the exception, but Thomas provided a solution for it

Reported by eplischke on 2011-01-19 08:06:09

dankurka commented 9 years ago
A combination with issue 6976 would be nice:
http://code.google.com/p/google-web-toolkit/issues/detail?id=6977

Reported by post2edbras on 2011-11-10 12:42:57

dankurka commented 9 years ago
Sent for review:
http://gwt-code-reviews.appspot.com/1618804

Instead of a new implementation that requires a deferred bind, I added static methods
to change the prefix and attribute.  This is easier to use because it doesn't require
a gwt.xml rule, and its more flexible because it allows you to change the prefix temporarily
or to an arbitrary value.  It also allows you to specify an attribute other than the
element ID, which is useful.

To use this, you call DebugInfo#setDebugIdPrefix("") at the top of your onModuleLoad()
method.

Reported by jlabanca@google.com on 2011-12-16 17:42:15

dankurka commented 9 years ago
You can now use DebugInfo#setDebugIdPrefix() to change the prefix and DebugInfo#setDebugIdAttribute()
to change the attribute that is set.

Example:
DebugInfo#setDebugIdPrefix(""); // Clears the prefix
DebugInfo#setDebugIdAttribute("debugId", false); // Set the "debugId" as an attribute

Reported by jlabanca@google.com on 2011-12-21 18:18:31

dankurka commented 9 years ago

Reported by stephen.haberman on 2011-12-22 03:29:15

dankurka commented 9 years ago
Bulk edit: should be fixed in the GWT 2.5 release candidate.

Reported by skybrian@google.com on 2012-06-27 03:38:11