Mhurd has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/157489

Change subject: Alerts now support duration, position and attributed strings.
......................................................................

Alerts now support duration, position and attributed strings.

Further stability improvements.

Change-Id: I473b5f02319d016b7c4cf8bfd7dea9b1930dcbef
---
M wikipedia/AppDelegate.m
M wikipedia/Categories/Alerts/AlertLabel.h
M wikipedia/Categories/Alerts/AlertLabel.m
M wikipedia/Categories/Alerts/UIViewController+Alert.h
M wikipedia/Categories/Alerts/UIViewController+Alert.m
M wikipedia/Categories/NSString+Extras.m
M wikipedia/Categories/NSURLRequest+DictionaryRequest.m
M wikipedia/Categories/TopActionSheet/UINavigationController+TopActionSheet.m
M wikipedia/Categories/UINavigationController+SearchNavStack.m
M wikipedia/Categories/UIView+Debugging.m
M wikipedia/Categories/UIView+RemoveConstraints.m
M wikipedia/Categories/UIView+SearchSubviews.h
M wikipedia/Categories/UIView+SearchSubviews.m
M wikipedia/Categories/UIViewController+HideKeyboard.m
M wikipedia/Categories/UIViewController+SearchChildViewControllers.m
M wikipedia/Categories/UIWebView+HideScrollGradient.m
M wikipedia/TabularScrollView/TabularScrollView.m
M wikipedia/View Controllers/AccountCreation/AccountCreationViewController.m
M wikipedia/View Controllers/Languages/LanguagesViewController.m
M wikipedia/View Controllers/Login/LoginViewController.m
M wikipedia/View Controllers/Navigation/Bottom/BottomMenuViewController.m
M wikipedia/View Controllers/Navigation/Primary/PrimaryMenuViewController.m
M wikipedia/View Controllers/Navigation/Secondary/SecondaryMenuViewController.m
M wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m
M wikipedia/View Controllers/Nearby/NearbyViewController.m
M wikipedia/View Controllers/Onboarding/OnboardingViewController.m
M wikipedia/View Controllers/PageHistory/PageHistoryViewController.m
M wikipedia/View Controllers/Preview/PreviewAndSaveViewController.m
M wikipedia/View Controllers/Preview/PreviewLicenseView.m
M wikipedia/View Controllers/References/ReferencesVC.m
M wikipedia/View Controllers/SearchResults/SearchResultsController.m
M wikipedia/View Controllers/SectionEditor/SectionEditorViewController.m
M wikipedia/View Controllers/TableOfContents/TOCViewController.m
M wikipedia/View Controllers/WebView/WebViewController.h
M wikipedia/View Controllers/WebView/WebViewController.m
M wikipedia/assets/abusefilter.css
M wikipedia/assets/preview.css
M wikipedia/assets/styles.css
M wikipedia/en.lproj/Localizable.strings
M wikipedia/qqq.lproj/Localizable.strings
40 files changed, 498 insertions(+), 355 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/apps/ios/wikipedia 
refs/changes/89/157489/1

diff --git a/wikipedia/AppDelegate.m b/wikipedia/AppDelegate.m
index a40bc9f..f137d7e 100644
--- a/wikipedia/AppDelegate.m
+++ b/wikipedia/AppDelegate.m
@@ -83,7 +83,8 @@
         @"FakeZeroOn" : @NO,
         @"ShowOnboarding" : @YES,
         @"LastHousekeepingDate" : [NSDate date], //[NSDate 
dateWithDaysBeforeNow:10]
-        @"SendUsageReports": @YES
+        @"SendUsageReports": @YES,
+        @"AccessSavedPagesMessageShown": @NO
     };
     [[NSUserDefaults standardUserDefaults] 
registerDefaults:userDefaultsDefaults];
 }
diff --git a/wikipedia/Categories/Alerts/AlertLabel.h 
b/wikipedia/Categories/Alerts/AlertLabel.h
index 4ac6761..f844072 100644
--- a/wikipedia/Categories/Alerts/AlertLabel.h
+++ b/wikipedia/Categories/Alerts/AlertLabel.h
@@ -4,6 +4,19 @@
 #import <UIKit/UIKit.h>
 #import "PaddedLabel.h"
 
+typedef NS_ENUM(NSInteger, AlertType) {
+    ALERT_TYPE_UNKNOWN,
+    ALERT_TYPE_TOP,
+    ALERT_TYPE_BOTTOM,
+    ALERT_TYPE_FULLSCREEN
+};
+
 @interface AlertLabel : PaddedLabel
 
+-(id)initWithText:(id)text duration:(CGFloat)duration 
padding:(UIEdgeInsets)padding type:(AlertType)type;
+
+-(void)hide;
+
+-(void)fade;
+
 @end
diff --git a/wikipedia/Categories/Alerts/AlertLabel.m 
b/wikipedia/Categories/Alerts/AlertLabel.m
index ce30f09..456cf70 100644
--- a/wikipedia/Categories/Alerts/AlertLabel.m
+++ b/wikipedia/Categories/Alerts/AlertLabel.m
@@ -4,68 +4,113 @@
 #import "AlertLabel.h"
 #import "WMF_Colors.h"
 #import "Defines.h"
+#import "UIView+RemoveConstraints.h"
+
+@interface AlertLabel()
+
+@property (nonatomic) CGFloat duration;
+@property (nonatomic) UIEdgeInsets padding;
+@property (nonatomic, strong) id text;
+@property (nonatomic) AlertType type;
+
+@end
 
 @implementation AlertLabel
 
-- (id)init
+-(id)initWithText:(id)text duration:(CGFloat)duration 
padding:(UIEdgeInsets)padding type:(AlertType)type;
 {
     self = [super init];
     if (self) {
-        self.alpha = 0.0f;
 
-        self.padding = UIEdgeInsetsMake(1, 10, 1, 10);
-
-        self.minimumScaleFactor = 0.2;
         self.font = [UIFont systemFontOfSize:10];
         self.textAlignment = NSTextAlignmentCenter;
         self.textColor = [UIColor colorWithWhite:0.0 alpha:1.0];
+
+        if([text isKindOfClass:[NSAttributedString class]]){
+            self.attributedText = text;
+        }else{
+            self.text = text;
+        }
+
+        self.duration = duration;
+        self.padding = padding;
+        self.type = type;
+        self.minimumScaleFactor = 0.2;
         self.numberOfLines = 0;
         self.lineBreakMode = NSLineBreakByWordWrapping;
         self.backgroundColor = CHROME_COLOR;
         self.userInteractionEnabled = YES;
-
-        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(tap)];
+        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(tap:)];
         [self addGestureRecognizer:tap];
     }
     return self;
 }
 
--(void)tap
+-(void)tap:(UITapGestureRecognizer *)recognizer
 {
-    // Hide without delay.
-    self.alpha = 0.0f;
-}
-
--(void)setHidden:(BOOL)hidden
-{
-    if (hidden){
-        [UIView beginAnimations:nil context:NULL];
-        [UIView setAnimationDuration:0.35];
-        [UIView setAnimationDelay:1.0f];
-        [self setAlpha:0.0f];
-        [UIView commitAnimations];
-    }else{
-        [self setAlpha:1.0f];
+    if(recognizer.state == UIGestureRecognizerStateEnded){
+        // Hide without delay.
+        [self hide];
     }
 }
 
--(void)setText:(NSString *)text
+-(void)hide
 {
-    if (text.length == 0){
-        // Just fade out if message is set to empty string
-        self.hidden = YES;
-    }else{
-        super.text = text;
-        self.hidden = NO;
-    }
+    // Don't do anything if this view has yet to move to its superview.
+    if (!self.superview) return;
+
+    // This is important. Without this, rapid taps on save icon followed by 
save icon long press to
+    // bring up the saved pages list followed by selection would cause crash 
on iOS 6. Crash related
+    // to the constraint system causeing the alert view to be retained too 
long.
+    [self removeConstraintsOfViewFromView:self.superview];
+
+    [self removeFromSuperview];
+}
+
+-(void)fade
+{
+    [self fadeAfterDelay:0];
+}
+
+-(void)fadeAfterDelay:(CGFloat)delay
+{
+    // Don't do anything if this view has yet to move to its superview.
+    if (!self.superview) return;
+    
+    [UIView animateWithDuration:0.35
+                          delay:delay
+                        options:0
+                     animations:^{
+                         self.alpha = 0.0;
+                     }
+                     completion:^(BOOL done){
+                         [self hide];
+                     }];
+}
+
+-(void)didMoveToSuperview
+{
+    if (self.duration == -1) return;
+    [self fadeAfterDelay:self.duration];
 }
 
 - (void)drawRect:(CGRect)rect {
     [super drawRect:rect];
     CGContextRef context = UIGraphicsGetCurrentContext();
 
-    CGContextMoveToPoint(context, CGRectGetMinX(rect), CGRectGetMaxY(rect));
-    CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
+    switch (self.type) {
+        case ALERT_TYPE_TOP:
+            CGContextMoveToPoint(context, CGRectGetMinX(rect), 
CGRectGetMaxY(rect));
+            CGContextAddLineToPoint(context, CGRectGetMaxX(rect), 
CGRectGetMaxY(rect));
+            break;
+        case ALERT_TYPE_BOTTOM:
+            CGContextMoveToPoint(context, CGRectGetMinX(rect), 
CGRectGetMinY(rect));
+            CGContextAddLineToPoint(context, CGRectGetMaxX(rect), 
CGRectGetMinY(rect));
+            break;
+        default: //ALERT_TYPE_FULLSCREEN
+            return;
+            break;
+    }
 
     CGContextSetStrokeColorWithColor(context, [[UIColor lightGrayColor] 
CGColor] );
     CGContextSetLineWidth(context, 1.0f / [UIScreen mainScreen].scale);
@@ -73,4 +118,11 @@
     CGContextStrokePath(context);
 }
 
+/*
+-(void)dealloc
+{
+    NSLog(@"DEALLOC'ING ALERT VIEW!");
+}
+*/
+
 @end
diff --git a/wikipedia/Categories/Alerts/UIViewController+Alert.h 
b/wikipedia/Categories/Alerts/UIViewController+Alert.h
index 2004bce..c3cc777 100644
--- a/wikipedia/Categories/Alerts/UIViewController+Alert.h
+++ b/wikipedia/Categories/Alerts/UIViewController+Alert.h
@@ -2,14 +2,13 @@
 //  Copyright (c) 2013 Wikimedia Foundation. Provided under MIT-style license; 
please copy and modify!
 
 #import <UIKit/UIKit.h>
+#import "AlertLabel.h"
 
 // Category for showing alerts from any view controller.
 
 @interface UIViewController (Alert)
 
-// Shows alert text just beneath the nav bar.
-// Fades out alert if alertText set to zero length string.
--(void)showAlert:(NSString *)alertText;
+-(void)showAlert:(id)alertText type:(AlertType)type duration:(CGFloat)duration;
 
 -(void)fadeAlert;
 
diff --git a/wikipedia/Categories/Alerts/UIViewController+Alert.m 
b/wikipedia/Categories/Alerts/UIViewController+Alert.m
index 7fc20ad..f5de0ec 100644
--- a/wikipedia/Categories/Alerts/UIViewController+Alert.m
+++ b/wikipedia/Categories/Alerts/UIViewController+Alert.m
@@ -2,57 +2,47 @@
 //  Copyright (c) 2013 Wikimedia Foundation. Provided under MIT-style license; 
please copy and modify!
 
 #import "UIViewController+Alert.h"
-#import "AlertLabel.h"
 #import "UIView+RemoveConstraints.h"
+#import "UIView+SearchSubviews.h"
+#import "WebViewController.h"
+#import "BottomMenuViewController.h"
 
 @implementation UIViewController (Alert)
 
--(void)showAlert:(NSString *)alertText
+-(void)showAlert:(id)alertText type:(AlertType)type duration:(CGFloat)duration
 {
     [[NSOperationQueue mainQueue] addOperationWithBlock: ^ {
-        AlertLabel *alertLabel = nil;
+        [self fadeAlert];
         
-        // Tack these alerts to the nav controller's view.
-        UIView *alertContainer = self.view;
+        if ([self shouldHideAlertForViewController:self]) return;
         
-        // Reuse existing alert label if any.
-        alertLabel = [self getExistingViewOfClass:[AlertLabel class] 
inContainer:alertContainer];
+        AlertLabel *newAlertLabel =
+        [[AlertLabel alloc] initWithText: alertText
+                                duration: duration
+                                 padding: UIEdgeInsetsMake(1, 10, 1, 10)
+                                 type:type];
         
-        // If none to reuse, add one.
-        if (!alertLabel) {
-            alertLabel = [[AlertLabel alloc] init];
-            alertLabel.translatesAutoresizingMaskIntoConstraints = NO;
-            //alertLabel.layer.cornerRadius = 3.0f;
-            //alertLabel.clipsToBounds = YES;
-            [alertContainer addSubview:alertLabel];
-            [self constrainAlertView:alertLabel fullScreen:NO];
-        }
-
-        BOOL hide = [self shouldHideAlertForViewController:self];
-
-        if (hide) {
-            alertLabel.alpha = 0.0;
-        }else{
-            alertLabel.text = alertText;
-        }
-
+        newAlertLabel.translatesAutoresizingMaskIntoConstraints = NO;
+        //newAlertLabel.layer.cornerRadius = 3.0f;
+        //newAlertLabel.clipsToBounds = YES;
+        [self.view addSubview:newAlertLabel];
+        
+        [self constrainAlertView:newAlertLabel type:type];
     }];
 }
 
 -(void)fadeAlert
 {
-    [self showAlert:@""];
+    // Fade existing alert labels if any.
+    NSArray *alertLabels = [self.view getSubviewsOfClass:[AlertLabel class]];
+    [alertLabels makeObjectsPerformSelector:@selector(fade)];
 }
 
 -(void)hideAlert
 {
-    // Hide alert immediately. Removes it so any running fade animations don't 
prevent immediate hide.
-    AlertLabel *alertLabel = [self getExistingViewOfClass:[AlertLabel class] 
inContainer:self.view];
-    if (alertLabel) {
-        [alertLabel removeConstraintsOfViewFromView:self.view];
-        [alertLabel removeFromSuperview];
-        alertLabel = nil;
-    }
+    // Hide existing alert labels if any.
+    NSArray *alertLabels = [self.view getSubviewsOfClass:[AlertLabel class]];
+    [alertLabels makeObjectsPerformSelector:@selector(hide)];
 }
 
 -(BOOL)shouldHideAlertForViewController:(UIViewController *)vc
@@ -100,38 +90,55 @@
 }
 */
 
--(void)constrainAlertView:(UIView *)view fullScreen:(BOOL)isFullScreen
+-(void)constrainAlertView: (UIView *)view type:(AlertType)type;
 {
+    [view removeConstraintsOfViewFromView:self.view];
+
     CGFloat margin = 0;
 
-    NSDictionary *views = NSDictionaryOfVariableBindings(view);
+    NSMutableDictionary *views = @{@"view": view}.mutableCopy;
     NSDictionary *metrics = @{@"space": @(margin)};
 
-    [self.view addConstraints:
-     [NSLayoutConstraint constraintsWithVisualFormat: 
@"H:|-(space)-[view]-(space)-|"
-                                             options: 0
-                                             metrics: metrics
-                                               views: views
-      ]
-     ];
-    
-    NSString *verticalConstraint = [NSString 
stringWithFormat:@"V:|-(space)-[view]%@", (isFullScreen) ? @"|": @""];
-    
-    [self.view addConstraints:
-     [NSLayoutConstraint constraintsWithVisualFormat: verticalConstraint
-                                             options: 0
-                                             metrics: metrics
-                                               views: views
-      ]
-     ];
-}
 
--(id)getExistingViewOfClass:(Class)class inContainer:(UIView *)container
-{
-    for (id view in container.subviews.copy) {
-        if ([view isMemberOfClass:class]) return view;
+    UIView *bottomMenuView = nil;
+    if([self isMemberOfClass:[WebViewController class]]){
+        WebViewController *webVC = (WebViewController *)self;
+        bottomMenuView = webVC.bottomMenuViewController.view;
+        if (bottomMenuView) {
+            views[@"bottomMenuView"] = bottomMenuView;
+        }
     }
-    return nil;
+
+    NSString *verticalFormatString = @"";
+    switch (type) {
+        case ALERT_TYPE_BOTTOM:
+            if (bottomMenuView) {
+                verticalFormatString = @"V:[view]-(space)-[bottomMenuView]";
+            }else{
+                verticalFormatString = @"V:[view]-(space)-|";
+            }
+            break;
+        case ALERT_TYPE_FULLSCREEN:
+            verticalFormatString = @"V:|-(space)-[view]-(space)-|";
+            break;
+        default: // ALERT_TYPE_TOP
+            verticalFormatString = @"V:|-(space)-[view]";
+            break;
+    }
+    
+    NSArray *viewConstraintArrays =
+    @[
+      [NSLayoutConstraint constraintsWithVisualFormat: 
@"H:|-(space)-[view]-(space)-|"
+                                              options: 0
+                                              metrics: metrics
+                                                views: views],
+      [NSLayoutConstraint constraintsWithVisualFormat: verticalFormatString
+                                              options: 0
+                                              metrics: metrics
+                                                views: views]
+      ];
+
+    [self.view addConstraints:[viewConstraintArrays 
valueForKeyPath:@"@unionOfArrays.self"]];
 }
 
 @end
diff --git a/wikipedia/Categories/NSString+Extras.m 
b/wikipedia/Categories/NSString+Extras.m
index c1c5ed0..9cf4334 100644
--- a/wikipedia/Categories/NSString+Extras.m
+++ b/wikipedia/Categories/NSString+Extras.m
@@ -75,7 +75,7 @@
     NSData *stringData = [self dataUsingEncoding:NSUTF8StringEncoding];
     TFHpple *parser = [TFHpple hppleWithHTMLData:stringData];
     NSArray *textNodes = [parser searchWithXPathQuery:@"//text()"];
-    NSMutableArray *results = [@[] mutableCopy];
+    NSMutableArray *results = @[].mutableCopy;
     for (TFHppleElement *node in textNodes) {
         if(node.isTextNode) [results addObject:node.raw];
     }
diff --git a/wikipedia/Categories/NSURLRequest+DictionaryRequest.m 
b/wikipedia/Categories/NSURLRequest+DictionaryRequest.m
index 31ea032..2ead3e3 100644
--- a/wikipedia/Categories/NSURLRequest+DictionaryRequest.m
+++ b/wikipedia/Categories/NSURLRequest+DictionaryRequest.m
@@ -15,7 +15,7 @@
 {
     NSMutableString *body = [NSMutableString string];
     
-    for (NSString *key in parameters) {
+    for (NSString *key in parameters.copy) {
         NSString *val = [parameters objectForKey:key];
         if ([body length])
             [body appendString:@"&"];
diff --git 
a/wikipedia/Categories/TopActionSheet/UINavigationController+TopActionSheet.m 
b/wikipedia/Categories/TopActionSheet/UINavigationController+TopActionSheet.m
index 019ea17..59f8d2e 100644
--- 
a/wikipedia/Categories/TopActionSheet/UINavigationController+TopActionSheet.m
+++ 
b/wikipedia/Categories/TopActionSheet/UINavigationController+TopActionSheet.m
@@ -3,6 +3,7 @@
 
 #import "UINavigationController+TopActionSheet.h"
 #import "UIView+RemoveConstraints.h"
+#import "UIView+SearchSubviews.h"
 
 #define ANIMATION_DURATION 0.23f
 
@@ -16,7 +17,7 @@
         UIView *superView = self.view;
         
         // Reuse existing container if any.
-        containerView = [self getExistingViewOfClass:[TabularScrollView class] 
inContainer:superView];
+        containerView = [superView getFirstSubviewOfClass:[TabularScrollView 
class]];
 
         // Remove container view if no views were specified.
         if (!views || (views.count == 0)) {
@@ -66,7 +67,7 @@
 
-(void)topActionSheetChangeOrientation:(TabularScrollViewOrientation)orientation
 {
     [[NSOperationQueue mainQueue] addOperationWithBlock: ^ {
-        TabularScrollView *containerView = [self 
getExistingViewOfClass:[TabularScrollView class] inContainer:self.view];
+        TabularScrollView *containerView = [self.view 
getFirstSubviewOfClass:[TabularScrollView class]];
 
         [containerView setOrientation:orientation];
             
@@ -105,14 +106,6 @@
     [self.view addConstraints:[constraints 
valueForKeyPath:@"@unionOfArrays.self"]];
 
     [self.view setNeedsUpdateConstraints];
-}
-
--(id)getExistingViewOfClass:(Class)class inContainer:(UIView *)container
-{
-    for (id view in container.subviews) {
-        if ([view isMemberOfClass:class]) return view;
-    }
-    return nil;
 }
 
 @end
diff --git a/wikipedia/Categories/UINavigationController+SearchNavStack.m 
b/wikipedia/Categories/UINavigationController+SearchNavStack.m
index e219628..0a158cc 100644
--- a/wikipedia/Categories/UINavigationController+SearchNavStack.m
+++ b/wikipedia/Categories/UINavigationController+SearchNavStack.m
@@ -7,7 +7,7 @@
 
 -(id)searchNavStackForViewControllerOfClass:(Class)aClass
 {
-    for (UIViewController *vc in self.viewControllers) {
+    for (UIViewController *vc in self.viewControllers.copy) {
         if ([vc isMemberOfClass:aClass]) return vc;
     }
     return nil;
@@ -16,7 +16,7 @@
 -(id)getVCBeneathVC:(id)thisVC
 {
     id vcBeneath = nil;
-    for (id vc in self.viewControllers) {
+    for (id vc in self.viewControllers.copy) {
         if (vc == thisVC) return vcBeneath;
         vcBeneath = vc;
     }
diff --git a/wikipedia/Categories/UIView+Debugging.m 
b/wikipedia/Categories/UIView+Debugging.m
index 3fa035d..7c054b7 100644
--- a/wikipedia/Categories/UIView+Debugging.m
+++ b/wikipedia/Categories/UIView+Debugging.m
@@ -12,7 +12,7 @@
     float(^color)() = ^float() {
         return (float)arc4random_uniform(100) / 100.0f;
     };
-    for (UIView *subView in self.subviews) {
+    for (UIView *subView in self.subviews.copy) {
         subView.layer.borderWidth = 1.0f;
         subView.layer.borderColor = [UIColor colorWithWhite:0.0f 
alpha:0.5f].CGColor;
         subView.layer.backgroundColor = [UIColor colorWithRed : color()
diff --git a/wikipedia/Categories/UIView+RemoveConstraints.m 
b/wikipedia/Categories/UIView+RemoveConstraints.m
index d167745..50a154d 100644
--- a/wikipedia/Categories/UIView+RemoveConstraints.m
+++ b/wikipedia/Categories/UIView+RemoveConstraints.m
@@ -7,7 +7,7 @@
 
 -(void)removeConstraintsOfViewFromView:(UIView *)view
 {
-    for (NSLayoutConstraint *c in [view.constraints copy]) {
+    for (NSLayoutConstraint *c in view.constraints.copy) {
         if (c.firstItem == self || c.secondItem == self) {
             [view removeConstraint: c];
         }
diff --git a/wikipedia/Categories/UIView+SearchSubviews.h 
b/wikipedia/Categories/UIView+SearchSubviews.h
index 6a7f940..aea20a6 100644
--- a/wikipedia/Categories/UIView+SearchSubviews.h
+++ b/wikipedia/Categories/UIView+SearchSubviews.h
@@ -7,4 +7,6 @@
 
 -(id)getFirstSubviewOfClass:(Class)class;
 
+-(NSArray *)getSubviewsOfClass:(Class)class;
+
 @end
diff --git a/wikipedia/Categories/UIView+SearchSubviews.m 
b/wikipedia/Categories/UIView+SearchSubviews.m
index 000984d..7ccd815 100644
--- a/wikipedia/Categories/UIView+SearchSubviews.m
+++ b/wikipedia/Categories/UIView+SearchSubviews.m
@@ -7,7 +7,7 @@
 
 -(id)getFirstSubviewOfClass:(Class)class
 {
-    for (id view in self.subviews) {
+    for (id view in self.subviews.copy) {
         if([view isMemberOfClass:class]){
             return view;
         }
@@ -15,4 +15,15 @@
     return nil;
 }
 
+-(NSArray *)getSubviewsOfClass:(Class)class
+{
+    NSMutableArray *output = @[].mutableCopy;
+    for (id view in self.subviews.copy) {
+        if([view isMemberOfClass:class]){
+            [output addObject:view];
+        }
+    }
+    return output;
+}
+
 @end
diff --git a/wikipedia/Categories/UIViewController+HideKeyboard.m 
b/wikipedia/Categories/UIViewController+HideKeyboard.m
index 45893a2..adffc3a 100644
--- a/wikipedia/Categories/UIViewController+HideKeyboard.m
+++ b/wikipedia/Categories/UIViewController+HideKeyboard.m
@@ -16,7 +16,7 @@
 -(void)recurseSubVCs
 {
     [self recurseSubviewsOfView:self.view];
-    for (UIViewController *subVC in self.childViewControllers) {
+    for (UIViewController *subVC in self.childViewControllers.copy) {
         if (subVC.presentedViewController) {
             [subVC.presentedViewController recurseSubVCs];
         }
@@ -35,7 +35,7 @@
             }
         }
     }
-    for (UIView *subView in view.subviews) {
+    for (UIView *subView in view.subviews.copy) {
         [self recurseSubviewsOfView:subView];
     }
 }
diff --git a/wikipedia/Categories/UIViewController+SearchChildViewControllers.m 
b/wikipedia/Categories/UIViewController+SearchChildViewControllers.m
index 42e1c68..3989ce6 100644
--- a/wikipedia/Categories/UIViewController+SearchChildViewControllers.m
+++ b/wikipedia/Categories/UIViewController+SearchChildViewControllers.m
@@ -7,7 +7,7 @@
 
 -(id)searchForChildViewControllerOfClass:(Class)aClass
 {
-    for (UIViewController *vc in self.childViewControllers) {
+    for (UIViewController *vc in self.childViewControllers.copy) {
         if ([vc isMemberOfClass:aClass]) return vc;
     }
     return nil;
diff --git a/wikipedia/Categories/UIWebView+HideScrollGradient.m 
b/wikipedia/Categories/UIWebView+HideScrollGradient.m
index 0c38090..4dbae66 100644
--- a/wikipedia/Categories/UIWebView+HideScrollGradient.m
+++ b/wikipedia/Categories/UIWebView+HideScrollGradient.m
@@ -8,7 +8,7 @@
 -(void)hideScrollGradient
 {
     if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) return;
-    for (UIView *view in self.scrollView.subviews) {
+    for (UIView *view in self.scrollView.subviews.copy) {
         if ([view isKindOfClass:[UIImageView class]]) {
             view.hidden = YES;
         }
diff --git a/wikipedia/TabularScrollView/TabularScrollView.m 
b/wikipedia/TabularScrollView/TabularScrollView.m
index 09452b1..588d05b 100644
--- a/wikipedia/TabularScrollView/TabularScrollView.m
+++ b/wikipedia/TabularScrollView/TabularScrollView.m
@@ -112,6 +112,7 @@
     
     if([sender isKindOfClass:[UIGestureRecognizer class]]){
         UIGestureRecognizer *recognizer = (UIGestureRecognizer *)sender;
+        if (recognizer.state != UIGestureRecognizerStateEnded) return;
         tappedView = recognizer.view;
         CGPoint loc = [recognizer locationInView:tappedView];
         tappedChildView = [tappedView hitTest:loc withEvent:nil];
diff --git a/wikipedia/View 
Controllers/AccountCreation/AccountCreationViewController.m b/wikipedia/View 
Controllers/AccountCreation/AccountCreationViewController.m
index 8f71c1c..ffe9272 100644
--- a/wikipedia/View Controllers/AccountCreation/AccountCreationViewController.m
+++ b/wikipedia/View Controllers/AccountCreation/AccountCreationViewController.m
@@ -153,11 +153,13 @@
     self.emailField.textAlignment = [WikipediaAppUtils rtlSafeAlignment];
 }
 
-- (void)loginButtonPushed:(id)sender
+- (void)loginButtonPushed:(UITapGestureRecognizer *)recognizer
 {
-    [self performModalSequeWithID: @"modal_segue_show_login"
-                  transitionStyle: UIModalTransitionStyleCoverVertical
-                            block: nil];
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        [self performModalSequeWithID: @"modal_segue_show_login"
+                      transitionStyle: UIModalTransitionStyleCoverVertical
+                                block: nil];
+    }
 }
 
 -(NSAttributedString *)getAttributedPlaceholderForString:(NSString *)string
@@ -350,8 +352,7 @@
 {
     self.captchaViewController.captchaTextBox.text = @"";
 
-    [self showAlert:MWLocalizedString(@"account-creation-captcha-obtaining", 
nil)];
-    [self fadeAlert];
+    [self showAlert:MWLocalizedString(@"account-creation-captcha-obtaining", 
nil) type:ALERT_TYPE_TOP duration:1];
 
     CaptchaResetOp *captchaResetOp =
     [[CaptchaResetOp alloc] initWithDomain: [SessionSingleton 
sharedInstance].domain
@@ -381,7 +382,7 @@
                                [self fadeAlert];
                                
                            } errorBlock: ^(NSError *error){
-                               [self showAlert:error.localizedDescription];
+                               [self showAlert:error.localizedDescription 
type:ALERT_TYPE_TOP duration:-1];
                                
                            }];
     
@@ -424,14 +425,14 @@
     // Create detached loginVC just for logging in.
     LoginViewController *loginVC = [[LoginViewController alloc] init];
     
-    [self showAlert:MWLocalizedString(@"account-creation-logging-in", nil)];
+    [self showAlert:MWLocalizedString(@"account-creation-logging-in", nil) 
type:ALERT_TYPE_TOP duration:-1];
     
     [loginVC loginWithUserName:self.usernameField.text 
password:self.passwordField.text onSuccess:^{
 
         NSString *loggedInMessage = 
MWLocalizedString(@"main-menu-account-title-logged-in", nil);
         loggedInMessage = [loggedInMessage 
stringByReplacingOccurrencesOfString: @"$1"
                                                                      
withString: self.usernameField.text];
-        [self showAlert:loggedInMessage];
+        [self showAlert:loggedInMessage type:ALERT_TYPE_TOP duration:-1];
 
         if (onboardingVC) {
             [self popModalToRoot];
@@ -454,13 +455,13 @@
 
     // Verify passwords fields match.
     if (![self.passwordField.text 
isEqualToString:self.passwordRepeatField.text]) {
-        [self 
showAlert:MWLocalizedString(@"account-creation-passwords-mismatched", nil)];
+        [self 
showAlert:MWLocalizedString(@"account-creation-passwords-mismatched", nil) 
type:ALERT_TYPE_TOP duration:-1];
         isAleadySaving = NO;
         return;
     }
 
     // Save!
-    [self showAlert:MWLocalizedString(@"account-creation-saving", nil)];
+    [self showAlert:MWLocalizedString(@"account-creation-saving", nil) 
type:ALERT_TYPE_TOP duration:-1];
 
     AccountCreationOp *accountCreationOp =
     [[AccountCreationOp alloc] initWithDomain: [SessionSingleton 
sharedInstance].domain
@@ -478,8 +479,7 @@
                                   [self.funnel logSuccess];
 
                                   dispatch_async(dispatch_get_main_queue(), 
^(){
-                                      [self showAlert:result];
-                                      [self fadeAlert];
+                                      [self showAlert:result 
type:ALERT_TYPE_TOP duration:1];
                                       [self performSelector:@selector(login) 
withObject:nil afterDelay:0.6f];
                                       isAleadySaving = NO;
                                   });
@@ -490,7 +490,7 @@
                                   isAleadySaving = NO;
                                   
                               } errorBlock: ^(NSError *error){
-                                  [self showAlert:error.localizedDescription];
+                                  [self showAlert:error.localizedDescription 
type:ALERT_TYPE_TOP duration:-1];
 
                                   [self.funnel 
logError:error.localizedDescription];
 
@@ -522,7 +522,7 @@
                                         isAleadySaving = NO;
                                     }
                                         errorBlock: ^(NSError *error){
-                                            [self 
showAlert:error.localizedDescription];
+                                            [self 
showAlert:error.localizedDescription type:ALERT_TYPE_TOP duration:-1];
                                             isAleadySaving = NO;
                                         }];
 
diff --git a/wikipedia/View Controllers/Languages/LanguagesViewController.m 
b/wikipedia/View Controllers/Languages/LanguagesViewController.m
index 35fd6df..4c6fd76 100644
--- a/wikipedia/View Controllers/Languages/LanguagesViewController.m
+++ b/wikipedia/View Controllers/Languages/LanguagesViewController.m
@@ -176,7 +176,7 @@
 
 -(void)downloadLangLinkData
 {
-    [self showAlert:MWLocalizedString(@"article-languages-downloading", nil)];
+    [self showAlert:MWLocalizedString(@"article-languages-downloading", nil) 
type:ALERT_TYPE_TOP duration:-1];
     AssetsFile *assetsFile = [[AssetsFile alloc] 
initWithFile:ASSETS_FILE_LANGUAGES];
 
     DownloadLangLinksOp *langLinksOp =
@@ -199,7 +199,7 @@
                                       
                                   } errorBlock: ^(NSError *error){
                                       //NSString *errorMsg = 
error.localizedDescription;
-                                      [self 
showAlert:error.localizedDescription];
+                                      [self 
showAlert:error.localizedDescription type:ALERT_TYPE_TOP duration:-1];
                                       
                                   }];
     
diff --git a/wikipedia/View Controllers/Login/LoginViewController.m 
b/wikipedia/View Controllers/Login/LoginViewController.m
index f6347c7..11d9613 100644
--- a/wikipedia/View Controllers/Login/LoginViewController.m
+++ b/wikipedia/View Controllers/Login/LoginViewController.m
@@ -191,8 +191,7 @@
                       NSString *loggedInMessage = 
MWLocalizedString(@"main-menu-account-title-logged-in", nil);
                       loggedInMessage = [loggedInMessage 
stringByReplacingOccurrencesOfString: @"$1"
                                                                                
    withString: self.usernameField.text];
-                      [self showAlert:loggedInMessage];
-                      [self fadeAlert];
+                      [self showAlert:loggedInMessage type:ALERT_TYPE_TOP 
duration:1.0f];
 
                       [self performSelector:(onboardingVC ? 
@selector(popModalToRoot) : @selector(popModal)) withObject:nil 
afterDelay:1.2f];
                       
@@ -255,7 +254,7 @@
                           [SessionSingleton 
sharedInstance].keychainCredentials.password = password;
                           
                           //NSString *result = 
loginResult[@"login"][@"result"];
-                          [self showAlert:loginStatus];
+                          [self showAlert:loginStatus type:ALERT_TYPE_TOP 
duration:-1];
                           
                           [[NSOperationQueue mainQueue] 
addOperationWithBlock:successBlock];
                           
@@ -266,14 +265,14 @@
                           
                       } cancelledBlock: ^(NSError *error){
                           
-                          [self showAlert:error.localizedDescription];
+                          [self showAlert:error.localizedDescription 
type:ALERT_TYPE_TOP duration:-1];
 
                           [[NSOperationQueue mainQueue] 
addOperationWithBlock:failBlock];
 
                           
                       } errorBlock: ^(NSError *error){
                           
-                          [self showAlert:error.localizedDescription];
+                          [self showAlert:error.localizedDescription 
type:ALERT_TYPE_TOP duration:-1];
 
                           [[NSOperationQueue mainQueue] 
addOperationWithBlock:failBlock];
 
@@ -297,7 +296,7 @@
                                
                            } errorBlock: ^(NSError *error){
                                
-                               [self showAlert:error.localizedDescription];
+                               [self showAlert:error.localizedDescription 
type:ALERT_TYPE_TOP duration:-1];
 
                                [[NSOperationQueue mainQueue] 
addOperationWithBlock:failBlock];
 
@@ -338,16 +337,18 @@
      ];
 }
 
-- (void)createAccountButtonPushed:(id)sender
+- (void)createAccountButtonPushed:(UITapGestureRecognizer *)recognizer
 {
-    [self.funnel logCreateAccountAttempt];
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        [self.funnel logCreateAccountAttempt];
 
-    [self performModalSequeWithID: @"modal_segue_show_create_account"
-                  transitionStyle: UIModalTransitionStyleCoverVertical
-                            block: ^(AccountCreationViewController 
*createAcctVC){
-                                createAcctVC.funnel = [[CreateAccountFunnel 
alloc] init];
-                                [createAcctVC.funnel 
logStartFromLogin:self.funnel.loginSessionToken];
-                            }];
+        [self performModalSequeWithID: @"modal_segue_show_create_account"
+                      transitionStyle: UIModalTransitionStyleCoverVertical
+                                block: ^(AccountCreationViewController 
*createAcctVC){
+                                    createAcctVC.funnel = 
[[CreateAccountFunnel alloc] init];
+                                    [createAcctVC.funnel 
logStartFromLogin:self.funnel.loginSessionToken];
+                                }];
+    }
 }
 
 @end
diff --git a/wikipedia/View 
Controllers/Navigation/Bottom/BottomMenuViewController.m b/wikipedia/View 
Controllers/Navigation/Bottom/BottomMenuViewController.m
index f820e84..1a9b552 100644
--- a/wikipedia/View Controllers/Navigation/Bottom/BottomMenuViewController.m
+++ b/wikipedia/View Controllers/Navigation/Bottom/BottomMenuViewController.m
@@ -21,6 +21,9 @@
 #import "Defines.h"
 #import "WikipediaAppUtils.h"
 #import "WMF_Colors.h"
+#import "UIViewController+ModalPresent.h"
+#import "UIViewController+ModalsSearch.h"
+#import "UIViewController+ModalPop.h"
 
 typedef NS_ENUM(NSInteger, BottomMenuItemTag) {
     BOTTOM_MENU_BUTTON_UNKNOWN,
@@ -98,6 +101,12 @@
     self.view.backgroundColor = CHROME_COLOR;
 
     [self addTapRecognizersToAllButtons];
+    
+    UILongPressGestureRecognizer *longPressRecognizer =
+    [[UILongPressGestureRecognizer alloc] initWithTarget: self
+                                                  action: 
@selector(saveButtonLongPressed:)];
+    longPressRecognizer.minimumPressDuration = 0.5f;
+    [self.saveButton addGestureRecognizer:longPressRecognizer];
 }
 
 -(void)addTapRecognizersToAllButtons
@@ -111,19 +120,21 @@
 
 #pragma mark Bottom bar button methods
 
-- (void)buttonPushed:(UITapGestureRecognizer *)sender
+- (void)buttonPushed:(UITapGestureRecognizer *)recognizer
 {
-    // If the tapped item was a button, first animate it briefly, then perform 
action.
-    if([sender.view isKindOfClass:[WikiGlyphButton class]]){
-        WikiGlyphButton *button = (WikiGlyphButton *)sender.view;
-        if (!button.enabled)return;
-        CGFloat animationScale = 1.25f;
-        [button.label animateAndRewindXF: 
CATransform3DMakeScale(animationScale, animationScale, 1.0f)
-                              afterDelay: 0.0
-                                duration: 0.06f
-                                    then: ^{
-                                        [self performActionForButton:button];
-                                    }];
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        // If the tapped item was a button, first animate it briefly, then 
perform action.
+        if([recognizer.view isKindOfClass:[WikiGlyphButton class]]){
+            WikiGlyphButton *button = (WikiGlyphButton *)recognizer.view;
+            if (!button.enabled)return;
+            CGFloat animationScale = 1.25f;
+            [button.label animateAndRewindXF: 
CATransform3DMakeScale(animationScale, animationScale, 1.0f)
+                                  afterDelay: 0.0
+                                    duration: 0.06f
+                                        then: ^{
+                                            [self 
performActionForButton:button];
+                                        }];
+        }
     }
 }
 
@@ -145,6 +156,15 @@
             break;
         default:
             break;
+    }
+}
+
+-(void)saveButtonLongPressed:(UILongPressGestureRecognizer *)recognizer
+{
+    if (recognizer.state == UIGestureRecognizerStateBegan){
+        [self performModalSequeWithID: @"modal_segue_show_saved_pages"
+                      transitionStyle: UIModalTransitionStyleCoverVertical
+                                block: nil];
     }
 }
 
@@ -211,6 +231,8 @@
 
         WebViewController *webVC = [NAV 
searchNavStackForViewControllerOfClass:[WebViewController class]];
 
+        [webVC showAlert:history.article.titleObj.text type:ALERT_TYPE_BOTTOM 
duration:0.8];
+
         [webVC navigateToPage: history.article.titleObj
                       domain: history.article.domain
              discoveryMethod: DISCOVERY_METHOD_BACKFORWARD
@@ -226,6 +248,8 @@
 
         WebViewController *webVC = [NAV 
searchNavStackForViewControllerOfClass:[WebViewController class]];
 
+        [webVC showAlert:history.article.titleObj.text type:ALERT_TYPE_BOTTOM 
duration:0.8];
+
         [webVC navigateToPage: history.article.titleObj
                       domain: history.article.domain
              discoveryMethod: DISCOVERY_METHOD_BACKFORWARD
diff --git a/wikipedia/View 
Controllers/Navigation/Primary/PrimaryMenuViewController.m b/wikipedia/View 
Controllers/Navigation/Primary/PrimaryMenuViewController.m
index 0a1ae7a..7e1f577 100644
--- a/wikipedia/View Controllers/Navigation/Primary/PrimaryMenuViewController.m
+++ b/wikipedia/View Controllers/Navigation/Primary/PrimaryMenuViewController.m
@@ -82,7 +82,7 @@
 
     [self addTableHeaderView];
     
-    [self.moreButton addGestureRecognizer:[[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(moreButtonTapped)]];
+    [self.moreButton addGestureRecognizer:[[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(moreButtonTapped:)]];
 }
 
 -(void)addTableHeaderView
@@ -243,9 +243,11 @@
     [self animateView:cell thenPerformActionForItem:tagNumber.integerValue];
 }
 
--(void)moreButtonTapped
+-(void)moreButtonTapped:(UITapGestureRecognizer *)recognizer
 {
-    [self animateView:self.moreButton 
thenPerformActionForItem:PRIMARY_MENU_ITEM_MORE];
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        [self animateView:self.moreButton 
thenPerformActionForItem:PRIMARY_MENU_ITEM_MORE];
+    }
 }
 
 -(void)animateView:(UIView *)view 
thenPerformActionForItem:(PrimaryMenuItemTag)tag
@@ -271,13 +273,13 @@
         }
             break;
         case PRIMARY_MENU_ITEM_RANDOM: {
-            //[self showAlert:MWLocalizedString(@"fetching-random-article", 
nil)];
+            //[self showAlert:MWLocalizedString(@"fetching-random-article", 
nil) type:ALERT_TYPE_TOP duration:-1];
             [self fetchRandomArticle];
             [self popModal];
         }
             break;
         case PRIMARY_MENU_ITEM_TODAY: {
-            //[self showAlert:MWLocalizedString(@"fetching-today-article", 
nil)];
+            //[self showAlert:MWLocalizedString(@"fetching-today-article", 
nil) type:ALERT_TYPE_TOP duration:-1];
             [NAV loadTodaysArticle];
             [self popModal];
         }
@@ -328,7 +330,7 @@
                                                  } cancelledBlock: ^(NSError 
*errorCancel) {
                                                     [self fadeAlert];
                                                  } errorBlock: ^(NSError 
*error) {
-                                                    [self 
showAlert:error.localizedDescription];
+                                                    [self 
showAlert:error.localizedDescription type:ALERT_TYPE_TOP duration:-1];
                                                  }];
 
     [[QueuesSingleton sharedInstance].randomArticleQ 
addOperation:downloadTitlesForRandomArticlesOp];
diff --git a/wikipedia/View 
Controllers/Navigation/Secondary/SecondaryMenuViewController.m b/wikipedia/View 
Controllers/Navigation/Secondary/SecondaryMenuViewController.m
index cc4b487..9c2cef2 100644
--- a/wikipedia/View 
Controllers/Navigation/Secondary/SecondaryMenuViewController.m
+++ b/wikipedia/View 
Controllers/Navigation/Secondary/SecondaryMenuViewController.m
@@ -689,8 +689,7 @@
 
     NSDictionary *selectedLangInfo = [notification userInfo];
     
-    [self showAlert:MWLocalizedString(@"main-menu-language-selection-saved", 
nil)];
-    [self fadeAlert];
+    [self showAlert:MWLocalizedString(@"main-menu-language-selection-saved", 
nil) type:ALERT_TYPE_TOP duration:1];
     
     [self switchPreferredLanguageToId:selectedLangInfo[@"code"] 
name:selectedLangInfo[@"name"]];
     
diff --git a/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m 
b/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m
index 1683588..d02d89a 100644
--- a/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m
+++ b/wikipedia/View Controllers/Navigation/Top/TopMenuViewController.m
@@ -493,6 +493,9 @@
 {
     UIView *tappedView = nil;
     if([sender isKindOfClass:[UIGestureRecognizer class]]){
+        // We only want to take action when the tap recognizer is in Ended 
state.
+        if (((UIGestureRecognizer *)sender).state != 
UIGestureRecognizerStateEnded) return;
+
         tappedView = ((UIGestureRecognizer *)sender).view;
     }else{
         tappedView = sender;
diff --git a/wikipedia/View Controllers/Nearby/NearbyViewController.m 
b/wikipedia/View Controllers/Nearby/NearbyViewController.m
index a1aca85..649cd61 100644
--- a/wikipedia/View Controllers/Nearby/NearbyViewController.m
+++ b/wikipedia/View Controllers/Nearby/NearbyViewController.m
@@ -231,7 +231,7 @@
             break;
     }
     
-    [self showAlert:errorMessage];
+    [self showAlert:errorMessage type:ALERT_TYPE_TOP duration:-1];
 }
 
 -(void)downloadData
@@ -239,12 +239,12 @@
     CLLocationDegrees lat1 = self.deviceLocation.coordinate.latitude;
     CLLocationDegrees long1 = self.deviceLocation.coordinate.longitude;
 
-    [self showAlert:MWLocalizedString(@"nearby-loading", nil)];
+    [self showAlert:MWLocalizedString(@"nearby-loading", nil) 
type:ALERT_TYPE_TOP duration:-1];
     
     NearbyOp *nearbyOp = [[NearbyOp alloc] initWithLatitude:lat1 
longitude:long1 completionBlock:^(NSArray *result){
         
         [[NSOperationQueue mainQueue] addOperationWithBlock: ^ {
-            //[self showAlert:MWLocalizedString(@"nearby-loaded", nil)];
+            //[self showAlert:MWLocalizedString(@"nearby-loaded", nil) 
type:ALERT_TYPE_TOP duration:-1];
             [self fadeAlert];
             
             self.nearbyDataArray = @[result];
@@ -260,11 +260,11 @@
         
     } cancelledBlock:^(NSError *error){
         NSLog(@"nearby op error = %@", error);
-        //[self showAlert:error.localizedDescription];
+        //[self showAlert:error.localizedDescription type:ALERT_TYPE_TOP 
duration:-1];
 
     } errorBlock:^(NSError *error){
         NSLog(@"nearby op error = %@", error);
-        [self showAlert:error.localizedDescription];
+        [self showAlert:error.localizedDescription type:ALERT_TYPE_TOP 
duration:-1];
     }];
    
     [[QueuesSingleton sharedInstance].nearbyQ cancelAllOperations];
diff --git a/wikipedia/View Controllers/Onboarding/OnboardingViewController.m 
b/wikipedia/View Controllers/Onboarding/OnboardingViewController.m
index 117d508..94904b2 100644
--- a/wikipedia/View Controllers/Onboarding/OnboardingViewController.m
+++ b/wikipedia/View Controllers/Onboarding/OnboardingViewController.m
@@ -117,11 +117,11 @@
     self.loginButton.layer.cornerRadius = cornerRadius;
     self.createAccountButton.layer.cornerRadius = cornerRadius;
     
-    [self.skipButton addGestureRecognizer:[[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(skipButtonTapped)]];
+    [self.skipButton addGestureRecognizer:[[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(skipButtonTapped:)]];
 
-    [self.createAccountButton addGestureRecognizer:[[UITapGestureRecognizer 
alloc] initWithTarget:self action:@selector(createAccountButtonTapped)]];
+    [self.createAccountButton addGestureRecognizer:[[UITapGestureRecognizer 
alloc] initWithTarget:self action:@selector(createAccountButtonTapped:)]];
 
-    [self.loginButton addGestureRecognizer:[[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(loginButtonTapped)]];
+    [self.loginButton addGestureRecognizer:[[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(loginButtonTapped:)]];
 
     self.createAccountButton.text = 
MWLocalizedString(@"onboarding-create-account", nil);
     self.skipButton.text = MWLocalizedString(@"onboarding-skip", nil);
@@ -231,23 +231,29 @@
                         substitutionAttributes: 
@[@{NSForegroundColorAttributeName : WMF_COLOR_BLUE}]];
 }
 
--(void)createAccountButtonTapped
+-(void)createAccountButtonTapped:(UITapGestureRecognizer *)recognizer
 {
-    [self performModalSequeWithID: @"modal_segue_show_create_account"
-                  transitionStyle: UIModalTransitionStyleCoverVertical
-                            block: nil];
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        [self performModalSequeWithID: @"modal_segue_show_create_account"
+                      transitionStyle: UIModalTransitionStyleCoverVertical
+                                block: nil];
+    }
 }
 
--(void)loginButtonTapped
+-(void)loginButtonTapped:(UITapGestureRecognizer *)recognizer
 {
-    [self performModalSequeWithID: @"modal_segue_show_login"
-                  transitionStyle: UIModalTransitionStyleCoverVertical
-                            block: nil];
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        [self performModalSequeWithID: @"modal_segue_show_login"
+                      transitionStyle: UIModalTransitionStyleCoverVertical
+                                block: nil];
+    }
 }
 
--(void)skipButtonTapped
+-(void)skipButtonTapped:(UITapGestureRecognizer *)recognizer
 {
-    [self hide];
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        [self hide];
+    }
 }
 
 - (void)didReceiveMemoryWarning
diff --git a/wikipedia/View Controllers/PageHistory/PageHistoryViewController.m 
b/wikipedia/View Controllers/PageHistory/PageHistoryViewController.m
index df077bb..75915f1 100644
--- a/wikipedia/View Controllers/PageHistory/PageHistoryViewController.m
+++ b/wikipedia/View Controllers/PageHistory/PageHistoryViewController.m
@@ -103,7 +103,7 @@
     
     __weak PageHistoryViewController *weakSelf = self;
 
-    [self showAlert:MWLocalizedString(@"page-history-downloading", nil)];
+    [self showAlert:MWLocalizedString(@"page-history-downloading", nil) 
type:ALERT_TYPE_TOP duration:-1];
 
     PageHistoryOp *pageHistoryOp =
     [[PageHistoryOp alloc] initWithDomain: [SessionSingleton 
sharedInstance].currentArticleDomain
@@ -121,7 +121,7 @@
                                [self fadeAlert];
                            }
                                errorBlock: ^(NSError *error){
-                                   [self showAlert:error.localizedDescription];
+                                   [self showAlert:error.localizedDescription 
type:ALERT_TYPE_TOP duration:-1];
                                }];
     pageHistoryOp.delegate = self;
     [[QueuesSingleton sharedInstance].pageHistoryQ addOperation:pageHistoryOp];
diff --git a/wikipedia/View Controllers/Preview/PreviewAndSaveViewController.m 
b/wikipedia/View Controllers/Preview/PreviewAndSaveViewController.m
index 14d15cb..7d98d9f 100644
--- a/wikipedia/View Controllers/Preview/PreviewAndSaveViewController.m
+++ b/wikipedia/View Controllers/Preview/PreviewAndSaveViewController.m
@@ -158,7 +158,7 @@
     
     self.previewLabel.text = 
MWLocalizedString(@"navbar-title-mode-edit-wikitext-preview", nil);
     
-    [self.previewLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(previewLabelTapped)]];
+    [self.previewLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(previewLabelTapped:)]];
     
     //self.saveAutomaticallyIfSignedIn = NO;
     
@@ -198,9 +198,11 @@
     [self preview];
 }
 
--(void)previewLabelTapped
+-(void)previewLabelTapped:(UITapGestureRecognizer *)recognizer
 {
-    [self.scrollView scrollSubViewToTop:self.previewLabel animated:YES];
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        [self.scrollView scrollSubViewToTop:self.previewLabel animated:YES];
+    }
 }
 
 -(void)dealloc
@@ -298,36 +300,39 @@
 
 -(void)buttonTapped:(UIGestureRecognizer *)recognizer
 {
-    MenuButton *tappedButton = (MenuButton *)recognizer.view;
-    
-    NSString *summaryKey;
-    switch (tappedButton.tag) {
-        case CANNED_SUMMARY_TYPOS:
-            summaryKey = @"typo";
-            break;
-        case CANNED_SUMMARY_GRAMMAR:
-            summaryKey = @"grammar";
-            break;
-        case CANNED_SUMMARY_LINKS:
-            summaryKey = @"links";
-            break;
-        case CANNED_SUMMARY_OTHER:
-            summaryKey = @"other";
-            break;
-        default:
-            NSLog(@"unrecognized button");
-    }
-    [self.funnel logEditSummaryTap:summaryKey];
-
-    switch (tappedButton.tag) {
-        case CANNED_SUMMARY_OTHER:
-            [self showSummaryOverlay];
-            break;
-            
-        default:
-            tappedButton.enabled = !tappedButton.enabled;
-            
-            break;
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        
+        MenuButton *tappedButton = (MenuButton *)recognizer.view;
+        
+        NSString *summaryKey;
+        switch (tappedButton.tag) {
+            case CANNED_SUMMARY_TYPOS:
+                summaryKey = @"typo";
+                break;
+            case CANNED_SUMMARY_GRAMMAR:
+                summaryKey = @"grammar";
+                break;
+            case CANNED_SUMMARY_LINKS:
+                summaryKey = @"links";
+                break;
+            case CANNED_SUMMARY_OTHER:
+                summaryKey = @"other";
+                break;
+            default:
+                NSLog(@"unrecognized button");
+        }
+        [self.funnel logEditSummaryTap:summaryKey];
+        
+        switch (tappedButton.tag) {
+            case CANNED_SUMMARY_OTHER:
+                [self showSummaryOverlay];
+                break;
+                
+            default:
+                tappedButton.enabled = !tappedButton.enabled;
+                
+                break;
+        }
     }
 }
 
@@ -390,14 +395,16 @@
 
 -(void)licenseLabelTapped:(UIGestureRecognizer *)recognizer
 {
-    // Call if user taps the blue "Log In" text in the CC text.
-    //self.saveAutomaticallyIfSignedIn = YES;
-    [self performModalSequeWithID: @"modal_segue_show_login"
-                  transitionStyle: UIModalTransitionStyleCoverVertical
-                            block: ^(LoginViewController *loginVC){
-                                loginVC.funnel = [[LoginFunnel alloc] init];
-                                [loginVC.funnel 
logStartFromEdit:self.funnel.editSessionToken];
-                            }];
+    if (recognizer.state == UIGestureRecognizerStateEnded) {        
+        // Call if user taps the blue "Log In" text in the CC text.
+        //self.saveAutomaticallyIfSignedIn = YES;
+        [self performModalSequeWithID: @"modal_segue_show_login"
+                      transitionStyle: UIModalTransitionStyleCoverVertical
+                                block: ^(LoginViewController *loginVC){
+                                    loginVC.funnel = [[LoginFunnel alloc] 
init];
+                                    [loginVC.funnel 
logStartFromEdit:self.funnel.editSessionToken];
+                                }];
+    }
 }
 
 -(void)highlightCaptchaSubmitButton:(BOOL)highlight
@@ -437,7 +444,7 @@
     if (isAleadyPreviewing) return;
     isAleadyPreviewing = YES;
 
-    [self showAlert:MWLocalizedString(@"wikitext-preview-changes", nil)];
+    [self showAlert:MWLocalizedString(@"wikitext-preview-changes", nil) 
type:ALERT_TYPE_TOP duration:-1];
     Section *section = (Section *)[articleDataContext_.mainContext 
objectWithID:self.sectionID];
 
     MWLanguageInfo *languageInfo = [MWLanguageInfo 
languageInfoForCode:section.article.domain];
@@ -470,13 +477,13 @@
         
     } cancelledBlock:^(NSError *error){
         NSString *errorMsg = error.localizedDescription;
-        [self showAlert:errorMsg];
+        [self showAlert:errorMsg type:ALERT_TYPE_TOP duration:-1];
         isAleadyPreviewing = NO;
         
     } errorBlock:^(NSError *error){
         NSString *errorMsg = error.localizedDescription;
         
-        [self showAlert:errorMsg];
+        [self showAlert:errorMsg type:ALERT_TYPE_TOP duration:-1];
         
         isAleadyPreviewing = NO;
     }];
@@ -518,7 +525,7 @@
 
     ArticleDataContextSingleton *articleDataContext_ = 
[ArticleDataContextSingleton sharedInstance];
 
-    [self showAlert:MWLocalizedString(@"wikitext-upload-save", nil)];
+    [self showAlert:MWLocalizedString(@"wikitext-upload-save", nil) 
type:ALERT_TYPE_TOP duration:-1];
     Section *section = (Section *)[articleDataContext_.mainContext 
objectWithID:self.sectionID];
 
     NSManagedObjectID *articleID = section.article.objectID;
@@ -546,13 +553,13 @@
 
     } cancelledBlock:^(NSError *error){
         NSString *errorMsg = error.localizedDescription;
-        [self showAlert:errorMsg];
+        [self showAlert:errorMsg type:ALERT_TYPE_TOP duration:-1];
         isAleadySaving = NO;
         
     } errorBlock:^(NSError *error){
         NSString *errorMsg = error.localizedDescription;
         
-        [self showAlert:errorMsg];
+        [self showAlert:errorMsg type:ALERT_TYPE_TOP duration:-1];
 
         switch (error.code) {
             case WIKITEXT_UPLOAD_ERROR_NEEDS_CAPTCHA:
@@ -577,7 +584,7 @@
                                                                                
 withObject: nil
                                                                                
 afterDelay: 0.4f];
 
-                                [self.captchaViewController 
showAlert:errorMsg];
+                                [self.captchaViewController showAlert:errorMsg 
type:ALERT_TYPE_TOP duration:-1];
 
                                 
self.captchaViewController.captchaImageView.image = nil;
 
@@ -693,7 +700,7 @@
                             
                         } errorBlock: ^(NSError *error){
                             
-                            [self showAlert:error.localizedDescription];
+                            [self showAlert:error.localizedDescription 
type:ALERT_TYPE_TOP duration:-1];
                             isAleadySaving = NO;
                             
                         }];
diff --git a/wikipedia/View Controllers/Preview/PreviewLicenseView.m 
b/wikipedia/View Controllers/Preview/PreviewLicenseView.m
index 7824bf4..1153bef 100644
--- a/wikipedia/View Controllers/Preview/PreviewLicenseView.m
+++ b/wikipedia/View Controllers/Preview/PreviewLicenseView.m
@@ -102,10 +102,11 @@
      ];
 }
 
--(void)termsLicenseLabelTapped:(UILabel *)label
+-(void)termsLicenseLabelTapped:(UITapGestureRecognizer *)recognizer
 {
-    // @todo on iPad position this against the view
-    [self.sheet showInView:ROOT.view];
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        [self.sheet showInView:ROOT.view];
+    }
 }
 
 -(UIActionSheet *)sheet
diff --git a/wikipedia/View Controllers/References/ReferencesVC.m 
b/wikipedia/View Controllers/References/ReferencesVC.m
index afb76b1..daab394 100644
--- a/wikipedia/View Controllers/References/ReferencesVC.m
+++ b/wikipedia/View Controllers/References/ReferencesVC.m
@@ -141,13 +141,13 @@
     self.prevButton.hidden = YES;
     [self.topContainerView addSubview:self.prevButton];
 
-    UITapGestureRecognizer *prevTap = [[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(prevButtonTap)];
+    UITapGestureRecognizer *prevTap = [[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(prevButtonTap:)];
     [self.prevButton addGestureRecognizer:prevTap];
 
-    UITapGestureRecognizer *nextTap = [[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(nextButtonTap)];
+    UITapGestureRecognizer *nextTap = [[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(nextButtonTap:)];
     [self.nextButton addGestureRecognizer:nextTap];
 
-    UITapGestureRecognizer *xTap = [[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(xButtonTap)];
+    UITapGestureRecognizer *xTap = [[UITapGestureRecognizer alloc] 
initWithTarget:self action:@selector(xButtonTap:)];
     [self.xButton addGestureRecognizer:xTap];
 
     //self.nextButton.layer.borderWidth = 1;
@@ -181,9 +181,11 @@
     //self.topContainerView.layer.borderColor = [UIColor whiteColor].CGColor;
 }
 
--(void)xButtonTap
+-(void)xButtonTap:(UITapGestureRecognizer *)recognizer
 {
-    [self.webVC referencesHide];
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        [self.webVC referencesHide];
+    }
 }
 
 -(void)setupConstraints
@@ -459,40 +461,46 @@
     }
 }
 
--(void)prevButtonTap
+-(void)prevButtonTap:(UITapGestureRecognizer *)recognizer
 {
-    if (!self.prevButton.enabled) return;
-
-    BOOL isRTL = [WikipediaAppUtils isDeviceLanguageRTL];
-
-    UIPageViewControllerNavigationDirection dir = isRTL
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        
+        if (!self.prevButton.enabled) return;
+        
+        BOOL isRTL = [WikipediaAppUtils isDeviceLanguageRTL];
+        
+        UIPageViewControllerNavigationDirection dir = isRTL
         ?
         UIPageViewControllerNavigationDirectionForward
         :
         UIPageViewControllerNavigationDirectionReverse;
-    
-    [self setViewControllers: @[[self 
viewControllerAtIndex:(--self.topPageControl.currentPage)]]
-                   direction: dir
-                    animated: YES
-                  completion: nil];
+        
+        [self setViewControllers: @[[self 
viewControllerAtIndex:(--self.topPageControl.currentPage)]]
+                       direction: dir
+                        animated: YES
+                      completion: nil];
+    }
 }
 
--(void)nextButtonTap
+-(void)nextButtonTap:(UITapGestureRecognizer *)recognizer
 {
-    if (!self.nextButton.enabled) return;
-
-    BOOL isRTL = [WikipediaAppUtils isDeviceLanguageRTL];
-
-    UIPageViewControllerNavigationDirection dir = isRTL
+    if (recognizer.state == UIGestureRecognizerStateEnded) {
+        
+        if (!self.nextButton.enabled) return;
+        
+        BOOL isRTL = [WikipediaAppUtils isDeviceLanguageRTL];
+        
+        UIPageViewControllerNavigationDirection dir = isRTL
         ?
         UIPageViewControllerNavigationDirectionReverse
         :
         UIPageViewControllerNavigationDirectionForward;
-
-    [self setViewControllers: @[[self 
viewControllerAtIndex:(++self.topPageControl.currentPage)]]
-                   direction: dir
-                    animated: YES
-                  completion: nil];
+        
+        [self setViewControllers: @[[self 
viewControllerAtIndex:(++self.topPageControl.currentPage)]]
+                       direction: dir
+                        animated: YES
+                      completion: nil];
+    }
 }
 
 /*
diff --git a/wikipedia/View Controllers/SearchResults/SearchResultsController.m 
b/wikipedia/View Controllers/SearchResults/SearchResultsController.m
index dd2b099..cfe10db 100644
--- a/wikipedia/View Controllers/SearchResults/SearchResultsController.m
+++ b/wikipedia/View Controllers/SearchResults/SearchResultsController.m
@@ -135,7 +135,7 @@
     [self clearSearchResults];
     
     // Show "Searching..." message.
-    [self showAlert:MWLocalizedString(@"search-searching", nil)];
+    [self showAlert:MWLocalizedString(@"search-searching", nil) 
type:ALERT_TYPE_TOP duration:-1];
     
     // Search for titles op.
     SearchOp *searchOp =
@@ -160,7 +160,7 @@
                              
                          } errorBlock: ^(NSError *error){
                              
-                             [self showAlert:error.localizedDescription];
+                             [self showAlert:error.localizedDescription 
type:ALERT_TYPE_TOP duration:-1];
                              
                          }];
     
diff --git a/wikipedia/View 
Controllers/SectionEditor/SectionEditorViewController.m b/wikipedia/View 
Controllers/SectionEditor/SectionEditorViewController.m
index 055dfbe..b7826c0 100644
--- a/wikipedia/View Controllers/SectionEditor/SectionEditorViewController.m
+++ b/wikipedia/View Controllers/SectionEditor/SectionEditorViewController.m
@@ -144,8 +144,7 @@
     switch (tappedItem.tag) {
         case NAVBAR_BUTTON_NEXT:
             if (![self changesMade]) {
-                [self 
showAlert:MWLocalizedString(@"wikitext-preview-changes-none", nil)];
-                [self fadeAlert];
+                [self 
showAlert:MWLocalizedString(@"wikitext-preview-changes-none", nil) 
type:ALERT_TYPE_TOP duration:1];
                 break;
             }
             [self preview];
@@ -173,7 +172,7 @@
 
 -(void)loadLatestWikiTextForSectionFromServer
 {
-    [self showAlert:MWLocalizedString(@"wikitext-downloading", nil)];
+    [self showAlert:MWLocalizedString(@"wikitext-downloading", nil) 
type:ALERT_TYPE_TOP duration:-1];
     Section *section = (Section *)[articleDataContext_.mainContext 
objectWithID:self.sectionID];
     NSString *domain = section.article.domain;
     self.protectionStatus = section.article.protectionStatus;
@@ -198,12 +197,9 @@
                 } else {
                     msg = MWLocalizedString(@"page_protected_other", nil);
                 }
-                [self showAlert:msg];
-                
-                [self fadeAlert];
+                [self showAlert:msg type:ALERT_TYPE_TOP duration:1];
             } else {
-                [self 
showAlert:MWLocalizedString(@"wikitext-download-success", nil)];
-                [self fadeAlert];
+                [self 
showAlert:MWLocalizedString(@"wikitext-download-success", nil) 
type:ALERT_TYPE_TOP duration:1];
             }
             self.unmodifiedWikiText = revision;
             self.editTextView.attributedText = [self 
getAttributedString:revision];
@@ -220,11 +216,11 @@
         
     } cancelledBlock:^(NSError *error){
         NSString *errorMsg = error.localizedDescription;
-        [self showAlert:errorMsg];
+        [self showAlert:errorMsg type:ALERT_TYPE_TOP duration:-1];
         
     } errorBlock:^(NSError *error){
         NSString *errorMsg = error.localizedDescription;
-        [self showAlert:errorMsg];
+        [self showAlert:errorMsg type:ALERT_TYPE_TOP duration:-1];
         
     }];
 
diff --git a/wikipedia/View Controllers/TableOfContents/TOCViewController.m 
b/wikipedia/View Controllers/TableOfContents/TOCViewController.m
index d0838d0..eb8cb1e 100644
--- a/wikipedia/View Controllers/TableOfContents/TOCViewController.m
+++ b/wikipedia/View Controllers/TableOfContents/TOCViewController.m
@@ -242,11 +242,14 @@
 {
     // If tapped, go to section/image selection.
     if ([sender isMemberOfClass:[UITapGestureRecognizer class]]) {
-        [self deSelectAllCells];
-        [self unHighlightAllCells];
-        [self navigateToSelection: sender
-                         duration: TOC_SELECTION_SCROLL_DURATION];
-        [self.funnel logClick];
+        // We only want to take action when the tap recognizer is in Ended 
state.
+        if (((UITapGestureRecognizer *)sender).state == 
UIGestureRecognizerStateEnded){
+            [self deSelectAllCells];
+            [self unHighlightAllCells];
+            [self navigateToSelection: sender
+                             duration: TOC_SELECTION_SCROLL_DURATION];
+            [self.funnel logClick];
+        }
     }
 }
 
diff --git a/wikipedia/View Controllers/WebView/WebViewController.h 
b/wikipedia/View Controllers/WebView/WebViewController.h
index b085e0a..fb00508 100644
--- a/wikipedia/View Controllers/WebView/WebViewController.h
+++ b/wikipedia/View Controllers/WebView/WebViewController.h
@@ -14,6 +14,8 @@
 @property (nonatomic) BOOL referencesHidden;
 @property (nonatomic) BOOL scrollingToTop;
 
+@property (weak, nonatomic) BottomMenuViewController *bottomMenuViewController;
+
 -(void)referencesShow:(NSDictionary *)payload;
 -(void)referencesHide;
 
diff --git a/wikipedia/View Controllers/WebView/WebViewController.m 
b/wikipedia/View Controllers/WebView/WebViewController.m
index 1e393ad..f230cf5 100644
--- a/wikipedia/View Controllers/WebView/WebViewController.m
+++ b/wikipedia/View Controllers/WebView/WebViewController.m
@@ -57,6 +57,7 @@
 #import "WikiGlyphButton.h"
 #import "WikiGlyphLabel.h"
 #import "WikiGlyph_Chars_iOS.h"
+#import "NSString+FormattedAttributedString.h"
 
 //#import "UIView+Debugging.h"
 
@@ -115,7 +116,6 @@
 
 @property (nonatomic) BOOL unsafeToToggleTOC;
 
-@property (weak, nonatomic) BottomMenuViewController *bottomMenuViewController;
 @property (strong, nonatomic) ReferencesVC *referencesVC;
 @property (weak, nonatomic) IBOutlet UIView *referencesContainerView;
 
@@ -291,14 +291,14 @@
     //self.referencesContainerView.layer.borderColor = [UIColor 
redColor].CGColor;
 }
 
--(void)showAlert:(NSString *)alertText
+-(void)showAlert:(id)alertText type:(AlertType)type duration:(CGFloat)duration
 {
     if ([self tocDrawerIsOpen]) return;
 
     // Don't show alerts if onboarding onscreen.
     if ([self shouldShowOnboarding]) return;
 
-    [super showAlert:alertText];
+    [super showAlert:alertText type:type duration:duration];
 }
 
 -(void)viewDidAppear:(BOOL)animated
@@ -1087,8 +1087,27 @@
         if (!article) return;
         if (article.saved.count == 0) {
             // Save!
-            [self showAlert:MWLocalizedString(@"share-menu-page-saved", nil)];
-            [self fadeAlert];
+
+            // First show saved message.
+            NSString *savedMessage = 
MWLocalizedString(@"share-menu-page-saved", nil);
+            
+            CGFloat duration = 2.0;
+            BOOL AccessSavedPagesMessageShown = [[NSUserDefaults 
standardUserDefaults] boolForKey:@"AccessSavedPagesMessageShown"];
+            if (!AccessSavedPagesMessageShown) {
+                duration = -1;
+                [[NSUserDefaults standardUserDefaults] setObject:@YES 
forKey:@"AccessSavedPagesMessageShown"];
+                [[NSUserDefaults standardUserDefaults] synchronize];
+                savedMessage = [savedMessage stringByAppendingString:@"\n$2"];
+            }
+
+            NSAttributedString *attributedSavedMessage =
+            [savedMessage attributedStringWithAttributes: @{}
+                                     substitutionStrings: @[article.title, 
MWLocalizedString(@"share-menu-page-saved-access", nil)]
+                                  substitutionAttributes: 
@[@{NSFontAttributeName: [UIFont italicSystemFontOfSize:10]}, @{}]];
+
+            [self showAlert:attributedSavedMessage type:ALERT_TYPE_BOTTOM 
duration:duration];
+            
+            // Actually perform the save.
             Saved *saved = [NSEntityDescription 
insertNewObjectForEntityForName:@"Saved" 
inManagedObjectContext:articleDataContext_.mainContext];
             saved.dateSaved = [NSDate date];
             [article addSavedObject:saved];
@@ -1405,7 +1424,7 @@
     [self hideKeyboard];
     
     // Show loading message
-    //[self showAlert:MWLocalizedString(@"search-loading-section-zero", nil)];
+    //[self showAlert:MWLocalizedString(@"search-loading-section-zero", nil) 
type:ALERT_TYPE_TOP duration:-1];
 
     if (invalidateCache) [self invalidateCacheForPageTitle:title 
domain:domain];
     
@@ -1490,7 +1509,7 @@
         if (article.section.count > 0 && !article.needsRefresh.boolValue) {
             [self.tocVC setTocSectionDataForSections:article.section];
             [self displayArticle:articleID mode:DISPLAY_ALL_SECTIONS];
-            //[self 
showAlert:MWLocalizedString(@"search-loading-article-loaded", nil)];
+            //[self 
showAlert:MWLocalizedString(@"search-loading-article-loaded", nil) 
type:ALERT_TYPE_TOP duration:-1];
             [self fadeAlert];
             return;
         }
@@ -1565,14 +1584,14 @@
         }];
         
         [self displayArticle:articleID mode:DISPLAY_APPEND_NON_LEAD_SECTIONS];
-        //[self showAlert:MWLocalizedString(@"search-loading-article-loaded", 
nil)];
-        [self fadeAlert];
+        //[self showAlert:MWLocalizedString(@"search-loading-article-loaded", 
nil) type:ALERT_TYPE_TOP duration:-1];
+        //[self fadeAlert];
 
     } cancelledBlock:^(NSError *error){
         [self fadeAlert];
     } errorBlock:^(NSError *error){
         NSString *errorMsg = error.localizedDescription;
-        [self showAlert:errorMsg];
+        [self showAlert:errorMsg type:ALERT_TYPE_TOP duration:-1];
     }];
 
     remainingSectionsOp.delegate = self;
@@ -1722,7 +1741,7 @@
         }];
 
         [self displayArticle:articleID mode:DISPLAY_LEAD_SECTION];
-        //[self 
showAlert:MWLocalizedString(@"search-loading-section-remaining", nil)];
+        //[self 
showAlert:MWLocalizedString(@"search-loading-section-remaining", nil) 
type:ALERT_TYPE_TOP duration:-1];
 
     } cancelledBlock:^(NSError *error){
 
@@ -1734,7 +1753,7 @@
 
     } errorBlock:^(NSError *error){
         NSString *errorMsg = error.localizedDescription;
-        [self showAlert:errorMsg];
+        [self showAlert:errorMsg type:ALERT_TYPE_TOP duration:-1];
         if (articleID) {
             // Remove the article so it doesn't get saved.
             Article *article = (Article *)[articleDataContext_.mainContext 
objectWithID:articleID];
@@ -2019,7 +2038,7 @@
                      self.zeroStatusLabel.padding = UIEdgeInsetsMake(3, 10, 3, 
10);
                      self.zeroStatusLabel.backgroundColor = [UIColor 
colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.93];
 
-                     [self showAlert:title];
+                     [self showAlert:title type:ALERT_TYPE_TOP duration:-1];
                      [NAV promptFirstTimeZeroOnWithTitleIfAppropriate:title];
                  });
              }
@@ -2045,7 +2064,7 @@
             self.zeroStatusLabel.padding = UIEdgeInsetsZero;
         });
 
-        [self showAlert:warnVerbiage];
+        [self showAlert:warnVerbiage type:ALERT_TYPE_TOP duration:-1];
         [NAV promptZeroOff];
     }
 }
@@ -2082,13 +2101,7 @@
 {
     NSString *title = [SessionSingleton sharedInstance].currentArticleTitle;
     
-    return
-    ([QueuesSingleton sharedInstance].articleRetrievalQ.operationCount == 0)
-    &&
-    (![self tocDrawerIsOpen])
-    &&
-    (title && (title.length > 0))
-    ;
+    return (![self tocDrawerIsOpen]) && (title && (title.length > 0));
 }
 
 #pragma mark Data migration
diff --git a/wikipedia/assets/abusefilter.css b/wikipedia/assets/abusefilter.css
index 07bf36d..7015256 100644
--- a/wikipedia/assets/abusefilter.css
+++ b/wikipedia/assets/abusefilter.css
@@ -199,7 +199,7 @@
   font-size: .8em;
   line-height: 1.5;
   padding: 0 !important;
-  color: #777;
+  color: #555;
   width: auto !important;
 }
 .content .thumbborder {
@@ -283,7 +283,7 @@
 }
 a.external {
   background-image: 
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAVElEQVR42n3PgQkAIAhEUXdqJ3dqJ3e6IoTPUSQcgj4EQ5IlUiLE0Jil3PECXhcHGBhZ8kg4hwxAu3MZeCGeyFnAXp4hqNQPnt7QL0nADpD6wHccLvnAKksq8iiaAAAAAElFTkSuQmCC);
-  background-image: 
url(//bits.wikimedia.org/static-1.24wmf15/extensions/MobileApp/../MobileFrontend/less/content/images/external-link-ltr-icon.png?2014-07-24T17:20:00Z)!ie;
+  background-image: 
url(//bits.wikimedia.org/static-1.24wmf18/extensions/MobileApp/../MobileFrontend/less/content/images/external-link-ltr-icon.png?2014-08-21T15:38:20Z)!ie;
   /* We don't need the !ie hack because this old IE uses the fallback already 
*/
   background-image: -webkit-linear-gradient(transparent,transparent), 
url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCI+PGRlZnM+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNLS45NTgtNC4yNTljLTEuMTM0IDAtMi4wNTYuOTIyLTIuMDU2IDIuMDU2IDAgLjM5NC4xNDMuNzM2LjMzNiAxLjA0OWwtLjA3LjA1NmMtLjM3My0uNTEzLS45NTQtLjg2Ny0xLjYzNi0uODY3LTEuMTM0IDAtMi4wNTYuOTIyLTIuMDU2IDIuMDU2cy45MjIgMi4wNTYgMi4wNTYgMi4wNTZjLjU5NiAwIDEuMTIxLS4yNjUgMS40OTYtLjY3MS0uMDc1LjIxMy0uMTI2LjQzMy0uMTI2LjY3MSAwIDEuMTM0LjkyMiAyLjA1NiAyLjA1NiAyLjA1NnMyLjA1Ni0uOTIyIDIuMDU2LTIuMDU2YzAtLjQ3Ni0uMTg5LS44OTYtLjQ2Mi0xLjI0NS44MTMuMTU4IDEuNjI3LjQ3NyAyLjIyNCAxLjM5OS0uNDQzLS40NDMtLjcyNy0xLjI0OC0uNzI3LTIuMzM2bC0uMzc4LS4wMjguMzUtLjAxNGMwLTEuMDg3LjI3LTEuODkzLjcxMy0yLjMzNi0uNTc1Ljg4OS0xLjM1NCAxLjIxNi0yLjE0IDEuMzg1LjI0My0uMzM3LjQyLS43MjguNDItMS4xNzUgMC0xLjEzNC0uOTIyLTIuMDU2LTIuMDU2LTIuMDU2eiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iTmFOIi8+PC9tYXJrZXI+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNMC0yLjgyOGwtMi44MjggMi44MjggMi44MjggMi44MjggMi44MjgtMi44MjgtMi44MjgtMi44Mjh6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSJOYU4iLz48L21hcmtlcj48bWFya2VyIG9yaWVudD0iYXV0byIgb3ZlcmZsb3c9InZpc2libGUiPjxwYXRoIGQ9Ik0xMCAwbDQtNC0xNCA0IDE0IDQtNC00eiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iTmFOIi8+PC9tYXJrZXI+PC9kZWZzPjxwYXRoIGZpbGw9IiNmZmYiIHN0cm9rZT0iIzA2YyIgZD0iTS41IDMuNTE4aDUuOTgydjUuOTgyaC01Ljk4MnoiLz48cGF0aCBkPSJNNC43NTUtLjE2aDUuMjM0djUuMzlsLTEuNTcxIDEuNTQ0LTEuMzEtMS4zMS0yLjcyNSAyLjcyNS0yLjY4OC0yLjY4OCAyLjgwOC0yLjgwOC0xLjMxLTEuMzF6IiBmaWxsPSIjMDZmIi8+PHBhdGggZD0iTTguOTg0Ljg0NWwuMDIyIDQuODg0LTEuODE3LTEuODE3LTIuODgxIDIuODgxLTEuMjI3LTEuMjI3IDIuODgxLTIuODgxLTEuODUtMS44NTF6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);
   background-image: linear-gradient(transparent,transparent), 
url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCI+PGRlZnM+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNLS45NTgtNC4yNTljLTEuMTM0IDAtMi4wNTYuOTIyLTIuMDU2IDIuMDU2IDAgLjM5NC4xNDMuNzM2LjMzNiAxLjA0OWwtLjA3LjA1NmMtLjM3My0uNTEzLS45NTQtLjg2Ny0xLjYzNi0uODY3LTEuMTM0IDAtMi4wNTYuOTIyLTIuMDU2IDIuMDU2cy45MjIgMi4wNTYgMi4wNTYgMi4wNTZjLjU5NiAwIDEuMTIxLS4yNjUgMS40OTYtLjY3MS0uMDc1LjIxMy0uMTI2LjQzMy0uMTI2LjY3MSAwIDEuMTM0LjkyMiAyLjA1NiAyLjA1NiAyLjA1NnMyLjA1Ni0uOTIyIDIuMDU2LTIuMDU2YzAtLjQ3Ni0uMTg5LS44OTYtLjQ2Mi0xLjI0NS44MTMuMTU4IDEuNjI3LjQ3NyAyLjIyNCAxLjM5OS0uNDQzLS40NDMtLjcyNy0xLjI0OC0uNzI3LTIuMzM2bC0uMzc4LS4wMjguMzUtLjAxNGMwLTEuMDg3LjI3LTEuODkzLjcxMy0yLjMzNi0uNTc1Ljg4OS0xLjM1NCAxLjIxNi0yLjE0IDEuMzg1LjI0My0uMzM3LjQyLS43MjguNDItMS4xNzUgMC0xLjEzNC0uOTIyLTIuMDU2LTIuMDU2LTIuMDU2eiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iTmFOIi8+PC9tYXJrZXI+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNMC0yLjgyOGwtMi44MjggMi44MjggMi44MjggMi44MjggMi44MjgtMi44MjgtMi44MjgtMi44Mjh6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSJOYU4iLz48L21hcmtlcj48bWFya2VyIG9yaWVudD0iYXV0byIgb3ZlcmZsb3c9InZpc2libGUiPjxwYXRoIGQ9Ik0xMCAwbDQtNC0xNCA0IDE0IDQtNC00eiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iTmFOIi8+PC9tYXJrZXI+PC9kZWZzPjxwYXRoIGZpbGw9IiNmZmYiIHN0cm9rZT0iIzA2YyIgZD0iTS41IDMuNTE4aDUuOTgydjUuOTgyaC01Ljk4MnoiLz48cGF0aCBkPSJNNC43NTUtLjE2aDUuMjM0djUuMzlsLTEuNTcxIDEuNTQ0LTEuMzEtMS4zMS0yLjcyNSAyLjcyNS0yLjY4OC0yLjY4OCAyLjgwOC0yLjgwOC0xLjMxLTEuMzF6IiBmaWxsPSIjMDZmIi8+PHBhdGggZD0iTTguOTg0Ljg0NWwuMDIyIDQuODg0LTEuODE3LTEuODE3LTIuODgxIDIuODgxLTEuMjI3LTEuMjI3IDIuODgxLTIuODgxLTEuODUtMS44NTF6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);
@@ -541,7 +541,7 @@
   height: 32px;
   width: 32px;
   background-image: 
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAANlBMVEUAAAD///9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW+FiFraAAAAEXRSTlMAABAgMEBQYHCAkKCwwNDg8InUWv0AAAGfSURBVHhe7djBjsIgFIXhOwjFeltK3/9lJ4J6SG5dHGgyyaRn1dUXlb8slJ+T9//AC7zACxRiLu37EqXsDPCW9ue2cBLo8/7a/RQwFK9OTwDj3k6Hwbk6Mb/EeRDUojyaHzKMgG4pRmy/ehoAXcklT3h+buoGffU8vDJlQJtfuuG5busEY/Xc28N4EPkp7EHwUaODjSkLIr8Iu/VIELkE2Bj9psDzSBuLQoLIxX1sLEfhQHirQ9rwvLAgcoHdejx4b3IJ8PDOcCBysfklJzToipc9Piu2OKFA5LL5o/xUhAZ9Qi7W40Dkspj8as48OGXkYj0ORH73w/yC8OCMXA5y5sE2lwgPh86Bbi3h+i8506Brc3kYjwb9VkL7lh8N+jaXxXg0GBGayW8WCoSXq+dNzjyIXGx+UXhQm1yCyZkHA8JAfvBosF6h21RvU3vb86B+4lCTcxf4rkTV3PZ9IAiTcxcYvnm94P3Qi9IN6rHXDybL5SAD4IHnZQAMxtu8jIA4E+Q8BKr1xkCcybrOcwhOBsE3JOT+4G+WC7zAC7zAXxMIT+qGYJfyAAAAAElFTkSuQmCC);
-  background-image: 
url(//bits.wikimedia.org/static-1.24wmf15/extensions/MobileApp/less/../images/edit.png?2014-07-24T17:20:00Z)!ie;
+  background-image: 
url(//bits.wikimedia.org/static-1.24wmf18/extensions/MobileApp/less/../images/edit.png?2014-08-21T15:38:20Z)!ie;
   background-size: 32px 32px;
   float: right;
   display: inline-float;
@@ -551,7 +551,7 @@
 }
 .page-protected a.edit_section_button {
   background-image: 
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAAXVBMVEUAAAD////Pz89sbW/Pz89sbW/Pz89sbW/Pz89sbW/Pz89sbW/Pz89sbW/Pz89sbW/Pz8/Pz8/Pz89sbW/Pz89sbW/Pz8/Pz89sbW/Pz89sbW/Pz89sbW/Pz89sbW+fZUWwAAAAHXRSTlMAABAQICAwMEBAUFBgYHBwgJCgoLDAwNDQ4ODw8PGFG8cAAAHOSURBVHhe7dTLcoMwDAVQxVCXJAoByiPUEf//mcW0Gh5KFrbojrtidUYM9wKnnfOP4AEe4AGCT3JvmuHR3BOAXcDrc/jN87wLeBvmnCUIATnZEUyeC/A7UYHWjeDdQ48PSL68eNOA6GgEH9Nh3m9GsFGASOTB6S7wufrHeLCkGfycwLMKrGgBwm8UoKknD/cCTffn7QSmk+cup51A6ybP+hsGmUCQvd7CTiCST2dAB0pPAcr6VQY0oPRgCqpB005eydvTglxnPlYLWvZ4ezqQ65zxsVrwwvPg7SlBJJ4HH6sDc64ze0qwWnroSAHKeSDRDL6JBGX9eB4FKUH2Sj5WC9p+PQ8lyA1BPnYVZ4NBnOssvS4NvhBp4dl+45nAV+Yv2q3nwakMBICyztnWAwgEzcpDWgchABR1Fp5DCAXTlVdtPAuBINevEB5/pQBQ1rneeAZCQaTVPERdQsGMVn97UZdgMJ89UeccIsDaA7V55SHEgD0vDtCJukSAKQM5kvBiwAtxRF3iwPKtFwm2TIi6RIJvvGgwe+UhxIO55ByCAqylZ0ED9luvt6ABU1kXUIHLWru2LVoDOrAk6tu6KLKMJSVohaMAtTnA4BzgAf4Asb6U9nmPcP4AAAAASUVORK5CYII=);
-  background-image: 
url(//bits.wikimedia.org/static-1.24wmf15/extensions/MobileApp/less/../images/edit-locked.png?2014-07-24T17:20:00Z)!ie;
+  background-image: 
url(//bits.wikimedia.org/static-1.24wmf18/extensions/MobileApp/less/../images/edit-locked.png?2014-08-21T15:38:20Z)!ie;
 }
 #mainpage a.edit_section_button {
   display: none;
@@ -833,23 +833,22 @@
   display: none;
 }
 #li-coordinates {
-  background-image: url("float: right;
-    display: none;
-    -webkit-background-size: auto 30px;
-    background-size: auto 30px;
+  background-image: 
url(//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Edge-firefox.png/80px-Edge-firefox.png);
+  float: right;
+  display: none;
+  -webkit-background-size: auto 30px;
+  background-size: auto 30px;
 }
-
 .client-js .content_block.coordinates {
-    display: none;
-    text-align: right;
-    margin-bottom: 0.5em;
-    font-size: smaller;
+  display: none;
+  text-align: right;
+  margin-bottom: 0.5em;
+  font-size: smaller;
 }
-
 .client-js .content_block.coordinates .latitude {
-    display:none;
-    padding-left: 20px;
-    background-image: 
url(//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Edge-firefox.png/50px-Edge-firefox.png");
+  display: none;
+  padding-left: 20px;
+  background-image: 
url(//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Edge-firefox.png/50px-Edge-firefox.png);
   background-repeat: no-repeat;
   -webkit-background-size: auto 15px;
   background-size: auto 15px;
diff --git a/wikipedia/assets/preview.css b/wikipedia/assets/preview.css
index 09fccec..d5a9f70 100644
--- a/wikipedia/assets/preview.css
+++ b/wikipedia/assets/preview.css
@@ -199,7 +199,7 @@
   font-size: .8em;
   line-height: 1.5;
   padding: 0 !important;
-  color: #777;
+  color: #555;
   width: auto !important;
 }
 .content .thumbborder {
@@ -283,7 +283,7 @@
 }
 a.external {
   background-image: 
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAVElEQVR42n3PgQkAIAhEUXdqJ3dqJ3e6IoTPUSQcgj4EQ5IlUiLE0Jil3PECXhcHGBhZ8kg4hwxAu3MZeCGeyFnAXp4hqNQPnt7QL0nADpD6wHccLvnAKksq8iiaAAAAAElFTkSuQmCC);
-  background-image: 
url(//bits.wikimedia.org/static-1.24wmf15/extensions/MobileApp/../MobileFrontend/less/content/images/external-link-ltr-icon.png?2014-07-24T17:20:00Z)!ie;
+  background-image: 
url(//bits.wikimedia.org/static-1.24wmf18/extensions/MobileApp/../MobileFrontend/less/content/images/external-link-ltr-icon.png?2014-08-21T15:38:20Z)!ie;
   /* We don't need the !ie hack because this old IE uses the fallback already 
*/
   background-image: -webkit-linear-gradient(transparent,transparent), 
url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCI+PGRlZnM+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNLS45NTgtNC4yNTljLTEuMTM0IDAtMi4wNTYuOTIyLTIuMDU2IDIuMDU2IDAgLjM5NC4xNDMuNzM2LjMzNiAxLjA0OWwtLjA3LjA1NmMtLjM3My0uNTEzLS45NTQtLjg2Ny0xLjYzNi0uODY3LTEuMTM0IDAtMi4wNTYuOTIyLTIuMDU2IDIuMDU2cy45MjIgMi4wNTYgMi4wNTYgMi4wNTZjLjU5NiAwIDEuMTIxLS4yNjUgMS40OTYtLjY3MS0uMDc1LjIxMy0uMTI2LjQzMy0uMTI2LjY3MSAwIDEuMTM0LjkyMiAyLjA1NiAyLjA1NiAyLjA1NnMyLjA1Ni0uOTIyIDIuMDU2LTIuMDU2YzAtLjQ3Ni0uMTg5LS44OTYtLjQ2Mi0xLjI0NS44MTMuMTU4IDEuNjI3LjQ3NyAyLjIyNCAxLjM5OS0uNDQzLS40NDMtLjcyNy0xLjI0OC0uNzI3LTIuMzM2bC0uMzc4LS4wMjguMzUtLjAxNGMwLTEuMDg3LjI3LTEuODkzLjcxMy0yLjMzNi0uNTc1Ljg4OS0xLjM1NCAxLjIxNi0yLjE0IDEuMzg1LjI0My0uMzM3LjQyLS43MjguNDItMS4xNzUgMC0xLjEzNC0uOTIyLTIuMDU2LTIuMDU2LTIuMDU2eiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iTmFOIi8+PC9tYXJrZXI+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNMC0yLjgyOGwtMi44MjggMi44MjggMi44MjggMi44MjggMi44MjgtMi44MjgtMi44MjgtMi44Mjh6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSJOYU4iLz48L21hcmtlcj48bWFya2VyIG9yaWVudD0iYXV0byIgb3ZlcmZsb3c9InZpc2libGUiPjxwYXRoIGQ9Ik0xMCAwbDQtNC0xNCA0IDE0IDQtNC00eiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iTmFOIi8+PC9tYXJrZXI+PC9kZWZzPjxwYXRoIGZpbGw9IiNmZmYiIHN0cm9rZT0iIzA2YyIgZD0iTS41IDMuNTE4aDUuOTgydjUuOTgyaC01Ljk4MnoiLz48cGF0aCBkPSJNNC43NTUtLjE2aDUuMjM0djUuMzlsLTEuNTcxIDEuNTQ0LTEuMzEtMS4zMS0yLjcyNSAyLjcyNS0yLjY4OC0yLjY4OCAyLjgwOC0yLjgwOC0xLjMxLTEuMzF6IiBmaWxsPSIjMDZmIi8+PHBhdGggZD0iTTguOTg0Ljg0NWwuMDIyIDQuODg0LTEuODE3LTEuODE3LTIuODgxIDIuODgxLTEuMjI3LTEuMjI3IDIuODgxLTIuODgxLTEuODUtMS44NTF6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);
   background-image: linear-gradient(transparent,transparent), 
url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCI+PGRlZnM+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNLS45NTgtNC4yNTljLTEuMTM0IDAtMi4wNTYuOTIyLTIuMDU2IDIuMDU2IDAgLjM5NC4xNDMuNzM2LjMzNiAxLjA0OWwtLjA3LjA1NmMtLjM3My0uNTEzLS45NTQtLjg2Ny0xLjYzNi0uODY3LTEuMTM0IDAtMi4wNTYuOTIyLTIuMDU2IDIuMDU2cy45MjIgMi4wNTYgMi4wNTYgMi4wNTZjLjU5NiAwIDEuMTIxLS4yNjUgMS40OTYtLjY3MS0uMDc1LjIxMy0uMTI2LjQzMy0uMTI2LjY3MSAwIDEuMTM0LjkyMiAyLjA1NiAyLjA1NiAyLjA1NnMyLjA1Ni0uOTIyIDIuMDU2LTIuMDU2YzAtLjQ3Ni0uMTg5LS44OTYtLjQ2Mi0xLjI0NS44MTMuMTU4IDEuNjI3LjQ3NyAyLjIyNCAxLjM5OS0uNDQzLS40NDMtLjcyNy0xLjI0OC0uNzI3LTIuMzM2bC0uMzc4LS4wMjguMzUtLjAxNGMwLTEuMDg3LjI3LTEuODkzLjcxMy0yLjMzNi0uNTc1Ljg4OS0xLjM1NCAxLjIxNi0yLjE0IDEuMzg1LjI0My0uMzM3LjQyLS43MjguNDItMS4xNzUgMC0xLjEzNC0uOTIyLTIuMDU2LTIuMDU2LTIuMDU2eiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iTmFOIi8+PC9tYXJrZXI+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNMC0yLjgyOGwtMi44MjggMi44MjggMi44MjggMi44MjggMi44MjgtMi44MjgtMi44MjgtMi44Mjh6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSJOYU4iLz48L21hcmtlcj48bWFya2VyIG9yaWVudD0iYXV0byIgb3ZlcmZsb3c9InZpc2libGUiPjxwYXRoIGQ9Ik0xMCAwbDQtNC0xNCA0IDE0IDQtNC00eiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iTmFOIi8+PC9tYXJrZXI+PC9kZWZzPjxwYXRoIGZpbGw9IiNmZmYiIHN0cm9rZT0iIzA2YyIgZD0iTS41IDMuNTE4aDUuOTgydjUuOTgyaC01Ljk4MnoiLz48cGF0aCBkPSJNNC43NTUtLjE2aDUuMjM0djUuMzlsLTEuNTcxIDEuNTQ0LTEuMzEtMS4zMS0yLjcyNSAyLjcyNS0yLjY4OC0yLjY4OCAyLjgwOC0yLjgwOC0xLjMxLTEuMzF6IiBmaWxsPSIjMDZmIi8+PHBhdGggZD0iTTguOTg0Ljg0NWwuMDIyIDQuODg0LTEuODE3LTEuODE3LTIuODgxIDIuODgxLTEuMjI3LTEuMjI3IDIuODgxLTIuODgxLTEuODUtMS44NTF6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);
@@ -812,23 +812,22 @@
   display: none;
 }
 #li-coordinates {
-  background-image: url("float: right;
-    display: none;
-    -webkit-background-size: auto 30px;
-    background-size: auto 30px;
+  background-image: 
url(//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Edge-firefox.png/80px-Edge-firefox.png);
+  float: right;
+  display: none;
+  -webkit-background-size: auto 30px;
+  background-size: auto 30px;
 }
-
 .client-js .content_block.coordinates {
-    display: none;
-    text-align: right;
-    margin-bottom: 0.5em;
-    font-size: smaller;
+  display: none;
+  text-align: right;
+  margin-bottom: 0.5em;
+  font-size: smaller;
 }
-
 .client-js .content_block.coordinates .latitude {
-    display:none;
-    padding-left: 20px;
-    background-image: 
url(//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Edge-firefox.png/50px-Edge-firefox.png");
+  display: none;
+  padding-left: 20px;
+  background-image: 
url(//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Edge-firefox.png/50px-Edge-firefox.png);
   background-repeat: no-repeat;
   -webkit-background-size: auto 15px;
   background-size: auto 15px;
diff --git a/wikipedia/assets/styles.css b/wikipedia/assets/styles.css
index 07bf36d..7015256 100644
--- a/wikipedia/assets/styles.css
+++ b/wikipedia/assets/styles.css
@@ -199,7 +199,7 @@
   font-size: .8em;
   line-height: 1.5;
   padding: 0 !important;
-  color: #777;
+  color: #555;
   width: auto !important;
 }
 .content .thumbborder {
@@ -283,7 +283,7 @@
 }
 a.external {
   background-image: 
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAVElEQVR42n3PgQkAIAhEUXdqJ3dqJ3e6IoTPUSQcgj4EQ5IlUiLE0Jil3PECXhcHGBhZ8kg4hwxAu3MZeCGeyFnAXp4hqNQPnt7QL0nADpD6wHccLvnAKksq8iiaAAAAAElFTkSuQmCC);
-  background-image: 
url(//bits.wikimedia.org/static-1.24wmf15/extensions/MobileApp/../MobileFrontend/less/content/images/external-link-ltr-icon.png?2014-07-24T17:20:00Z)!ie;
+  background-image: 
url(//bits.wikimedia.org/static-1.24wmf18/extensions/MobileApp/../MobileFrontend/less/content/images/external-link-ltr-icon.png?2014-08-21T15:38:20Z)!ie;
   /* We don't need the !ie hack because this old IE uses the fallback already 
*/
   background-image: -webkit-linear-gradient(transparent,transparent), 
url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCI+PGRlZnM+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNLS45NTgtNC4yNTljLTEuMTM0IDAtMi4wNTYuOTIyLTIuMDU2IDIuMDU2IDAgLjM5NC4xNDMuNzM2LjMzNiAxLjA0OWwtLjA3LjA1NmMtLjM3My0uNTEzLS45NTQtLjg2Ny0xLjYzNi0uODY3LTEuMTM0IDAtMi4wNTYuOTIyLTIuMDU2IDIuMDU2cy45MjIgMi4wNTYgMi4wNTYgMi4wNTZjLjU5NiAwIDEuMTIxLS4yNjUgMS40OTYtLjY3MS0uMDc1LjIxMy0uMTI2LjQzMy0uMTI2LjY3MSAwIDEuMTM0LjkyMiAyLjA1NiAyLjA1NiAyLjA1NnMyLjA1Ni0uOTIyIDIuMDU2LTIuMDU2YzAtLjQ3Ni0uMTg5LS44OTYtLjQ2Mi0xLjI0NS44MTMuMTU4IDEuNjI3LjQ3NyAyLjIyNCAxLjM5OS0uNDQzLS40NDMtLjcyNy0xLjI0OC0uNzI3LTIuMzM2bC0uMzc4LS4wMjguMzUtLjAxNGMwLTEuMDg3LjI3LTEuODkzLjcxMy0yLjMzNi0uNTc1Ljg4OS0xLjM1NCAxLjIxNi0yLjE0IDEuMzg1LjI0My0uMzM3LjQyLS43MjguNDItMS4xNzUgMC0xLjEzNC0uOTIyLTIuMDU2LTIuMDU2LTIuMDU2eiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iTmFOIi8+PC9tYXJrZXI+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNMC0yLjgyOGwtMi44MjggMi44MjggMi44MjggMi44MjggMi44MjgtMi44MjgtMi44MjgtMi44Mjh6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSJOYU4iLz48L21hcmtlcj48bWFya2VyIG9yaWVudD0iYXV0byIgb3ZlcmZsb3c9InZpc2libGUiPjxwYXRoIGQ9Ik0xMCAwbDQtNC0xNCA0IDE0IDQtNC00eiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iTmFOIi8+PC9tYXJrZXI+PC9kZWZzPjxwYXRoIGZpbGw9IiNmZmYiIHN0cm9rZT0iIzA2YyIgZD0iTS41IDMuNTE4aDUuOTgydjUuOTgyaC01Ljk4MnoiLz48cGF0aCBkPSJNNC43NTUtLjE2aDUuMjM0djUuMzlsLTEuNTcxIDEuNTQ0LTEuMzEtMS4zMS0yLjcyNSAyLjcyNS0yLjY4OC0yLjY4OCAyLjgwOC0yLjgwOC0xLjMxLTEuMzF6IiBmaWxsPSIjMDZmIi8+PHBhdGggZD0iTTguOTg0Ljg0NWwuMDIyIDQuODg0LTEuODE3LTEuODE3LTIuODgxIDIuODgxLTEuMjI3LTEuMjI3IDIuODgxLTIuODgxLTEuODUtMS44NTF6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);
   background-image: linear-gradient(transparent,transparent), 
url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCI+PGRlZnM+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNLS45NTgtNC4yNTljLTEuMTM0IDAtMi4wNTYuOTIyLTIuMDU2IDIuMDU2IDAgLjM5NC4xNDMuNzM2LjMzNiAxLjA0OWwtLjA3LjA1NmMtLjM3My0uNTEzLS45NTQtLjg2Ny0xLjYzNi0uODY3LTEuMTM0IDAtMi4wNTYuOTIyLTIuMDU2IDIuMDU2cy45MjIgMi4wNTYgMi4wNTYgMi4wNTZjLjU5NiAwIDEuMTIxLS4yNjUgMS40OTYtLjY3MS0uMDc1LjIxMy0uMTI2LjQzMy0uMTI2LjY3MSAwIDEuMTM0LjkyMiAyLjA1NiAyLjA1NiAyLjA1NnMyLjA1Ni0uOTIyIDIuMDU2LTIuMDU2YzAtLjQ3Ni0uMTg5LS44OTYtLjQ2Mi0xLjI0NS44MTMuMTU4IDEuNjI3LjQ3NyAyLjIyNCAxLjM5OS0uNDQzLS40NDMtLjcyNy0xLjI0OC0uNzI3LTIuMzM2bC0uMzc4LS4wMjguMzUtLjAxNGMwLTEuMDg3LjI3LTEuODkzLjcxMy0yLjMzNi0uNTc1Ljg4OS0xLjM1NCAxLjIxNi0yLjE0IDEuMzg1LjI0My0uMzM3LjQyLS43MjguNDItMS4xNzUgMC0xLjEzNC0uOTIyLTIuMDU2LTIuMDU2LTIuMDU2eiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iTmFOIi8+PC9tYXJrZXI+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG92ZXJmbG93PSJ2aXNpYmxlIj48cGF0aCBkPSJNMC0yLjgyOGwtMi44MjggMi44MjggMi44MjggMi44MjggMi44MjgtMi44MjgtMi44MjgtMi44Mjh6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSJOYU4iLz48L21hcmtlcj48bWFya2VyIG9yaWVudD0iYXV0byIgb3ZlcmZsb3c9InZpc2libGUiPjxwYXRoIGQ9Ik0xMCAwbDQtNC0xNCA0IDE0IDQtNC00eiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iTmFOIi8+PC9tYXJrZXI+PC9kZWZzPjxwYXRoIGZpbGw9IiNmZmYiIHN0cm9rZT0iIzA2YyIgZD0iTS41IDMuNTE4aDUuOTgydjUuOTgyaC01Ljk4MnoiLz48cGF0aCBkPSJNNC43NTUtLjE2aDUuMjM0djUuMzlsLTEuNTcxIDEuNTQ0LTEuMzEtMS4zMS0yLjcyNSAyLjcyNS0yLjY4OC0yLjY4OCAyLjgwOC0yLjgwOC0xLjMxLTEuMzF6IiBmaWxsPSIjMDZmIi8+PHBhdGggZD0iTTguOTg0Ljg0NWwuMDIyIDQuODg0LTEuODE3LTEuODE3LTIuODgxIDIuODgxLTEuMjI3LTEuMjI3IDIuODgxLTIuODgxLTEuODUtMS44NTF6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);
@@ -541,7 +541,7 @@
   height: 32px;
   width: 32px;
   background-image: 
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAANlBMVEUAAAD///9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW9sbW+FiFraAAAAEXRSTlMAABAgMEBQYHCAkKCwwNDg8InUWv0AAAGfSURBVHhe7djBjsIgFIXhOwjFeltK3/9lJ4J6SG5dHGgyyaRn1dUXlb8slJ+T9//AC7zACxRiLu37EqXsDPCW9ue2cBLo8/7a/RQwFK9OTwDj3k6Hwbk6Mb/EeRDUojyaHzKMgG4pRmy/ehoAXcklT3h+buoGffU8vDJlQJtfuuG5busEY/Xc28N4EPkp7EHwUaODjSkLIr8Iu/VIELkE2Bj9psDzSBuLQoLIxX1sLEfhQHirQ9rwvLAgcoHdejx4b3IJ8PDOcCBysfklJzToipc9Piu2OKFA5LL5o/xUhAZ9Qi7W40Dkspj8as48OGXkYj0ORH73w/yC8OCMXA5y5sE2lwgPh86Bbi3h+i8506Brc3kYjwb9VkL7lh8N+jaXxXg0GBGayW8WCoSXq+dNzjyIXGx+UXhQm1yCyZkHA8JAfvBosF6h21RvU3vb86B+4lCTcxf4rkTV3PZ9IAiTcxcYvnm94P3Qi9IN6rHXDybL5SAD4IHnZQAMxtu8jIA4E+Q8BKr1xkCcybrOcwhOBsE3JOT+4G+WC7zAC7zAXxMIT+qGYJfyAAAAAElFTkSuQmCC);
-  background-image: 
url(//bits.wikimedia.org/static-1.24wmf15/extensions/MobileApp/less/../images/edit.png?2014-07-24T17:20:00Z)!ie;
+  background-image: 
url(//bits.wikimedia.org/static-1.24wmf18/extensions/MobileApp/less/../images/edit.png?2014-08-21T15:38:20Z)!ie;
   background-size: 32px 32px;
   float: right;
   display: inline-float;
@@ -551,7 +551,7 @@
 }
 .page-protected a.edit_section_button {
   background-image: 
url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAAXVBMVEUAAAD////Pz89sbW/Pz89sbW/Pz89sbW/Pz89sbW/Pz89sbW/Pz89sbW/Pz89sbW/Pz8/Pz8/Pz89sbW/Pz89sbW/Pz8/Pz89sbW/Pz89sbW/Pz89sbW/Pz89sbW+fZUWwAAAAHXRSTlMAABAQICAwMEBAUFBgYHBwgJCgoLDAwNDQ4ODw8PGFG8cAAAHOSURBVHhe7dTLcoMwDAVQxVCXJAoByiPUEf//mcW0Gh5KFrbojrtidUYM9wKnnfOP4AEe4AGCT3JvmuHR3BOAXcDrc/jN87wLeBvmnCUIATnZEUyeC/A7UYHWjeDdQ48PSL68eNOA6GgEH9Nh3m9GsFGASOTB6S7wufrHeLCkGfycwLMKrGgBwm8UoKknD/cCTffn7QSmk+cup51A6ybP+hsGmUCQvd7CTiCST2dAB0pPAcr6VQY0oPRgCqpB005eydvTglxnPlYLWvZ4ezqQ65zxsVrwwvPg7SlBJJ4HH6sDc64ze0qwWnroSAHKeSDRDL6JBGX9eB4FKUH2Sj5WC9p+PQ8lyA1BPnYVZ4NBnOssvS4NvhBp4dl+45nAV+Yv2q3nwakMBICyztnWAwgEzcpDWgchABR1Fp5DCAXTlVdtPAuBINevEB5/pQBQ1rneeAZCQaTVPERdQsGMVn97UZdgMJ89UeccIsDaA7V55SHEgD0vDtCJukSAKQM5kvBiwAtxRF3iwPKtFwm2TIi6RIJvvGgwe+UhxIO55ByCAqylZ0ED9luvt6ABU1kXUIHLWru2LVoDOrAk6tu6KLKMJSVohaMAtTnA4BzgAf4Asb6U9nmPcP4AAAAASUVORK5CYII=);
-  background-image: 
url(//bits.wikimedia.org/static-1.24wmf15/extensions/MobileApp/less/../images/edit-locked.png?2014-07-24T17:20:00Z)!ie;
+  background-image: 
url(//bits.wikimedia.org/static-1.24wmf18/extensions/MobileApp/less/../images/edit-locked.png?2014-08-21T15:38:20Z)!ie;
 }
 #mainpage a.edit_section_button {
   display: none;
@@ -833,23 +833,22 @@
   display: none;
 }
 #li-coordinates {
-  background-image: url("float: right;
-    display: none;
-    -webkit-background-size: auto 30px;
-    background-size: auto 30px;
+  background-image: 
url(//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Edge-firefox.png/80px-Edge-firefox.png);
+  float: right;
+  display: none;
+  -webkit-background-size: auto 30px;
+  background-size: auto 30px;
 }
-
 .client-js .content_block.coordinates {
-    display: none;
-    text-align: right;
-    margin-bottom: 0.5em;
-    font-size: smaller;
+  display: none;
+  text-align: right;
+  margin-bottom: 0.5em;
+  font-size: smaller;
 }
-
 .client-js .content_block.coordinates .latitude {
-    display:none;
-    padding-left: 20px;
-    background-image: 
url(//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Edge-firefox.png/50px-Edge-firefox.png");
+  display: none;
+  padding-left: 20px;
+  background-image: 
url(//upload.wikimedia.org/wikipedia/commons/thumb/5/57/Edge-firefox.png/50px-Edge-firefox.png);
   background-repeat: no-repeat;
   -webkit-background-size: auto 15px;
   background-size: auto 15px;
diff --git a/wikipedia/en.lproj/Localizable.strings 
b/wikipedia/en.lproj/Localizable.strings
index 7006936..1e517a8 100644
--- a/wikipedia/en.lproj/Localizable.strings
+++ b/wikipedia/en.lproj/Localizable.strings
@@ -156,8 +156,9 @@
 "credits-github-mirror" = "App mirror (GitHub)";
 "credits-external-libraries" = "External repositories";
 
-"share-menu-save-page" = "Save Article";
-"share-menu-page-saved" = "Article Saved";
+"share-menu-save-page" = "Save page";
+"share-menu-page-saved" = "$1 saved for offline reading.";
+"share-menu-page-saved-access" = "One-time reminder: to access your saved 
pages, long-press the heart icon below or tap the W icon above.";
 
 "timestamp-just-now" = "just now";
 "timestamp-minutes" = "%d minutes ago";
diff --git a/wikipedia/qqq.lproj/Localizable.strings 
b/wikipedia/qqq.lproj/Localizable.strings
index 67f1154..73ae3d7 100644
--- a/wikipedia/qqq.lproj/Localizable.strings
+++ b/wikipedia/qqq.lproj/Localizable.strings
@@ -146,7 +146,8 @@
 "credits-github-mirror" = "Text for item linking to the app's mirrored GitHub 
repository";
 "credits-external-libraries" = "Title for area of credits page showing 
external open source libraries used by app.\n{{Identical|External}}";
 "share-menu-save-page" = "Button text for saving current page from the share 
menu";
-"share-menu-page-saved" = "Alert text shown when page saved";
+"share-menu-page-saved" = "Alert text shown when page saved for offline 
reading. $1 is the name of the page being saved";
+"share-menu-page-saved-access" = "Reminder to user of ways to access saved 
pages.";
 "timestamp-just-now" = "Human-readable approximate timestamp for events in the 
last couple of minutes.\n{{Identical|Just now}}";
 "timestamp-minutes" = "Human-readable approximate timestamp for events in the 
last couple hours, expressed as minutes";
 "timestamp-hours" = "Human-readable approximate timestamp for events in the 
last couple days, expressed as hours";

-- 
To view, visit https://gerrit.wikimedia.org/r/157489
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I473b5f02319d016b7c4cf8bfd7dea9b1930dcbef
Gerrit-PatchSet: 1
Gerrit-Project: apps/ios/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Mhurd <mh...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to