Santhosh has uploaded a new change for review.

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

Change subject: [WIP] A generic callout widget
......................................................................

[WIP] A generic callout widget

Change-Id: I0c6bc6b24b2ca903733bed2a4955741d46dc9ea6
---
A modules/widgets/callout/ext.cx.callout.css
A modules/widgets/callout/ext.cx.callout.js
2 files changed, 476 insertions(+), 0 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/ContentTranslation 
refs/changes/74/196574/1

diff --git a/modules/widgets/callout/ext.cx.callout.css 
b/modules/widgets/callout/ext.cx.callout.css
new file mode 100644
index 0000000..6d5efe4
--- /dev/null
+++ b/modules/widgets/callout/ext.cx.callout.css
@@ -0,0 +1,209 @@
+.cx-callout {
+       color: #333;
+       position: absolute;
+       overflow: visible;
+       padding: 20px;
+       background: white;
+       border: 1px solid #ccc;
+       border-bottom-width: 3px;
+       border-radius: 3px;
+       max-width: 500px;
+    z-index: 100000;
+    cursor: default;
+}
+
+.cx-callout-w::after, .cx-callout-w::before {
+       right: 100%;
+       top: 50%;
+       border: solid transparent;
+       content: " ";
+       height: 0;
+       width: 0;
+       position: absolute;
+       pointer-events: none;
+}
+
+.cx-callout-w::after {
+       border-color: transparent;
+       border-right-color: #fff;
+       border-width: 12px;
+       margin-top: -12px;
+}
+.cx-callout-w::before {
+       border-color: transparent;
+       border-right-color: #ccc;
+       border-width: 13px;
+       margin-top: -13px;
+}
+
+
+.cx-callout-e:after, .cx-callout-e:before {
+       left: 100%;
+       top: 50%;
+       border: solid transparent;
+       content: " ";
+       height: 0;
+       width: 0;
+       position: absolute;
+       pointer-events: none;
+}
+
+.cx-callout-e:after {
+       border-color: transparent;
+       border-left-color: #fff;
+       border-width: 12px;
+       margin-top: -12px;
+}
+.cx-callout-e:before {
+       border-color: transparent;
+       border-left-color: #ccc;
+       border-width: 13px;
+       margin-top: -13px;
+}
+
+
+.cx-callout-n:after, .cx-callout-n:before {
+       bottom: 100%;
+       left: 50%;
+       border: solid transparent;
+       content: " ";
+       height: 0;
+       width: 0;
+       position: absolute;
+       pointer-events: none;
+}
+
+.cx-callout-n:after {
+       border-color: transparent;
+       border-bottom-color: #fff;
+       border-width: 12px;
+       margin-left: -12px;
+}
+.cx-callout-n:before {
+       border-color: transparent;
+       border-bottom-color: #ccc;
+       border-width: 13px;
+       margin-left: -13px;
+}
+
+.cx-callout-nw:after, .cx-callout-nw:before {
+       bottom: 100%;
+       left: 25%;
+       border: solid transparent;
+       content: " ";
+       height: 0;
+       width: 0;
+       position: absolute;
+       pointer-events: none;
+}
+
+.cx-callout-nw:after {
+       border-color: transparent;
+       border-bottom-color: #fff;
+       border-width: 12px;
+       margin-left: -12px;
+}
+
+.cx-callout-nw:before {
+       border-color: transparent;
+       border-bottom-color: #ccc;
+       border-width: 13px;
+       margin-left: -13px;
+}
+
+.cx-callout-ne:after, .cx-callout-ne:before {
+       bottom: 100%;
+       left: 75%;
+       border: solid transparent;
+       content: " ";
+       height: 0;
+       width: 0;
+       position: absolute;
+       pointer-events: none;
+}
+
+.cx-callout-ne:after {
+       border-color: transparent;
+       border-bottom-color: #fff;
+       border-width: 12px;
+       margin-left: -12px;
+}
+.cx-callout-ne:before {
+       border-color: transparent;
+       border-bottom-color: #ccc;
+       border-width: 13px;
+       margin-left: -13px;
+}
+
+.cx-callout-s:after, .cx-callout-s:before {
+       top: 100%;
+       left: 50%;
+       border: solid transparent;
+       content: " ";
+       height: 0;
+       width: 0;
+       position: absolute;
+       pointer-events: none;
+}
+
+.cx-callout-s:after {
+       border-color: transparent;
+       border-top-color: #fff;
+       border-width: 12px;
+       margin-left: -12px;
+}
+.cx-callout-s:before {
+       border-color: transparent;
+       border-top-color: #ccc;
+       border-width: 13px;
+       margin-left: -13px;
+}
+
+.cx-callout-sw:after, .cx-callout-sw:before {
+       top: 100%;
+       left: 25%;
+       border: solid transparent;
+       content: " ";
+       height: 0;
+       width: 0;
+       position: absolute;
+       pointer-events: none;
+}
+
+.cx-callout-sw:after {
+       border-color: transparent;
+       border-top-color: #fff;
+       border-width: 12px;
+       margin-left: -12px;
+}
+.cx-callout-sw:before {
+       border-color: transparent;
+       border-top-color: #ccc;
+       border-width: 13px;
+       margin-left: -13px;
+}
+
+.cx-callout-se:after, .cx-callout-se:before {
+       top: 100%;
+       left: 75%;
+       border: solid transparent;
+       content: " ";
+       height: 0;
+       width: 0;
+       position: absolute;
+       pointer-events: none;
+}
+
+.cx-callout-se:after {
+       border-color: transparent;
+       border-top-color: #fff;
+       border-width: 12px;
+       margin-left: -12px;
+}
+
+.cx-callout-se:before {
+       border-color: transparent;
+       border-top-color: #ccc;
+       border-width: 13px;
+       margin-left: -13px;
+}
diff --git a/modules/widgets/callout/ext.cx.callout.js 
b/modules/widgets/callout/ext.cx.callout.js
new file mode 100644
index 0000000..298d771
--- /dev/null
+++ b/modules/widgets/callout/ext.cx.callout.js
@@ -0,0 +1,267 @@
+/**
+ * @file
+ * @ingroup Extensions
+ * @copyright See AUTHORS.txt
+ * @license GPL-2.0+
+ */
+( function ( $ ) {
+       'use strict';
+
+       function maybeCall( thing, ctx ) {
+               return ( typeof thing === 'function' ) ? ( thing.call( ctx ) ) 
: thing;
+       }
+
+       function Callout( element, options ) {
+               this.$element = $( element );
+               this.options = $.extend( {}, $.fn.callout.defaults, options );
+               this.shown = false;
+               this.listen();
+       }
+
+       Callout.prototype.show = function () {
+               var $dialog, content;
+
+               content = maybeCall( this.options.content );
+               if ( !content ) {
+                       return;
+               }
+
+               $dialog = this.dialog();
+               $dialog.find( '.cx-callout-content' ).html( content );
+               $dialog[ 0 ].className = 'cx-callout'; // reset classname in 
case of dynamic gravity
+
+               $dialog.remove().css( {
+                       top: 0,
+                       left: 0,
+                       visibility: 'hidden',
+                       display: 'block'
+               } ).appendTo( document.body );
+
+               this.position();
+
+               if ( this.options.fade ) {
+                       $dialog.stop().css( {
+                               opacity: 0,
+                               display: 'block',
+                               visibility: 'visible'
+                       } ).animate( {
+                               opacity: this.options.opacity
+                       }, 100 );
+               } else {
+                       $dialog.css( {
+                               visibility: 'visible',
+                               opacity: this.options.opacity
+                       } );
+               }
+               this.shown = true;
+       };
+
+       Callout.prototype.position = function () {
+               var $dialog, pos, gravity, actualWidth, actualHeight, position;
+
+               pos = $.extend( {}, this.$element.offset(), {
+                       width: this.$element[ 0 ].offsetWidth,
+                       height: this.$element[ 0 ].offsetHeight
+               } );
+
+               $dialog = this.dialog();
+               gravity = ( typeof this.options.gravity === 'function' ) ? 
this.options.gravity.call( this.$element[ 0 ] ) : this.options.gravity;
+
+               // Attach css classes before checking height/width so they
+               // can be applied.
+               $dialog.addClass( 'cx-callout-' + gravity );
+
+               actualWidth = $dialog[ 0 ].offsetWidth;
+               actualHeight = $dialog[ 0 ].offsetHeight;
+               switch ( gravity.charAt( 0 ) ) {
+               case 'n':
+                       position = {
+                               top: pos.top + pos.height + this.options.offset,
+                               left: pos.left + pos.width / 2 - actualWidth / 2
+                       };
+                       break;
+               case 's':
+                       position = {
+                               top: pos.top - actualHeight - 
this.options.offset,
+                               left: pos.left + pos.width / 2 - actualWidth / 2
+                       };
+                       break;
+               case 'e':
+                       position = {
+                               top: pos.top + pos.height / 2 - actualHeight / 
2,
+                               left: pos.left - actualWidth - 
this.options.offset
+                       };
+                       break;
+               case 'w':
+                       position = {
+                               top: pos.top + pos.height / 2 - actualHeight / 
2,
+                               left: pos.left + pos.width + this.options.offset
+                       };
+                       break;
+               }
+
+               if ( gravity.length === 2 ) {
+                       if ( gravity.charAt( 1 ) === 'w' ) {
+                               if ( this.options.center ) {
+                                       position.left = pos.left + pos.width / 
2 - 15;
+                               } else {
+                                       position.left = pos.left;
+                               }
+                       } else {
+                               if ( this.options.center ) {
+                                       position.left = pos.left + pos.width / 
2 - actualWidth + 15;
+                               } else {
+                                       position.left = pos.left + pos.width;
+                               }
+                       }
+               }
+               $dialog.css( position );
+       };
+
+       Callout.prototype.listen = function () {
+               var timer, self = this;
+
+               if ( this.options.trigger === 'hover' ) {
+                       this.$element.hover( function () {
+                               self.show();
+                       }, function () {
+                               self.hide();
+                       } );
+               }
+               if ( this.options.trigger === 'click' ) {
+                       this.$element.on( 'click', function () {
+                               if ( self.shown ) {
+                                       self.hide();
+                               } else {
+                                       self.show();
+                               }
+                       } );
+               }
+               $( window ).resize( function () {
+                       clearTimeout( timer );
+                       timer = setTimeout( function () {
+                               self.position();
+                       }, 200 );
+               } );
+       };
+
+       Callout.prototype.hide = function () {
+               if ( this.options.fade ) {
+                       this.dialog().stop().fadeOut( 100, function () {
+                               $( this ).remove();
+                       } );
+               } else {
+                       this.dialog().remove();
+               }
+               this.shown = false;
+       };
+
+       Callout.prototype.dialog = function () {
+               if ( !this.$dialog ) {
+                       this.$dialog = $( '<div class="cx-callout"></div>' 
).html( '</div><div class="cx-callout-content"></div>' );
+               }
+               return this.$dialog;
+       };
+
+       Callout.prototype.validate = function () {
+               if ( !this.$element[ 0 ].parentNode ) {
+                       this.hide();
+                       this.$element = null;
+                       this.options = null;
+               }
+       };
+
+       $.fn.callout = function ( options ) {
+               if ( options === true ) {
+                       return this.data( 'callout' );
+               } else if ( typeof options === 'string' ) {
+                       var callout = this.data( 'callout' );
+                       if ( callout ) {
+                               callout[ options ]();
+                       }
+                       return this;
+               }
+
+               function get( ele ) {
+                       var callout = $.data( ele, 'callout' );
+                       if ( !callout ) {
+                               callout = new Callout( ele, 
$.fn.callout.elementOptions( ele, options ) );
+                               $.data( ele, 'callout', callout );
+                       }
+                       return callout;
+               }
+
+               this.each( function () {
+                       get( this );
+               } );
+
+               return this;
+       };
+
+       $.fn.callout.defaults = {
+               gravity: 'n',
+               center: true,
+               offset: 10,
+               opacity: 1.0,
+               trigger: 'hover'
+       };
+
+       // Overwrite this method to provide options on a per-element basis.
+       // For example, you could store the gravity in a 'cx-callout-gravity' 
attribute:
+       // return $.extend({}, options, {gravity: 
$(ele).attr('cx-callout-gravity') || 'n' });
+       // (remember - do not modify 'options' in place!)
+       $.fn.callout.elementOptions = function ( ele, options ) {
+               return $.metadata ? $.extend( {}, options, $( ele ).metadata() 
) : options;
+       };
+
+       $.fn.callout.autoNS = function () {
+               return $( this ).offset().top > ( $( document ).scrollTop() + 
$( window ).height() / 2 ) ? 's' : 'n';
+       };
+
+       $.fn.callout.autoWE = function () {
+               return $( this ).offset().left > ( $( document ).scrollLeft() + 
$( window ).width() / 2 ) ? 'e' : 'w';
+       };
+
+       /**
+        * yields a closure of the supplied parameters, producing a function 
that takes
+        * no arguments and is suitable for use as an autogravity function like 
so:
+        *
+        * @param margin (int) - distance from the viewable region edge that an
+        *        element should be before setting its tooltip's gravity to be 
away
+        *        from that edge.
+        * @param prefer (string, e.g. 'n', 'sw', 'w') - the direction to prefer
+        *        if there are no viewable region edges effecting the tooltip's
+        *        gravity. It will try to vary from this minimally, for example,
+        *        if 'sw' is preferred and an element is near the right viewable
+        *        region edge, but not the top edge, it will set the gravity for
+        *        that element's tooltip to be 'se', preserving the southern
+        *        component.
+        */
+       $.fn.callout.autoBounds = function ( margin, prefer ) {
+               return function () {
+                       var dir = {
+                                       ns: prefer[ 0 ],
+                                       ew: ( prefer.length > 1 ? prefer[ 1 ] : 
false )
+                               },
+                               boundTop = $( document ).scrollTop() + margin,
+                               boundLeft = $( document ).scrollLeft() + margin,
+                               $this = $( this );
+
+                       if ( $this.offset().top < boundTop ) {
+                               dir.ns = 'n';
+                       }
+                       if ( $this.offset().left < boundLeft ) {
+                               dir.ew = 'w';
+                       }
+                       if ( $( window ).width() + $( document ).scrollLeft() - 
$this.offset().left < margin ) {
+                               dir.ew = 'e';
+                       }
+                       if ( $( window ).height() + $( document ).scrollTop() - 
$this.offset().top < margin ) {
+                               dir.ns = 's';
+                       }
+
+                       return dir.ns + ( dir.ew ? dir.ew : '' );
+               };
+       };
+
+}( jQuery ) );

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0c6bc6b24b2ca903733bed2a4955741d46dc9ea6
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/ContentTranslation
Gerrit-Branch: master
Gerrit-Owner: Santhosh <santhosh.thottin...@gmail.com>

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

Reply via email to