Home > Articles > Home & Office Computing > eBay/Yahoo/Google

This chapter is from the book

Drag and Drop Implementation in a GWT Module

Now that we have a good grasp of how to use the dnd module, let's look at how it's implemented.

The drag-and-drop module is implemented inside, our Components module. Figure 6.5 shows the drag and drop's pertinent files and directories.

Figure 6.5

Figure 6.5 Drag-and-drop module's files and directories

Like all GWT modules, our drag-and-drop module has an XML configuration file. Like most modules, our drag-and-drop module also has some Java classes and interfaces.

The Module Configuration File

Every GWT module must provide a configuration file. The dnd module's configuration file is listed in Listing 6.10.

Listing 6.10. com/gwtsolutions/dnd/Dnd.gwt.xml

1.<module>
2.   <inherits name='com.google.gwt.core.Core'/>
3.</module>

It doesn't get any simpler than that. All we need for our dnd module is the core GWT classes, so that's what we inherit.

Now let's look at the Java classes in the dnd module.

The Abstract Drag Source and Drop Target Classes

The DragSource class is listed in Listing 6.11.

Listing 6.11. com.gwtsolutions.components.client.ui.dnd.DragSource

1.package com.gwtsolutions.components.client.ui.dnd;
2.
3.import com.google.gwt.user.client.ui.AbsolutePanel;
4.import com.google.gwt.user.client.ui.MouseListener;
5.import com.google.gwt.user.client.ui.Widget;
6.import com.gwtsolutions.components.client.ui.MousePanel;
7.import com.gwtsolutions.components.client.ui.Point;
8.
9.public abstract class DragSource extends MousePanel {
10.  private static final String BAD_PARENT =
11.      "Drag sources must have a parent of type AbsolutePanel";
12.  private static final MouseListener defaultDragger =
13.      new FollowsMouseDragger();
14.
15.  private boolean dragging = false;
16.  private Point originalLocation = null;
17.  private DropTarget enclosingDropTarget = null;
18.
19.  public DragSource(Widget w) {
20.    // Drag sources contain only one widget, which is
21.    // the widget passed to this constructor
22.    add(w);
23.
24.    // Listener order is significant. See the text
25.    // of GWT Solutions for more information
26.    addMouseListener(new DragSourceListener());
27.    addMouseListener(getMouseListener());
28.  }
29.
30.  public void onLoad() {
31.    // GWT calls this method when the drag source's
32.    // DOM element is added to the browser's DOM tree.
33.    if ( ! (getParent() instanceof AbsolutePanel))
34.      throw new IllegalStateException(BAD_PARENT);
35.  }
36.
37.  public void dragStarted() {
38.    // subclasses can override this no-op method
39.    // as needed
40.  }
41.
42.  public void droppedOutsideDropTarget() {
43.    // By default, when a drag source is dropped outside
44.    // of any drop target, it is returned to its original
45.    // position. Subclasses can override this method to
46.    // change or augment that behavior
47.    returnToOriginalPosition();
48.  }
49.
50.  public void acceptedByDropTarget(DropTarget dt) {
51.    // subclasses can override this no-op method
52.    // as needed
53.  }
54.
55.  public void rejectedByDropTarget(DropTarget dt) {
56.    // By default, when a drag source is rejected by
57.    // a drop target, it is returned to its original
58.    // position. Subclasses can override this method to
59.    // change or augment that behavior
60.    returnToOriginalPosition();
61.  }
62.
63.  public boolean isDragging() {
64.    return dragging;
65.  }
66.
67.  public void setDragging(boolean dragging) {
68.    this.dragging = dragging;
69.  }
70.
71.  public void setOriginalLocation(Point originalLocation) {
72.    this.originalLocation = originalLocation;
73.  }
74.
75.  public DropTarget getEnclosingDropTarget() {
76.    return enclosingDropTarget;
77.  }
78.
79.  public void setEnclosingDropTarget(
80.      DropTarget enclosingDropTarget) {
81.    this.enclosingDropTarget = enclosingDropTarget;
82.  }
83.
84.  protected void returnToOriginalPosition() {
85.    AbsolutePanel ap = (AbsolutePanel) getParent();
86.    ap.setWidgetPosition(this, originalLocation.x,
87.        originalLocation.y);
88.  }
89.
90.  protected MouseListener getMouseListener() {
91.    return defaultDragger;
92.  }
93.}

This simple extension of the MousePanel we discussed in "The Viewport's Use of a Focus Panel: Revisited" (page 115) defines three properties and implements four methods that subclasses are likely to use: dragStarted(), droppedOutsideDropTarget(), acceptedByDropTarget(), and rejectedByDropTarget().

The properties keep track of whether the mouse panel is currently being dragged, its position before the drag began, and the enclosing drop target, if any. The methods are typically overridden by subclasses, as is the case for the MusicPlayerPanelDropTarget, listed in Listing 6.6 on page 178.

You may wonder why DragSource extends MousePanel. Here's why: Not all GWT widgets support mouse listeners; in fact, most do not, and we want to be able to drag any GWT component. So we wrap widgets in a mouse panel, which does support mouse listeners. Unbeknownst to users of the dnd module, they are really dragging mouse panels, which contain a single widget. We used this same technique in The Viewport's Use of a Focus Panel: Revisited" (page 115). See that section for more information about mouse panels and mouse listeners.

The DragSource class adds two mouse listeners to the widget that it wraps. The first listener, an instance of DragSourceListener, which is listed in Listing 6.15 on page 192, monitors the drag and invokes the abstract methods defined by the DragSource and DropTarget classes at the appropriate times.

The second listener, by default, is an instance of FollowsMouseDragger, which is listed in Listing 6.14 on page 191. That implementation of the MouseListener interface drags the drag source wherever the mouse goes. Notice that the mouse listener—an instance of FollowsMouseListener—is pluggable; DragSource subclasses can override getMouseListener() to provide a different dragger.

Oh, one more thing: The order in which we add listeners is significant because that is the order in which GWT will invoke them.2 For the drag-and-drop module to function properly, the drag source listener must be added first because the DragSourceListener's onMouseUp method turns into a no-op if the drag source is not being dragged (we don't want the drag source listener to react to mouse up events if the drag source is not being dragged). Because AbstractMouseDragger.onMouseUp() sets the drag source's dragged property to false, that method must be called after the DragSourceListener.onMouseUp(). If you reverse the order of the addition of the mouse listeners, you will see that the drag-and-drop module never reacts to mouse up events.

The DropTarget class is listed in Listing 6.12.

Listing 6.12. com.gwtsolutions.components.client.ui.dnd.DropTarget

1.package com.gwtsolutions.components.client.ui.dnd;
2.
3.import com.google.gwt.user.client.ui.Widget;
4.import com.gwtsolutions.components.client.ui.MousePanel;
5.
6.public abstract class DropTarget extends MousePanel {
7.  public abstract boolean acceptsDragSource(DragSource ds);
8.
9.  public DropTarget(Widget w) {
10.    // This panel conatians only one widget, which is the
11.    // widget passed to this constructor
12.    add(w);
13.  }
14.
15.  public void dragSourceEntered(DragSource ds) {
16.    // subclasses can override this no-op method
17.    // as needed
18.  }
19.
20.  public void dragSourceExited(DragSource ds) {
21.    // subclasses can override this no-op method
22.    // as needed
23.  }
24.
25.  public void dragSourceDropped(DragSource ds) {
26.    // If the drag source dropped on this drop target
27.    // is acceptable, notify the drag source that it's been
28.    // dropped on this drop target; otherwise, notify the
29.    // drag source that it was rejected by this drop target
30.    if (acceptsDragSource(ds))
31.      ds.acceptedByDropTarget(this);
32.    else
33.      ds.rejectedByDropTarget(this);
34.  }
35.}

This is another extension of MousePanel because we want any GWT widget to be able to function as a drop target. This class provides no-op defaults for two of the three methods that subclasses are likely to override: dragSourceEntered() and dragSourceExited().

For dragSourceDropped(), if the drag source is acceptable to the drop target—indicated by the return value of acceptsDragSource(), which is an abstract method subclasses must implement—we tell the drag source that it was accepted by the drop target; otherwise, we notify the drag source that, sadly enough, it was rejected by the drop target.

Mouse Listeners

The final pieces of the dnd puzzle are the mouse listeners, where most of the complexity lies. Listing 6.13 lists the AbstractMouseDragger class, which blithely drags widgets around on an absolute panel.

Listing 6.13. com.gwtsolutions.components.client.ui.dnd.AbstractMouseDragger

1.package com.gwtsolutions.components.client.ui.dnd;
2.
3.import com.google.gwt.user.client.DOM;
4.import com.google.gwt.user.client.ui.AbsolutePanel;
5.import com.google.gwt.user.client.ui.MouseListenerAdapter;
6.
7.public abstract class AbstractMouseDragger extends
8.    MouseListenerAdapter {
9.  private int xoffset, yoffset;
10.
11.  // Subclasses implement this method to override the
12.  // proposed left edge of the dragSource after a drag
13.  protected abstract int getNextLeft(int proposedLeft,
14.      DragSource ds);
15.
16.  // Subclasses implement this method to override the
17.  // proposed top edge of the dragSource after a drag
18.  protected abstract int getNextTop(int proposedTop,
19.      DragSource ds);
20.
21.  public void onMouseDown(DragSource ds, int x, int y) {
22.    xoffset = x;
23.    yoffset = y;
24.
25.    // Enable event capturing, so that subsequent mouse
26.    // events are all sent directly to the ds's
27.    // DOM element
28.    DOM.setCapture(ds.getElement());
29.
30.    // Tell the drag source that dragging has begun
31.    ds.setDragging(true);
32.  }
33.
34.  public void onMouseMove(DragSource ds, int x, int y) {
35.    if (ds.isDragging()) {
36.      // If the drag source is being dragged, calculate
37.      // the proposed left and top, and give subclasses
38.      // a chance to adjust those values
39.      AbsolutePanel ap = (AbsolutePanel) ds.getParent();
40.      int proposedLeft = x + ap.getWidgetLeft(ds) - xoffset;
41.      int proposedRight = y + ap.getWidgetTop(ds) - yoffset;
42.
43.      int nextLeft = getNextLeft(proposedLeft, ds);
44.      int nextRight = getNextTop(proposedRight, ds);
45.
46.      // Set the drag source's position to the next
47.      // left and next right
48.      ap.setWidgetPosition(ds, nextLeft, nextRight);
49.    }
50.  }
51.
52.  public void onMouseUp(DragSource ds, int x, int y) {
53.    // Tell the drag source that dragging is done and
54.    // release the capture of mouse events that was set
55.    // in onMouseDown()
56.    ds.setDragging(false);
57.    DOM.releaseCapture(ds.getElement());
58.  }
59.
60.  protected int checkLeftBounds(int proposedLeft,
61.      DragSource dragSource) {
62.    // Adjust the left edge of the dragSource if it's outside
63.    // the bounds of it's parent panel
64.    AbsolutePanel panel =
65.        (AbsolutePanel) dragSource.getParent();
66.    int dragSourceWidth = dragSource.getOffsetWidth();
67.    int panelWidth = panel.getOffsetWidth();
68.    int nextLeft = proposedLeft;
69.
70.    if (proposedLeft + dragSourceWidth > panelWidth)
71.      nextLeft = panelWidth - dragSourceWidth;
72.
73.    nextLeft = nextLeft < 0 ? 0 : nextLeft;
74.    return nextLeft;
75.  }
76.
77.  protected int checkTopBounds(
78.    // Adjust the top edge of the dragSource if it's outside
79.    // the bounds of it's parent panel
80.    int proposedTop, DragSource dragSource) {
81.    AbsolutePanel panel =
82.        (AbsolutePanel) dragSource.getParent();
83.    int dragSourceHeight = dragSource.getOffsetHeight();
84.    int panelHeight = panel.getOffsetHeight();
85.    int nextRight = proposedTop;
86.
87.    if (proposedTop + dragSourceHeight > panelHeight)
88.      nextRight = panelHeight - dragSourceHeight;
89.
90.    nextRight = nextRight < 0 ? 0 : nextRight;
91.    return nextRight;
92.  }
93.}

This class knows nothing about drag sources or drop targets; all it does is drag widgets. Most of the logic consists of basic math that calculates the next position of a widget and checks boundaries to make sure the widget does not escape its enclosing absolute panel.

The interesting parts of the class are the calls to DOM.setCapture() and DOM.releaseCapture(), in onMouseDown() and onMouseUp(), respectively. DOM.setCapture() captures all mouse events and makes them available only to the widget that it is passed until DOM.releaseCapture() is invoked, returning event handling to normal. That provides a significant boost to performance while a widget is being dragged, which gives us time to make sophisticated calculations, like those in the DragSourceListener class, listed in Listing 6.15.

One other interesting thing about the AbstractMouseDragger class: It's abstract because it defines two abstract methods that can be implemented by subclasses to plug in a different dragging algorithm. Those methods—getNextLeft() and getNextTop()—are passed proposed locations that follow the mouse and return final locations for the current mouse movement. Those methods can be implemented by subclasses for specialized dragging, such as dragging widgets only in the horizontal or vertical directions. One of those subclasses is the FollowsMouseDragger class, listed in Listing 6.14, which follows the mouse but restricts the widget being dragged to the bounds of its enclosing absolute panel by invoking the inherited methods checkLeftBounds() and checkTopBounds().

Listing 6.14. com.gwtsolutions.components.client.ui.dnd.FollowsMouseDragger

1.package com.gwtsolutions.components.client.ui.dnd;
2.
3.// This extension of AbstractMouseDragger drags a drag source
4.// so that it follows the mouse.
5.public class FollowsMouseDragger extends AbstractMouseDragger {
6.  protected int getNextLeft(int proposedLeft,
7.      DragSource dragSource) {
8.    // Adjust left edge if the left edge is outside the
9.    // bounds of the drag source's parent panel
10.    return checkLeftBounds(proposedLeft, dragSource);
11.  }
12.
13.  protected int getNextTop(int proposedTop,
14.      DragSource dragSource) {
15.    // Adjust left edge if the top edge is outside the
16.    // bounds of the drag source's parent panel
17.    return checkTopBounds(proposedTop, dragSource);
18.  }
19.}

The DragSourceListener class, which makes callbacks to drag sources and drop targets as a widget is dragged, is listed in Listing 6.15.

Listing 6.15. com.gwtsolutions.components.client.ui.dnd.DragSourceListener

1. package com.gwtsolutions.components.client.ui.dnd;
2.
3. import com.google.gwt.user.client.DOM;
4. import com.google.gwt.user.client.Event;
5. import com.google.gwt.user.client.EventPreview;
6. import com.google.gwt.user.client.ui.AbsolutePanel;
7. import com.google.gwt.user.client.ui.MouseListenerAdapter;
8. import com.google.gwt.user.client.ui.Widget;
9. import com.google.gwt.user.client.ui.WidgetCollection;
10.import com.gwtsolutions.components.client.ui.Point;
11.
12.import java.util.Iterator;
13.
14.public class DragSourceListener extends MouseListenerAdapter {
15.  private final Point[] dsCorners = new Point[4];
16.  private final WidgetCollection dropTargets =
17.      new WidgetCollection(null);
18.
19.  // The following event preview prevents the browser
20.  // from reacting to mouse drags as the user drags
21.  // drag sources
22.  private static EventPreview preventDefaultMouseEvents =
23.    new EventPreview() {
24.      public boolean onEventPreview(Event event) {
25.        switch (DOM.eventGetType(event)) {
26.          case Event.ONMOUSEDOWN:
27.          case Event.ONMOUSEMOVE:
28.            DOM.eventPreventDefault(event);
29.        }
30.        return true;
31.      }
32.    };
33.
34.  public void onMouseEnter(Widget sender) {
35.    // Prevent the browser from reacting to mouse
36.    // events once the cursor enters the drag source
37.    DOM.addEventPreview(preventDefaultMouseEvents);
38.  }
39.  public void onMouseLeave(Widget sender) {
40.    // Restore browser event handling when the cursor
41.    // leaves the drag source
42.    DOM.removeEventPreview(preventDefaultMouseEvents);
43.  }
44.  public void onMouseDown(Widget sender, int x, int y) {
45.    // All drag sources must have an AbsolutePanel for a
46.    // parent. This restriction is enforced in the
47.    // drag source's onLoad method
48.    AbsolutePanel parent = (AbsolutePanel)sender.getParent();
49.    Iterator widgetIterator = parent.iterator();
50.
51.    // Iterate over the parent's widgets and put all
52.    // drop targets in the dropTargets widget collection
53.    // for future reference (see intersectsDropTarget(),
54.    // implemented below)
55.    while (widgetIterator.hasNext()) {
56.      Widget w = (Widget) widgetIterator.next();
57.      if (w instanceof DropTarget) {
58.        dropTargets.add(w);
59.      }
60.    }
61.
62.    // Set the original location of the drag source in
63.    // case the drag source is dropped outside any drop
64.    // targets or is dropped on a drop target that rejects
65.    // the drag source
66.    DragSource ds = (DragSource) sender;
67.    ds.setOriginalLocation(new Point(parent.getWidgetLeft(ds),
68.        parent.getWidgetTop(ds)));
69.
70.    // Notify the drag source that a drag has been
71.    // initiated
72.    ds.dragStarted();
73.  }
74.
75.  public void onMouseMove(Widget sender, int x, int y) {
76.    DragSource ds = (DragSource) sender;
77.    if (!ds.isDragging()) {
78.      // Don't do anything if the drag source is
79.      // not being dragged
80.      return;
81.    }
82.
83.    Widget dsWidget = ds.getWidget();
84.    DropTarget dt = intersectsDropTarget(dsWidget);
85.
86.    // If the drag source intersects a drop target...
87.    if (dt != null) {
88.      // ...and if the drag source just entered
89.      // the drop target...
90.      if (ds.getEnclosingDropTarget() == null) {
91.        // ...set the enclosing drop target and
92.        // notify the drop target that the drag source
93.        // has entered
94.        ds.setEnclosingDropTarget(dt);
95.        dt.dragSourceEntered(ds);
96.      }
97.    }
98.    // If the drag source is not intersecting a drop
99.    // target...
100.    else {
101.      DropTarget enclosingDropTarget =
102.          ds.getEnclosingDropTarget();
103.
104.      // ...and the drag source was inside a drop target
105.      // previously...
106.      if (enclosingDropTarget != null) {
107.        // ...set the enclosing drop target to null
108.        // and notify the drop target that the drag
109.        // source has exited
110.        ds.setEnclosingDropTarget(null);
111.        enclosingDropTarget.dragSourceExited(ds);
112.      }
113.    }
114.  }
115.
116.  public void onMouseUp(Widget sender, int x, int y) {
117.    DragSource ds = (DragSource) sender;
118.    Widget dsWidget = ds.getWidget();
119.
120.    if (!ds.isDragging()) {
121.      // If the drag source is not being dragged,
122.      // do nothing
123.      return;
124.    }
125.
126.    DropTarget dt = intersectsDropTarget(dsWidget);
127.    if (dt != null) {
128.      // If the drag source intersects a drop target,
129.      // notify the drop target that the drag source
130.      // was dropped
131.      dt.dragSourceDropped(ds);
132.    }
133.    else {
134.      // If the drag source doesn't intersect a drop
135.      // target, notify the drag source that it was
136.      // dropped outside of any drop target
137.      ds.droppedOutsideDropTarget();
138.    }
139.  }
140.
141.  private DropTarget intersectsDropTarget(Widget dsWidget) {
142.    // Iterate over the collection of drop targets in the
143.    // drag source's enclosing panel and see if the drag
144.    // source intersects any of those drop targets; if so,
145.    // return that drop target
146.    Iterator it = dropTargets.iterator();
147.    while (it.hasNext()) {
148.      DropTarget dt = (DropTarget) it.next();
149.      int dtLeft = dt.getAbsoluteLeft();
150.      int dtTop = dt.getAbsoluteTop();
151.      int dtWidth = dt.getOffsetWidth();
152.      int dtHeight = dt.getOffsetHeight();
153.      int dsLeft = dsWidget.getAbsoluteLeft();
154.      int dsTop = dsWidget.getAbsoluteTop();
155.      int dsWidth = dsWidget.getOffsetWidth();
156.      int dsHeight = dsWidget.getOffsetHeight();
157.      dsCorners[0] = new Point(dsLeft, dsTop);
158.      dsCorners[1] = new Point(dsLeft + dsWidth, dsTop);
159.      dsCorners[2] =
160.          new Point(dsLeft + dsWidth, dsTop + dsHeight);
161.      dsCorners[3] = new Point(dsLeft, dsTop + dsHeight);
162.
163.      for (int i = 0; i < dsCorners.length; ++i) {
164.        int x = dsCorners[i].x;
165.        int y = dsCorners[i].y;
166.        if (x > dtLeft && x < dtLeft + dtWidth && y > dtTop
167.            && y < dtTop + dtHeight) {
168.          return dt;
169.        }
170.      }
171.    }
172.    return null;
173.  }
174.}

This is where most of the heavy lifting in the dnd module occurs. On a mouse down event, onMouseDown() finds all the drop targets in the drag source's enclosing absolute panel and stores them in an instance of WidgetCollection for further reference. That method also stores the drag source's location and invokes its startDragging method.

When the drag source is dragged, onMouseMove() checks to see if the drag source intersects one of the drop targets discovered in onMouseDown(); if so, it sets the drag source's enclosingDropTarget property and informs the drop target that a drag source has entered. If the drag source does not intersect a drop target but currently has an enclosing drop target, the listener informs the drop target that the drag source has exited and sets the drag source's enclosingDropTarget property to null.

When a drag source is dropped, either inside or outside a drop target, onMouseUp() informs both the drag source and drop target of the event.

Finally, notice that in onMouseEnter(), we call GWT's DOM.addEventPreview method to add an event preview to the top of the JavaScript event stack to prevent the browser from reacting to mouse drags. If we don't do that, then when a user drags an image, the browser will drag around an outline of the image as the user drags the mouse. It will not drag the image itself. Without that event preview, our drag and drop turns into mush (you might want to try removing the event preview and see the results for yourself). Subsequently, onMouseLeave() removes the event preview so that event handling returns to normal. See "Overriding a Pop-Up Panel's Default Event Handling Behavior" (page 211) for a more in-depth discussion of DOM.addEventPreview() and DOM.eventPreventDefault().

One final detail of our drag-and-drop module: The DragSourceListener class uses instances of the Component module's Point class, which is listed in Listing 6.16.

Listing 6.16. com.gwtsolutions.components.client.ui.Point

1.package com.gwtsolutions.components.client.ui;
2.
3.public class Point { // immutable
4.  final public int x;
5.  final public int y;
6.
7.  public Point(int x, int y) {
8.    this.x = x;
9.    this.y = y;
10.  }
11.}

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020