summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/Translate/resources/js/ext.translate.messagetable.js
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/Translate/resources/js/ext.translate.messagetable.js')
-rw-r--r--www/wiki/extensions/Translate/resources/js/ext.translate.messagetable.js524
1 files changed, 296 insertions, 228 deletions
diff --git a/www/wiki/extensions/Translate/resources/js/ext.translate.messagetable.js b/www/wiki/extensions/Translate/resources/js/ext.translate.messagetable.js
index ff8405d8..adf3d33c 100644
--- a/www/wiki/extensions/Translate/resources/js/ext.translate.messagetable.js
+++ b/www/wiki/extensions/Translate/resources/js/ext.translate.messagetable.js
@@ -1,18 +1,7 @@
-( function ( $, mw ) {
+( function () {
'use strict';
- var delay, itemsClass;
-
- delay = ( function () {
- var timer = 0;
-
- return function ( callback, milliseconds ) {
- clearTimeout( timer );
- timer = setTimeout( callback, milliseconds );
- };
- }() );
-
- itemsClass = {
+ var itemsClass = {
proofread: '.tux-message-proofread',
page: '.tux-message-pagemode',
translate: '.tux-message'
@@ -27,62 +16,22 @@
action: 'query',
list: 'messagecollection',
mcgroup: messageGroup,
- format: 'json',
mclanguage: language,
mcoffset: offset,
mclimit: limit,
mcfilter: filter,
mcprop: 'definition|translation|tags|properties',
- rawcontinue: 1
+ rawcontinue: 1,
+ errorformat: 'html'
} );
- },
-
- loadMessages: function ( changes ) {
- // FIXME: this should be member method
- var $container = $( '.tux-messagelist' ),
- $loader = $( '.tux-messagetable-loader' ),
- $statsbar = $( '.tux-message-list-statsbar' );
-
- changes = changes || {};
-
- // Clear current messages
- $container.trigger( 'clear' );
-
- // Change the properties that are provided
- if ( changes.filter !== undefined ) {
- $loader.data( 'filter', changes.filter );
- }
- if ( changes.group !== undefined ) {
- $loader.data( 'messagegroup', changes.group );
- }
-
- // Reset the number of messages remaining
- $loader.find( '.tux-messagetable-loader-count' ).text( '' );
-
- // Reset the statsbar
- $statsbar
- .empty()
- .removeData()
- .languagestatsbar( {
- language: $container.data( 'targetlangcode' ),
- group: $loader.data( 'messagegroup' )
- } );
-
- // Reset other info and make visible
- $loader
- .removeData( 'offset' )
- .removeAttr( 'data-offset' )
- .removeClass( 'hide' );
-
- // And start loading
- $loader.trigger( 'appear' );
}
} );
- function MessageTable( container, options ) {
+ function MessageTable( container, options, settings ) {
this.$container = $( container );
this.options = options;
this.options = $.extend( {}, $.fn.messagetable.defaults, options );
+ this.settings = settings;
// mode can be proofread, page or translate
this.mode = this.options.mode;
this.firstProofreadTipShown = false;
@@ -90,7 +39,11 @@
this.$header = this.$container.siblings( '.tux-messagetable-header' );
// Container is between these in the dom.
this.$loader = this.$container.siblings( '.tux-messagetable-loader' );
+ this.$loaderIcon = this.$loader.find( '.tux-loading-indicator' );
+ this.$loaderInfo = this.$loader.find( '.tux-messagetable-loader-info' );
this.$actionBar = this.$container.siblings( '.tux-action-bar' );
+ this.$statsBar = this.$actionBar.find( '.tux-message-list-statsbar' );
+ this.$proofreadOwnTranslations = this.$actionBar.find( '.tux-proofread-own-translations-button' );
this.messages = [];
this.loading = false;
this.init();
@@ -99,8 +52,6 @@
MessageTable.prototype = {
init: function () {
- this.switchMode( this.mode );
- this.initialized = true;
this.$actionBar.removeClass( 'hide' );
},
@@ -109,35 +60,24 @@
$filterInput = this.$container.parent().find( '.tux-message-filter-box' );
// Vector has transitions of 250ms which affect layout. Let those finish.
- $( window ).on( 'scroll resize', function () {
- delay( function () {
- messageTable.scroll();
- }, 250 );
- } ).resize( function () {
+ $( window ).on( 'scroll', $.debounce( 250, function () {
+ messageTable.scroll();
+
+ if ( isLoaderVisible( messageTable.$loader ) ) {
+ messageTable.load();
+ }
+ } ) ).on( 'resize', $.throttle( 250, function () {
messageTable.resize();
- } );
+ messageTable.scroll();
+ } ) );
if ( mw.translate.isPlaceholderSupported( $filterInput ) ) {
$filterInput.prop( 'placeholder', mw.msg( 'tux-message-filter-placeholder' ) );
}
- $filterInput.on( 'textchange', function () {
- delay( function () {
- messageTable.search( $filterInput.val() );
- }, 300 );
- } );
-
- this.$container.on( 'clear', $.proxy( messageTable.clear, messageTable ) );
-
- this.$loader.appear( function () {
- // Avoid the overlap calls to load()
- setTimeout( function () {
- messageTable.load();
- }, 250 );
- }, {
- // Appear callback need to be called more than once.
- one: false
- } );
+ $filterInput.on( 'textchange', $.debounce( 250, function () {
+ messageTable.search( $filterInput.val() );
+ } ) );
this.$actionBar.find( 'button.proofread-mode-button' ).on( 'click', function () {
messageTable.switchMode( 'proofread' );
@@ -150,6 +90,20 @@
this.$actionBar.find( 'button.page-mode-button' ).on( 'click', function () {
messageTable.switchMode( 'page' );
} );
+
+ this.$proofreadOwnTranslations.click( function () {
+ var $this = $( this ),
+ hideMessage = mw.msg( 'tux-editor-proofreading-hide-own-translations' ),
+ showMessage = mw.msg( 'tux-editor-proofreading-show-own-translations' );
+
+ if ( $this.hasClass( 'down' ) ) {
+ messageTable.setHideOwnInProofreading( false );
+ $this.removeClass( 'down' ).text( hideMessage );
+ } else {
+ messageTable.setHideOwnInProofreading( true );
+ $this.addClass( 'down' ).text( showMessage );
+ }
+ } );
},
/**
@@ -157,15 +111,20 @@
*/
clear: function () {
this.$container.empty();
- $( '.translate-tipsy' ).remove();
+ $( '.translate-tooltip' ).remove();
this.messages = [];
// Any ongoing loading process will notice this and will reject results.
this.loading = false;
},
+ /**
+ * Adds a new message using current mode.
+ *
+ * @param {Object} message
+ */
add: function ( message ) {
// Prepare the message for display
- mw.translateHooks.run( 'formatMessageBeforeTable', message );
+ mw.hook( 'mw.translate.messagetable.formatMessageBeforeTable' ).fire( message );
if ( this.mode === 'translate' ) {
this.addTranslate( message );
@@ -178,6 +137,8 @@
/**
* Add a message to the message table for translation.
+ *
+ * @param {Object} message
*/
addTranslate: function ( message ) {
var $message,
@@ -190,8 +151,10 @@
$messageWrapper = $( '<div>' ).addClass( 'row tux-message' ),
statusMsg = '';
+ message.proofreadable = false;
+
if ( message.tags.length &&
- $.inArray( 'optional', message.tags ) >= 0 &&
+ message.tags.indexOf( 'optional' ) >= 0 &&
status === 'untranslated'
) {
status = 'optional';
@@ -245,7 +208,7 @@
dir: targetLangDir
} )
.text( message.translation || '' )
- ),
+ ),
$( '<div>' )
.addClass( 'two columns tux-list-status text-center' )
.append(
@@ -276,11 +239,14 @@
/**
* Add a message to the message table for proofreading.
+ *
+ * @param {Object} message
*/
addProofread: function ( message ) {
- var icon, $message;
+ var $message, $icon;
- $message = $( '<div>' ).addClass( 'row tux-message-proofread' );
+ $message = $( '<div>' )
+ .addClass( 'row tux-message tux-message-proofread' );
this.$container.append( $message );
$message.proofread( {
@@ -289,30 +255,53 @@
targetlangcode: this.$container.data( 'targetlangcode' )
} );
- // Add autotipsy to first available proofread action icon
- if ( this.firstProofreadTipShown ) {
+ $icon = $message.find( '.tux-proofread-action' );
+ if ( $icon.length === 0 ) {
return;
}
- icon = $message.find( '.tux-proofread-action' );
- if ( icon.length === 0 ) {
+ // Add autotooltip to first available proofread action icon
+ if ( this.firstProofreadTipShown ) {
return;
}
-
this.firstProofreadTipShown = true;
- icon.addClass( 'autotipsy' );
-
- // Selectors are not cached in case the element no longer exists
- setTimeout( function () {
- var icon = $( '.autotipsy' );
- if ( icon.length ) { icon.tipsy( 'show' ); }
- }, 1000 );
- setTimeout( function () {
- var icon = $( '.autotipsy' );
- if ( icon.length ) { icon.tipsy( 'hide' ); }
- }, 4000 );
+ $icon.addClass( 'autotooltip' );
+
+ mw.loader.using( 'oojs-ui-core' ).done( function () {
+ var tooltip = new OO.ui.PopupWidget( {
+ padded: true,
+ align: 'center',
+ width: 250,
+ classes: [ 'translate-tooltip' ],
+ $content: $( '<p>' ).text( $icon.prop( 'title' ) )
+ } );
+
+ setTimeout( function () {
+ var offset, $icon = $( '.autotooltip:visible' );
+ if ( !$icon.length ) {
+ return;
+ }
+
+ offset = $icon.offset();
+ tooltip.$element.appendTo( 'body' );
+ tooltip.toggle( true ).toggleClipping( false ).togglePositioning( false );
+ tooltip.$element.css( {
+ top: offset.top + $icon.outerHeight() + 5,
+ left: offset.left + $icon.outerWidth() - tooltip.$element.width() / 2 - 15
+ } );
+
+ setTimeout( function () {
+ tooltip.$element.remove();
+ }, 4000 );
+ }, 1000 );
+ } );
},
+ /**
+ * Add a message to the message table for wiki page mode.
+ *
+ * @param {Object} message
+ */
addPageModeMessage: function ( message ) {
var $message;
@@ -354,17 +343,14 @@
$result = this.$container.find( '.tux-message-filter-result' );
if ( !$result.length ) {
$note = $( '<div>' )
- .addClass( 'nine columns advanced-search' );
+ .addClass( 'advanced-search' );
- $button = $( '<div>' )
- .addClass( 'three columns' )
- .append( $( '<button>' )
- .addClass( 'button' )
- .text( mw.msg( 'tux-message-filter-advanced-button' ) )
- );
+ $button = $( '<button>' )
+ .addClass( 'mw-ui-button' )
+ .text( mw.msg( 'tux-message-filter-advanced-button' ) );
$result = $( '<div>' )
- .addClass( 'row highlight tux-message-filter-result' )
+ .addClass( 'tux-message-filter-result' )
.append( $note, $button );
this.$container.prepend( $result );
@@ -381,7 +367,6 @@
} );
}
- this.$loader.trigger( 'appear' );
this.updateLastMessage();
// Trigger a scroll event for the window to make sure all floating toolbars
@@ -408,100 +393,160 @@
}
},
- load: function () {
+ /**
+ * Start loading messages again with new settings.
+ *
+ * @param {Object} changes
+ */
+ changeSettings: function ( changes ) {
+ // Clear current messages
+ this.clear();
+ this.settings = $.extend( this.settings, changes );
+
+ if ( this.initialized === false ) {
+ this.switchMode( this.mode );
+ }
+
+ // Reset the number of messages remaining
+ this.$loaderInfo.text(
+ mw.msg( 'tux-messagetable-loading-messages', this.$loader.data( 'pagesize' ) )
+ );
+
+ // Reset the statsbar
+ this.$statsBar
+ .empty()
+ .removeData()
+ .languagestatsbar( {
+ language: this.settings.language,
+ group: this.settings.group
+ } );
+
+ this.initialized = true;
+ // Reset other info and make visible
+ this.$loader
+ .removeData( 'offset' )
+ .removeAttr( 'data-offset' )
+ .removeClass( 'hide' );
+
+ if ( changes.offset ) {
+ this.$loader.data( 'offset', changes.offset );
+ }
+
+ this.$header.removeClass( 'hide' );
+ this.$actionBar.removeClass( 'hide' );
+
+ // Start loading messages
+ this.load( changes.limit );
+ },
+
+ /**
+ * @param {number} [limit] Only load this many messages and then stop even if there is more.
+ */
+ load: function ( limit ) {
var remaining,
query,
- messageTable = this,
- $messageList = $( '.tux-messagelist' ),
+ self = this,
offset = this.$loader.data( 'offset' ),
- filter = messageTable.$loader.data( 'filter' ),
- targetLangCode = $messageList.data( 'targetlangcode' ),
- messagegroup = messageTable.$loader.data( 'messagegroup' ),
- pageSize = messageTable.$loader.data( 'pagesize' );
+ pageSize = limit || this.$loader.data( 'pagesize' );
if ( offset === -1 ) {
return;
}
- if ( messageTable.loading ) {
+ if ( this.loading ) {
// Avoid duplicate loading - the offset will be wrong and it will result
// in duplicate messages shown in the page
return;
}
- messageTable.loading = true;
-
- mw.translate.getMessages( messagegroup, targetLangCode, offset, pageSize, filter )
- .done( function ( result ) {
- var messages = result.query.messagecollection,
- state;
+ this.loading = true;
+ this.$loaderIcon.removeClass( 'tux-loading-indicator--stopped' );
+
+ mw.translate.getMessages(
+ this.settings.group,
+ this.settings.language,
+ offset,
+ pageSize,
+ this.settings.filter
+ ).done( function ( result ) {
+ var messages = result.query.messagecollection,
+ state, i;
+
+ if ( !self.loading ) {
+ // reject. This was cancelled.
+ return;
+ }
- if ( !messageTable.loading ) {
- // reject. This was cancelled.
- return;
+ if ( result.warnings ) {
+ for ( i = 0; i !== result.warnings.length; i++ ) {
+ if ( result.warnings[ i ].code === 'translate-language-disabled-source' ) {
+ self.handleLoadErrors( [ result.warnings[ i ] ] );
+ break;
+ }
}
+ return;
+ }
- messageTable.loading = false;
-
- if ( messages.length === 0 ) {
- // And this is the first load for the filter...
- if ( messageTable.$container.children().length === 0 ) {
- messageTable.displayEmptyListHelp();
- }
+ if ( messages.length === 0 ) {
+ // And this is the first load for the filter...
+ if ( self.$container.children().length === 0 ) {
+ self.displayEmptyListHelp();
}
+ }
- $.each( messages, function ( index, message ) {
- message.group = messagegroup;
- messageTable.add( message );
- messageTable.messages.push( message );
+ $.each( messages, function ( index, message ) {
+ message.group = self.settings.group;
+ self.add( message );
+ self.messages.push( message );
- if ( index === 0 && messageTable.mode === 'translate' ) {
- $( '.tux-message:first' ).data( 'translateeditor' ).init();
- }
- } );
+ if ( index === 0 && self.mode === 'translate' ) {
+ $( '.tux-message:first' ).data( 'translateeditor' ).init();
+ }
+ } );
- state = result.query.metadata && result.query.metadata.state;
- $( '.tux-workflow' ).workflowselector( messagegroup, targetLangCode, state );
+ state = result.query.metadata && result.query.metadata.state;
+ $( '.tux-workflow' ).workflowselector(
+ self.settings.group,
+ self.settings.language,
+ state
+ ).removeClass( 'hide' );
- // Dynamically loaded messages should pass the search filter if present.
- query = $( '.tux-message-filter-box' ).val();
+ // Dynamically loaded messages should pass the search filter if present.
+ query = $( '.tux-message-filter-box' ).val();
- if ( query ) {
- messageTable.search( query );
- }
+ if ( query ) {
+ self.search( query );
+ }
- if ( result[ 'query-continue' ] === undefined ) {
- // End of messages
- messageTable.$loader.data( 'offset', -1 )
- .addClass( 'hide' );
- } else {
- messageTable.$loader.data( 'offset', result[ 'query-continue' ].messagecollection.mcoffset );
+ if ( result[ 'query-continue' ] === undefined || limit ) {
+ // End of messages
+ self.$loader.data( 'offset', -1 )
+ .addClass( 'hide' );
- remaining = result.query.metadata.remaining;
+ // Helpfully open the first message in show mode
+ // TODO: Refactor to avoid direct DOM access
+ $( '.tux-message-item' ).first().click();
+ } else {
+ self.$loader.data( 'offset', result[ 'query-continue' ].messagecollection.mcoffset );
- $( '.tux-messagetable-loader-count' ).text(
- mw.msg( 'tux-messagetable-more-messages', remaining )
- );
+ remaining = result.query.metadata.remaining;
- $( '.tux-messagetable-loader-more' ).text(
- mw.msg( 'tux-messagetable-loading-messages', Math.min( remaining, pageSize ) )
- );
+ self.$loaderInfo.text(
+ mw.msg( 'tux-messagetable-more-messages', remaining )
+ );
- // Make sure the floating toolbars are visible without the need for scroll
- $( window ).trigger( 'scroll' );
- }
+ // Make sure the floating toolbars are visible without the need for scroll
+ $( window ).trigger( 'scroll' );
+ }
- messageTable.updateLastMessage();
- } )
- .fail( function ( errorCode, response ) {
- if ( response.error && response.error.code === 'mctranslate-language-disabled' ) {
- $( '.tux-editor-header .group-warning' )
- .text( mw.msg( 'translate-language-disabled' ) )
- .show();
- }
- messageTable.$loader.data( 'offset', -1 ).addClass( 'hide' );
- messageTable.loading = false;
- } );
+ self.updateHideOwnInProofreadingToggleVisibility();
+ self.updateLastMessage();
+ } ).fail( function ( errorCode, response ) {
+ self.handleLoadErrors( response.errors, errorCode );
+ } ).always( function () {
+ self.$loaderIcon.addClass( 'tux-loading-indicator--stopped' );
+ self.loading = false;
+ } );
},
updateLastMessage: function () {
@@ -527,12 +572,33 @@
*/
otherActionButton: function ( labelMsg, callback ) {
return $( '<button>' )
- .addClass( 'green button' )
+ .addClass( 'mw-ui-button mw-ui-progressive mw-ui-big' )
.text( mw.msg( labelMsg ) )
.on( 'click', callback );
},
/**
+ * Enables own message hiding in proofread mode.
+ *
+ * @param {boolean} enabled
+ */
+ setHideOwnInProofreading: function ( enabled ) {
+ if ( enabled ) {
+ this.$container.addClass( 'tux-hide-own' );
+ } else {
+ this.$container.removeClass( 'tux-hide-own' );
+ }
+ },
+
+ updateHideOwnInProofreadingToggleVisibility: function () {
+ if ( this.$container.find( '.tux-message-proofread.own-translation' ).length ) {
+ this.$proofreadOwnTranslations.removeClass( 'hide' );
+ } else {
+ this.$proofreadOwnTranslations.addClass( 'hide' );
+ }
+ },
+
+ /**
* If the user selection doesn't show anything,
* give some pointers to other things to do.
*/
@@ -635,14 +701,13 @@
*/
switchMode: function ( mode ) {
var messageTable = this,
- filter = messageTable.$loader.data( 'filter' ),
+ filter = this.settings.filter,
userId = mw.config.get( 'wgUserId' ),
$tuxTabUntranslated,
$tuxTabUnproofread,
- $controlOwnButton,
$hideTranslatedButton;
- messageTable.$actionBar.find( '.down' ).removeClass( 'down' );
+ messageTable.$actionBar.find( '.tux-view-switcher .down' ).removeClass( 'down' );
if ( mode === 'translate' ) {
messageTable.$actionBar.find( '.translate-mode-button' ).addClass( 'down' );
}
@@ -660,11 +725,10 @@
// Emulate clear without clearing loaded messages
messageTable.$container.empty();
- $( '.translate-tipsy' ).remove();
+ $( '.translate-tooltip' ).remove();
$tuxTabUntranslated = $( '.tux-message-selector > .tux-tab-untranslated' );
$tuxTabUnproofread = $( '.tux-message-selector > .tux-tab-unproofread' );
- $controlOwnButton = messageTable.$actionBar.find( '.tux-proofread-own-translations-button' );
$hideTranslatedButton = messageTable.$actionBar.find( '.tux-editor-clear-translated' );
if ( messageTable.mode === 'proofread' ) {
@@ -679,16 +743,15 @@
mw.translate.changeFilter( 'translated|!reviewer:' + userId +
'|!last-translator:' + userId );
$tuxTabUnproofread.addClass( 'selected' );
+ // Own translations are not present in proofread + unreviewed mode
}
- $controlOwnButton.removeClass( 'hide' );
$hideTranslatedButton.addClass( 'hide' );
} else {
$tuxTabUntranslated.removeClass( 'hide' );
$tuxTabUnproofread.addClass( 'hide' );
- $controlOwnButton.addClass( 'hide' );
- if ( messageTable.$loader.data( 'filter' ).indexOf( '!translated' ) > -1 ) {
+ if ( filter.indexOf( '!translated' ) > -1 ) {
$hideTranslatedButton.removeClass( 'hide' );
}
@@ -708,6 +771,11 @@
messageTable.displayEmptyListHelp();
}
+ this.$loaderInfo.text(
+ mw.msg( 'tux-messagetable-loading-messages', this.$loader.data( 'pagesize' ) )
+ );
+
+ messageTable.updateHideOwnInProofreadingToggleVisibility();
messageTable.updateLastMessage();
},
@@ -759,6 +827,30 @@
} else if ( isActionBarFloating && needsActionBarFloat ) {
this.$actionBar.width( messageListWidth );
}
+ },
+
+ /**
+ * Handles errors encountered during the loading state.
+ * Displays the errors and updates the state of the table.
+ *
+ * @param {Array} errors
+ * @param {string} errorCode
+ */
+ handleLoadErrors: function ( errors, errorCode ) {
+ var $warningContainer = $( '.tux-editor-header .group-warning' );
+
+ if ( errors ) {
+ $.map( errors, function ( error ) {
+ $warningContainer.append( error[ '*' ] );
+ } );
+ } else {
+ $warningContainer.text( mw.msg( 'api-error-unknownerror', errorCode ) );
+ }
+
+ $( '.tux-workflow' ).addClass( 'hide' );
+ this.$loader.data( 'offset', -1 ).addClass( 'hide' );
+ this.$actionBar.addClass( 'hide' );
+ this.$header.addClass( 'hide' );
}
};
@@ -787,44 +879,6 @@
mode: new mw.Uri().query.action || 'translate'
};
- $( 'document' ).ready( function () {
- var api = new mw.Api();
-
- // Currently used only in the pre-TUX editor
- $( '.mw-translate-messagereviewbutton' ).click( function () {
- var $b, successFunction, failFunction, params;
- $b = $( this );
-
- successFunction = function ( data ) {
- var reason;
-
- if ( data.error ) {
- // Give grep a chance to find the usages:
- // api-error-invalidrevision, api-error-unknownmessage,
- // api-error-fuzzymessage, api-error-owntranslation
- reason = mw.msg( 'api-error-' + data.error.code );
- $b.val( mw.msg( 'translate-messagereview-failure', reason ) );
- } else {
- $b.val( mw.msg( 'translate-messagereview-done' ) );
- }
- };
-
- failFunction = function ( jqXHR ) {
- $b.val( mw.msg( 'translate-messagereview-failure', jqXHR.statusText ) );
- };
-
- params = {
- action: 'translationreview',
- revision: $b.data( 'revision' )
- };
- $b.val( mw.msg( 'translate-messagereview-progress' ) );
- $b.prop( 'disabled', true );
-
- // Change to csrf when support for MW 1.25 is dropped
- api.postWithToken( 'edit', params ).done( successFunction ).fail( failFunction );
- } );
- } );
-
/**
* Escape the search query for regex match.
*
@@ -832,6 +886,20 @@
* @return {string} Escaped string that is safe to use for a search.
*/
function escapeRegex( value ) {
- return value.replace( /[\-\[\]{}()*+?.,\\\^$\|#\s]/g, '\\$&' );
+ return value.replace( /[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&' );
}
-}( jQuery, mediaWiki ) );
+
+ function isLoaderVisible( $loader ) {
+ var viewportBottom, elementTop,
+ $window = $( window );
+
+ viewportBottom = ( window.innerHeight ? window.innerHeight : $window.height() ) +
+ $window.scrollTop();
+
+ elementTop = $loader.offset().top;
+
+ // Start already if user is reaching close to the bottom
+ return elementTop - viewportBottom < 200;
+ }
+
+}() );