Merge lp:~danilo/launchpad/bug-772754-other-subscribers-activity into lp:launchpad

Proposed by Данило Шеган
Status: Merged
Approved by: Graham Binns
Approved revision: no longer in the source branch.
Merged at revision: 13243
Proposed branch: lp:~danilo/launchpad/bug-772754-other-subscribers-activity
Merge into: lp:launchpad
Prerequisite: lp:~danilo/launchpad/bug-772754-other-subscribers-subscribers
Diff against target: 610 lines (+541/-3)
2 files modified
lib/lp/bugs/javascript/subscribers_list.js (+190/-2)
lib/lp/bugs/javascript/tests/test_subscribers_list.js (+351/-1)
To merge this branch: bzr merge lp:~danilo/launchpad/bug-772754-other-subscribers-activity
Reviewer Review Type Date Requested Status
Graham Binns (community) code Approve
Review via email: mp+64180@code.launchpad.net

Description of the change

= Bug 772754: Other subscribers list, part 4 =

This is part of ongoing work for providing the "other subscribers" list as indicated in mockup https://launchpadlibrarian.net/71552495/all-in-one.png attached to bug 772754 by Gary.

This branch continues on the previous branches to provide methods to indicate either some global activity in the subscribers list (like "Loading subscribers") or some activity on a particular subscriber (eg. "Subscribing", "Unsubscribing", along with spinner).

It is comprehensively tested.

== Tests ==

lp/bugs/javascript/tests/test_subscribers_list.html

== Demo and Q/A ==

N/A

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/bugs/javascript/subscribers_list.js
  lib/lp/bugs/javascript/tests/test_subscribers_list.js

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/bugs/javascript/subscribers_list.js'
--- lib/lp/bugs/javascript/subscribers_list.js 2011-06-15 11:08:30 +0000
+++ lib/lp/bugs/javascript/subscribers_list.js 2011-06-15 11:08:35 +0000
@@ -82,6 +82,9 @@
82 list: 'subscribers-list',82 list: 'subscribers-list',
83 subscriber: 'subscriber',83 subscriber: 'subscriber',
84 no_subscribers: 'no-subscribers-indicator',84 no_subscribers: 'no-subscribers-indicator',
85 activity: 'global-activity-indicator',
86 activity_text: 'global-activity-text',
87 subscriber_activity: 'subscriber-activity-indicator',
85 actions: 'subscriber-actions',88 actions: 'subscriber-actions',
86 unsubscribe: 'unsubscribe-action'89 unsubscribe: 'unsubscribe-action'
87};90};
@@ -152,12 +155,14 @@
152 * of no subscribers.155 * of no subscribers.
153 *156 *
154 * @method resetNoSubscribers157 * @method resetNoSubscribers
158 * @param force_hide {Boolean} Whether to force hiding of the "no subscribers"
159 * indication.
155 */160 */
156SubscribersList.prototype.resetNoSubscribers = function() {161SubscribersList.prototype.resetNoSubscribers = function(force_hide) {
157 var has_sections = (162 var has_sections = (
158 this.container_node.one('.' + CSS_CLASSES.section) !== null);163 this.container_node.one('.' + CSS_CLASSES.section) !== null);
159 var no_subs;164 var no_subs;
160 if (has_sections) {165 if (has_sections || force_hide === true) {
161 // Make sure the indicator for no subscribers is not there.166 // Make sure the indicator for no subscribers is not there.
162 no_subs = this.container_node.one('.' + CSS_CLASSES.no_subscribers);167 no_subs = this.container_node.one('.' + CSS_CLASSES.no_subscribers);
163 if (no_subs !== null) {168 if (no_subs !== null) {
@@ -172,6 +177,106 @@
172};177};
173178
174/**179/**
180 * Returns or creates a node for progress indication for the subscribers list.
181 *
182 * If node is not present, it is created and added to the beginning of
183 * subscribers list container node.
184 *
185 * @method _ensureActivityNode
186 * @return {Y.Node} A node with the spinner img node and a span text node.
187 */
188SubscribersList.prototype._ensureActivityNode = function() {
189 var activity_node = this.container_node.one('.' + CSS_CLASSES.activity);
190 if (activity_node === null) {
191 activity_node = Y.Node.create('<div />')
192 .addClass(CSS_CLASSES.activity);
193 progress_icon = Y.Node.create('<img />')
194 .set('src', '/@@/spinner');
195 activity_node.appendChild(progress_icon);
196 activity_node.appendChild(
197 Y.Node.create('<span />')
198 .addClass(CSS_CLASSES.activity_text));
199 this.container_node.prepend(activity_node);
200 }
201 return activity_node;
202};
203
204/**
205 * Sets icon in the activity node to either 'error' or 'spinner' icon.
206 *
207 * @method _setActivityErrorIcon
208 * @param node {Y.Node} An activity node as returned by _ensureActivityNode().
209 * @param error {Boolean} Whether to show an error icon.
210 * Otherwise shows a spinner image.
211 */
212SubscribersList.prototype._setActivityErrorIcon = function(node, error) {
213 var progress_icon = node.one('img');
214 if (error === true) {
215 progress_icon.set('src', '/@@/error');
216 } else {
217 progress_icon.set('src', '/@@/spinner');
218 }
219};
220
221/**
222 * Sets the activity text inside the activity node.
223 *
224 * @method _setActivityText
225 * @param node {Y.Node} An activity node as returned by _ensureActivityNode().
226 * @param text {String} Description of the activity currently in progress.
227 */
228SubscribersList.prototype._setActivityText = function(node, text) {
229 var text_node = node.one('.' + CSS_CLASSES.activity_text);
230 text_node.set('text', ' ' + text);
231};
232
233/**
234 * Indicate some activity for the subscribers list with a progress spinner
235 * and optionally some text.
236 *
237 * @method startActivity
238 * @param text {String} Description of the action to indicate progress of.
239 */
240SubscribersList.prototype.startActivity = function(text) {
241 // We don't ever want "No subscribers" to be shown when loading is in
242 // progress.
243 this.resetNoSubscribers(true);
244
245 var activity_node = this._ensureActivityNode();
246 // Ensure the icon is back to the spinner.
247 this._setActivityErrorIcon(activity_node, false);
248 this._setActivityText(activity_node, text);
249};
250
251/**
252 * Stop any activity indication for the subscribers list and optionally
253 * display an error message.
254 *
255 * @method stopActivity
256 * @param error_text {String} Error message to display. If not a string,
257 * it is considered that the operation was successful and no error
258 * indication is added to the subscribers list.
259 */
260SubscribersList.prototype.stopActivity = function(error_text) {
261 var activity_node = this.container_node.one('.' + CSS_CLASSES.activity);
262 if (Y.Lang.isString(error_text)) {
263 // There is an error message, keep the node visible with
264 // the error message in.
265 activity_node = this._ensureActivityNode(true);
266 this._setActivityErrorIcon(activity_node, true);
267 this._setActivityText(activity_node, error_text);
268 this.resetNoSubscribers(true);
269 } else {
270 // No errors, remove the activity node if present.
271 if (activity_node !== null) {
272 activity_node.remove();
273 }
274 // Restore "No subscribers" indication if needed.
275 this.resetNoSubscribers();
276 }
277};
278
279/**
175 * Get a CSS class to use for the section of the subscribers' list280 * Get a CSS class to use for the section of the subscribers' list
176 * with subscriptions with the level `level`.281 * with subscriptions with the level `level`.
177 *282 *
@@ -551,5 +656,88 @@
551 this._removeSectionNodeIfEmpty(existing_section);656 this._removeSectionNodeIfEmpty(existing_section);
552};657};
553658
659/**
660 * Indicates some activity for a subscriber in the subscribers list.
661 * Uses a regular Launchpad progress spinner UI.
662 *
663 * If subscriber is not in the list already, it fails with an exception.
664 * If there are any actions available for the subscriber (such as unsubscribe
665 * action), they are hidden.
666 *
667 * @method indicateSubscriberActivity
668 * @param subscriber {Object} Object containing at least `name`
669 * for the subscriber.
670 */
671SubscribersList.prototype.indicateSubscriberActivity = function(subscriber) {
672 var subscriber_node = this._getSubscriberNode(subscriber);
673 var progress_node = subscriber_node.one(
674 '.' + CSS_CLASSES.subscriber_activity);
675
676 // No-op if there is already indication of progress,
677 // and creates a new node with the spinner if there isn't.
678 if (progress_node === null) {
679 var actions_node = subscriber_node.one('.' + CSS_CLASSES.actions);
680 if (actions_node !== null) {
681 actions_node.setStyle('display', 'none');
682 }
683 var progress_icon = Y.Node.create('<img />')
684 .set('src', '/@@/spinner');
685
686 progress_node = Y.Node.create('<span />')
687 .addClass(CSS_CLASSES.subscriber_activity)
688 .setStyle('float', 'right');
689 progress_node.appendChild(progress_icon);
690 subscriber_node.appendChild(progress_node);
691 }
692};
693
694/**
695 * Stop any indication of activity for a subscriber in the subscribers list.
696 *
697 * If the spinner is present, it removes it. If `success` parameter is
698 * passed in, it determines if success or failure animation will be shown
699 * as well.
700 *
701 * If subscriber is not in the list already, it fails with an exception.
702 * If there are any actions available for the subscriber (such as unsubscribe
703 * action), they are re-displayed if hidden.
704 *
705 * @method stopSubscriberActivity
706 * @param subscriber {Object} Object containing at least `name`
707 * for the subscriber.
708 * @param success {Boolean} Whether to indicate success (`success` == true,
709 * flash green) or failure (false, red). Otherwise, perform no
710 * animation.
711 * @param callback {Function} Function to call if and when success/failure
712 * animation completes.
713 */
714SubscribersList.prototype.stopSubscriberActivity = function(subscriber,
715 success,
716 callback) {
717 var subscriber_node = this._getSubscriberNode(subscriber);
718 var progress_node = subscriber_node.one(
719 '.' + CSS_CLASSES.subscriber_activity);
720 if (progress_node !== null) {
721 // Remove and destroy the node if present.
722 progress_node.remove(true);
723 }
724 // If actions node is present and hidden, show it.
725 var actions_node = subscriber_node.one('.' + CSS_CLASSES.actions);
726 if (actions_node !== null) {
727 actions_node.setStyle('display', 'inline');
728 }
729
730 if (success === true || success === false) {
731 var anim;
732 if (success === true) {
733 anim = Y.lazr.anim.green_flash({ node: subscriber_node });
734 } else {
735 anim = Y.lazr.anim.red_flash({ node: subscriber_node });
736 }
737 anim.on('end', callback);
738 anim.run();
739 }
740};
741
554742
555}, "0.1", {"requires": ["node", "lazr.anim", "lp.client", "lp.names"]});743}, "0.1", {"requires": ["node", "lazr.anim", "lp.client", "lp.names"]});
556744
=== modified file 'lib/lp/bugs/javascript/tests/test_subscribers_list.js'
--- lib/lp/bugs/javascript/tests/test_subscribers_list.js 2011-06-15 11:08:30 +0000
+++ lib/lp/bugs/javascript/tests/test_subscribers_list.js 2011-06-15 11:08:35 +0000
@@ -430,6 +430,29 @@
430 no_subs_nodes.item(0).get('text'));430 no_subs_nodes.item(0).get('text'));
431 },431 },
432432
433 test_no_subscribers_force_hide: function() {
434 // When resetNoSubscribers() is called on an empty
435 // SubscribersList but with force_hide parameter set to true,
436 // indication of no subscribers is not added.
437 var subscribers_list = setUpSubscribersList(this.root);
438 subscribers_list.resetNoSubscribers(true);
439 var no_subs_nodes = this.root.all(
440 '.no-subscribers-indicator');
441 Y.Assert.areEqual(0, no_subs_nodes.size());
442 },
443
444 test_no_subscribers_force_hide_removal: function() {
445 // When resetNoSubscribers() is called on an empty
446 // SubscribersList which already has a no-subscribers
447 // indication shown, it is removed.
448 var subscribers_list = setUpSubscribersList(this.root);
449 subscribers_list.resetNoSubscribers();
450 subscribers_list.resetNoSubscribers(true);
451 var no_subs_nodes = this.root.all(
452 '.no-subscribers-indicator');
453 Y.Assert.areEqual(0, no_subs_nodes.size());
454 },
455
433 test_subscribers_no_addition: function() {456 test_subscribers_no_addition: function() {
434 // When resetNoSubscribers() is called on a SubscribersList457 // When resetNoSubscribers() is called on a SubscribersList
435 // with some subscribers, no indication of no subscribers is added.458 // with some subscribers, no indication of no subscribers is added.
@@ -474,6 +497,184 @@
474497
475498
476/**499/**
500 * Test activity/progress indication for the entire subscribers list.
501 */
502suite.add(new Y.Test.Case({
503 name: 'SubscribersList.startActivity() and stopActivity() test',
504
505 _should: {
506 error: {
507 test_setActivityErrorIcon_error: true,
508 test_setActivityText_error: true
509 }
510 },
511
512 setUp: function() {
513 this.root = Y.Node.create('<div />');
514 Y.one('body').appendChild(this.root);
515 },
516
517 tearDown: function() {
518 this.root.remove();
519 },
520
521 test_ensureActivityNode: function() {
522 // With no activity node present, one is created and put
523 // into the subscribers list container node.
524 var subscribers_list = setUpSubscribersList(this.root);
525 var node = subscribers_list._ensureActivityNode();
526 Y.Assert.isNotNull(node);
527 Y.Assert.isTrue(node.hasClass('global-activity-indicator'));
528 Y.Assert.areSame(
529 subscribers_list.container_node, node.get('parentNode'));
530 },
531
532 test_ensureActivityNode_contents: function() {
533 // Created node contains an img tag with the spinner icon
534 // and a span tag for the text.
535 var subscribers_list = setUpSubscribersList(this.root);
536 var node = subscribers_list._ensureActivityNode();
537 var icon = node.one('img');
538 Y.Assert.isNotNull(icon);
539 Y.Assert.areEqual('file:///@@/spinner', icon.get('src'));
540 var text = node.one('span');
541 Y.Assert.isNotNull(text);
542 Y.Assert.isTrue(text.hasClass('global-activity-text'));
543 },
544
545 test_ensureActivityNode_existing: function() {
546 // When activity node already exists, it is returned
547 // and no new one is created.
548 var subscribers_list = setUpSubscribersList(this.root);
549 var existing_node = subscribers_list._ensureActivityNode();
550 var new_node = subscribers_list._ensureActivityNode();
551 Y.Assert.areSame(existing_node, new_node);
552 Y.Assert.areEqual(
553 1,
554 subscribers_list
555 .container_node
556 .all('.global-activity-indicator')
557 .size());
558 },
559
560 test_setActivityErrorIcon_error_icon: function() {
561 // With the activity node passed in, error icon is set
562 // when desired.
563 var subscribers_list = setUpSubscribersList(this.root);
564 var node = subscribers_list._ensureActivityNode();
565 var icon_node = node.one('img');
566 subscribers_list._setActivityErrorIcon(node, true);
567 Y.Assert.areEqual('file:///@@/error', icon_node.get('src'));
568 },
569
570 test_setActivityErrorIcon_spinner_icon: function() {
571 // With the activity node passed in, spinner icon is restored
572 // when requested (error parameter !== true).
573 var subscribers_list = setUpSubscribersList(this.root);
574 var node = subscribers_list._ensureActivityNode();
575 var icon_node = node.one('img');
576 subscribers_list._setActivityErrorIcon(node, false);
577 Y.Assert.areEqual('file:///@@/spinner', icon_node.get('src'));
578 },
579
580 test_setActivityErrorIcon_error: function() {
581 // With non-activity node passed in, it fails.
582 var subscribers_list = setUpSubscribersList(this.root);
583 var node = Y.Node.create('<div />');
584 subscribers_list._setActivityErrorIcon(node, true);
585 },
586
587 test_setActivityText: function() {
588 // With activity node and text passed in, proper
589 // text is set in the activity text node.
590 var subscribers_list = setUpSubscribersList(this.root);
591 var node = subscribers_list._ensureActivityNode();
592 subscribers_list._setActivityText(node, "Blah");
593 // Single whitespace is prepended to better separate
594 // icon from the text.
595 Y.Assert.areEqual(" Blah", node.one('span').get('text'));
596 },
597
598 test_setActivityText_error: function() {
599 // With non-activity node passed in, it fails.
600 var subscribers_list = setUpSubscribersList(this.root);
601 var node = Y.Node.create('<div />');
602 subscribers_list._setActivityText(node, "Blah");
603 },
604
605 test_startActivity: function() {
606 // startActivity adds the spinner icon and sets the appropriate text.
607 var subscribers_list = setUpSubscribersList(this.root);
608 subscribers_list.startActivity("Blah");
609
610 var node = subscribers_list._ensureActivityNode();
611
612 Y.Assert.areEqual('file:///@@/spinner', node.one('img').get('src'));
613 Y.Assert.areEqual(" Blah", node.one('span').get('text'));
614 },
615
616 test_startActivity_restores_state: function() {
617 // startActivity removes the no-subscribers indicator if present
618 // and restores the activity node icon.
619 var subscribers_list = setUpSubscribersList(this.root);
620 // Add a no-subscribers indication.
621 subscribers_list.resetNoSubscribers();
622 // Create an activity node and set the error icon.
623 var node = subscribers_list._ensureActivityNode();
624 subscribers_list._setActivityErrorIcon(node, true);
625
626 // Call startActivity() and see how it restores everything.
627 subscribers_list.startActivity();
628 Y.Assert.areEqual('file:///@@/spinner', node.one('img').get('src'));
629 Y.Assert.isNull(
630 subscribers_list.container_node.one('.no-subscribers-indicator'));
631 },
632
633 test_stopActivity: function() {
634 // stopActivity without parameters assumes a successful completion
635 // of the activity, so it removes the activity node and restores
636 // no-subscribers indication if needed.
637 var subscribers_list = setUpSubscribersList(this.root);
638 subscribers_list.startActivity("Blah");
639 subscribers_list.stopActivity();
640
641 var node = subscribers_list.container_node.one(
642 '.global-activity-indicator');
643 Y.Assert.isNull(node);
644 // Indication of no subscribers is restored.
645 Y.Assert.isNotNull(
646 subscribers_list.container_node.one('.no-subscribers-indicator'));
647 },
648
649 test_stopActivity_noop: function() {
650 // stopActivity without parameters assumes a successful completion
651 // of the activity. If no activity was in progress, nothing happens.
652 var subscribers_list = setUpSubscribersList(this.root);
653 subscribers_list.stopActivity();
654
655 var node = subscribers_list.container_node.one(
656 '.global-activity-indicator');
657 Y.Assert.isNull(node);
658 },
659
660 test_stopActivity_with_error_message: function() {
661 // stopActivity with error message passed in creates an activity
662 // node even if activity was not in progress and sets the error
663 // icon and error text to the passed in message..
664 var subscribers_list = setUpSubscribersList(this.root);
665 subscribers_list.stopActivity("Problem!");
666 var node = subscribers_list._ensureActivityNode();
667 Y.Assert.areEqual('file:///@@/error', node.one('img').get('src'));
668 Y.Assert.areEqual(" Problem!", node.one('span').get('text'));
669
670 // Indication of no subscribers is not added.
671 Y.Assert.isNull(
672 subscribers_list.container_node.one('.no-subscribers-indicator'));
673 }
674}));
675
676
677/**
477 * Function to get a list of all the sections present in the678 * Function to get a list of all the sections present in the
478 * subscribers_list (a SubscribersList object).679 * subscribers_list (a SubscribersList object).
479 */680 */
@@ -815,7 +1016,6 @@
815}));1016}));
8161017
8171018
818
819/**1019/**
820 * Test adding of subscribers and relevant helper methods.1020 * Test adding of subscribers and relevant helper methods.
821 */1021 */
@@ -1235,6 +1435,156 @@
1235}));1435}));
12361436
12371437
1438/**
1439 * Test showing/stopping indication of activity for a subscriber.
1440 */
1441suite.add(new Y.Test.Case({
1442 name: 'SubscribersList.indicateSubscriberActivity() and ' +
1443 'SubscribersList.stopSubscriberActivity() test',
1444
1445 setUp: function() {
1446 this.root = Y.Node.create('<div />');
1447 Y.one('body').appendChild(this.root);
1448 },
1449
1450 tearDown: function() {
1451 this.root.remove();
1452 },
1453
1454 _should: {
1455 error: {
1456 test_indicateSubscriberActivity_error:
1457 new Error('Subscriber is not present in the subscribers list. ' +
1458 'Please call addSubscriber(subscriber) first.'),
1459 test_stopSubscriberActivity_error:
1460 new Error('Subscriber is not present in the subscribers list. ' +
1461 'Please call addSubscriber(subscriber) first.')
1462 }
1463 },
1464
1465 test_indicateSubscriberActivity_error: function() {
1466 // When subscriber is not in the list, fails with an exception.
1467 var subscribers_list = setUpSubscribersList(this.root);
1468 var subscriber = { name: 'user' };
1469 subscribers_list.indicateSubscriberActivity(subscriber);
1470 },
1471
1472 test_indicateSubscriberActivity_node: function() {
1473 // Creates a node with spinner image in it.
1474 var subscribers_list = setUpSubscribersList(this.root);
1475 var subscriber = { name: 'user' };
1476 var node = subscribers_list.addSubscriber(subscriber, 'Details');
1477 subscribers_list.indicateSubscriberActivity(subscriber);
1478
1479 // This is the created node.
1480 var progress_node = node.one('.subscriber-activity-indicator');
1481 Y.Assert.isNotNull(progress_node);
1482 var progress_icon = progress_node.one('img');
1483 // We get an absolute URI, instead of the relative one which
1484 // the code sets. Since the test runs from the local file system,
1485 // that means "file://".
1486 Y.Assert.areEqual('file:///@@/spinner', progress_icon.get('src'));
1487 },
1488
1489 test_indicateSubscriberActivity_actions_hidden: function() {
1490 // If there are any actions (in an actions node), they are
1491 // all hidden.
1492 var subscribers_list = setUpSubscribersList(this.root);
1493 var subscriber = { name: 'user' };
1494 var node = subscribers_list.addSubscriber(subscriber, 'Details');
1495 var actions_node = subscribers_list._getOrCreateActionsNode(node);
1496
1497 subscribers_list.indicateSubscriberActivity(subscriber);
1498 Y.Assert.areEqual('none', actions_node.getStyle('display'));
1499 },
1500
1501 test_stopSubscriberActivity_error: function() {
1502 // When subscriber is not in the list, fails with an exception.
1503 var subscribers_list = setUpSubscribersList(this.root);
1504 var subscriber = { name: 'user' };
1505 subscribers_list.stopSubscriberActivity(subscriber);
1506 },
1507
1508 test_stopSubscriberActivity_noop: function() {
1509 // When there's no activity in progress, nothing happens.
1510 var subscribers_list = setUpSubscribersList(this.root);
1511 var subscriber = { name: 'user' };
1512 var node = subscribers_list.addSubscriber(subscriber, 'Details');
1513 subscribers_list.stopSubscriberActivity(subscriber);
1514 },
1515
1516 test_stopSubscriberActivity_spinner_removed: function() {
1517 // When there is some activity in progress, spinner is removed.
1518 var subscribers_list = setUpSubscribersList(this.root);
1519 var subscriber = { name: 'user' };
1520 var node = subscribers_list.addSubscriber(subscriber, 'Details');
1521 // Create the spinner.
1522 subscribers_list.indicateSubscriberActivity(subscriber);
1523 // And remove it.
1524 subscribers_list.stopSubscriberActivity(subscriber);
1525 Y.Assert.isNull(node.one('.subscriber-activity-indicator'));
1526 },
1527
1528 test_stopSubscriberActivity_actions_restored: function() {
1529 // When there is some activity in progress, spinner is removed.
1530 var subscribers_list = setUpSubscribersList(this.root);
1531 var subscriber = { name: 'user' };
1532 var node = subscribers_list.addSubscriber(subscriber, 'Details');
1533 var actions_node = subscribers_list._getOrCreateActionsNode(node);
1534 // Hide actions.
1535 actions_node.setStyle('display', 'none');
1536 // And restore actions.
1537 subscribers_list.stopSubscriberActivity(subscriber);
1538 Y.Assert.areEqual('inline', actions_node.getStyle('display'));
1539 },
1540
1541 test_stopSubscriberActivity_success_callback: function() {
1542 // When we are indicating successful/failed operation,
1543 // green_flash/red_flash animation is executed and callback
1544 // function is called when it ends.
1545 var subscribers_list = setUpSubscribersList(this.root);
1546 var subscriber = { name: 'user' };
1547 subscribers_list.addSubscriber(subscriber, 'Details');
1548 var callback_called = false;
1549 var callback = function() {
1550 callback_called = true;
1551 };
1552
1553 subscribers_list.stopSubscriberActivity(
1554 subscriber, true, callback);
1555 // Callback is not called immediatelly.
1556 Y.Assert.isFalse(callback_called);
1557 this.wait(function() {
1558 // But after waiting for animation to complete,
1559 // callback is called.
1560 Y.Assert.isTrue(callback_called);
1561 }, 1100);
1562 },
1563
1564 test_stopSubscriberActivity_no_callback: function() {
1565 // When we pass the callback in, but success is neither
1566 // 'true' nor 'false', callback is not called.
1567 var subscribers_list = setUpSubscribersList(this.root);
1568 var subscriber = { name: 'user' };
1569 subscribers_list.addSubscriber(subscriber, 'Details');
1570 var callback_called = false;
1571 var callback = function() {
1572 callback_called = true;
1573 };
1574
1575 subscribers_list.stopSubscriberActivity(
1576 subscriber, "no-callback", callback);
1577 // Callback is not called.
1578 Y.Assert.isFalse(callback_called);
1579 this.wait(function() {
1580 // Nor is it called after any potential animations complete.
1581 Y.Assert.isFalse(callback_called);
1582 }, 1100);
1583 }
1584
1585}));
1586
1587
1238var handle_complete = function(data) {1588var handle_complete = function(data) {
1239 window.status = '::::' + JSON.stringify(data);1589 window.status = '::::' + JSON.stringify(data);
1240 };1590 };