Przeglądaj źródła

Improved, more user friendly tooltips.

j8
yanas 11 lat temu
rodzic
commit
73cd3c04f6
9 zmienionych plików z 679 dodań i 20 usunięć
  1. 3
    0
      app.js
  2. 124
    0
      css/popover.css
  3. 2
    2
      css/popup_menu.css
  4. 2
    1
      css/videolayout_default.css
  5. 18
    13
      index.html
  6. 110
    0
      libs/popover.js
  7. 399
    0
      libs/tooltip.js
  8. 8
    1
      util.js
  9. 13
    3
      videolayout.js

+ 3
- 0
app.js Wyświetl plik

889
 $(document).ready(function () {
889
 $(document).ready(function () {
890
     Chat.init();
890
     Chat.init();
891
 
891
 
892
+    $('body').popover({ selector: '[data-toggle=popover]',
893
+                        trigger: 'click hover'});
894
+
892
     // Set the defaults for prompt dialogs.
895
     // Set the defaults for prompt dialogs.
893
     jQuery.prompt.setDefaults({persistent: false});
896
     jQuery.prompt.setDefaults({persistent: false});
894
 
897
 

+ 124
- 0
css/popover.css Wyświetl plik

1
+.popover {
2
+  position: absolute;
3
+  top: 0;
4
+  left: 0;
5
+  z-index: 1010;
6
+  display: none;
7
+  max-width: 300px;
8
+  min-width: 100px;
9
+  padding: 1px;
10
+  text-align: left;
11
+  color: #428bca;
12
+  background-color: #ffffff;
13
+  background-clip: padding-box;
14
+  border: 1px solid #cccccc;
15
+  border: 1px solid rgba(0, 0, 0, 0.2);
16
+  border-radius: 6px;
17
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
18
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.4);
19
+  white-space: normal;
20
+}
21
+.popover.top {
22
+  margin-top: -10px;
23
+}
24
+.popover.right {
25
+  margin-left: 10px;
26
+}
27
+.popover.bottom {
28
+  margin-top: 10px;
29
+}
30
+.popover.left {
31
+  margin-left: -10px;
32
+}
33
+.popover-title {
34
+  margin: 0;
35
+  padding: 8px 14px;
36
+  font-size: 11pt;
37
+  font-weight: normal;
38
+  line-height: 18px;
39
+  background-color: #f7f7f7;
40
+  border-bottom: 1px solid #ebebeb;
41
+  border-radius: 5px 5px 0 0;
42
+}
43
+.popover-content {
44
+  padding: 9px 14px;
45
+  font-size: 10pt;
46
+  white-space:pre-wrap;
47
+  text-align: center;
48
+}
49
+.popover > .arrow,
50
+.popover > .arrow:after {
51
+  position: absolute;
52
+  display: block;
53
+  width: 0;
54
+  height: 0;
55
+  border-color: transparent;
56
+  border-style: solid;
57
+}
58
+.popover > .arrow {
59
+  border-width: 11px;
60
+}
61
+.popover > .arrow:after {
62
+  border-width: 10px;
63
+  content: "";
64
+}
65
+.popover.top > .arrow {
66
+  left: 50%;
67
+  margin-left: -11px;
68
+  border-bottom-width: 0;
69
+  border-top-color: #999999;
70
+  border-top-color: rgba(0, 0, 0, 0.25);
71
+  bottom: -11px;
72
+}
73
+.popover.top > .arrow:after {
74
+  content: " ";
75
+  bottom: 1px;
76
+  margin-left: -10px;
77
+  border-bottom-width: 0;
78
+  border-top-color: #ffffff;
79
+}
80
+.popover.right > .arrow {
81
+  top: 50%;
82
+  left: -11px;
83
+  margin-top: -11px;
84
+  border-left-width: 0;
85
+  border-right-color: #999999;
86
+  border-right-color: rgba(0, 0, 0, 0.25);
87
+}
88
+.popover.right > .arrow:after {
89
+  content: " ";
90
+  left: 1px;
91
+  bottom: -10px;
92
+  border-left-width: 0;
93
+  border-right-color: #ffffff;
94
+}
95
+.popover.bottom > .arrow {
96
+  left: 50%;
97
+  margin-left: -11px;
98
+  border-top-width: 0;
99
+  border-bottom-color: #999999;
100
+  border-bottom-color: rgba(0, 0, 0, 0.25);
101
+  top: -11px;
102
+}
103
+.popover.bottom > .arrow:after {
104
+  content: " ";
105
+  top: 1px;
106
+  margin-left: -10px;
107
+  border-top-width: 0;
108
+  border-bottom-color: #ffffff;
109
+}
110
+.popover.left > .arrow {
111
+  top: 50%;
112
+  right: -11px;
113
+  margin-top: -11px;
114
+  border-right-width: 0;
115
+  border-left-color: #999999;
116
+  border-left-color: rgba(0, 0, 0, 0.25);
117
+}
118
+.popover.left > .arrow:after {
119
+  content: " ";
120
+  right: 1px;
121
+  border-right-width: 0;
122
+  border-left-color: #ffffff;
123
+  bottom: -10px;
124
+}

+ 2
- 2
css/popup_menu.css Wyświetl plik

9
     padding-bottom: 5px;
9
     padding-bottom: 5px;
10
     padding-top: 5px;
10
     padding-top: 5px;
11
     right: 10px;
11
     right: 10px;
12
-    left: 0px;
12
+    left: -5px;
13
     width: 100px;
13
     width: 100px;
14
     background-color: rgba(0,0,0,1);
14
     background-color: rgba(0,0,0,1);
15
     -webkit-box-shadow: 0 0 2px #000000, 0 0 10px #000000;
15
     -webkit-box-shadow: 0 0 2px #000000, 0 0 10px #000000;
21
     display: block;
21
     display: block;
22
     position: absolute;
22
     position: absolute;
23
     bottom: -9px;
23
     bottom: -9px;
24
-    left: 13px;
24
+    left: 11px;
25
 }
25
 }
26
 
26
 
27
 ul.popupmenu li {
27
 ul.popupmenu li {

+ 2
- 1
css/videolayout_default.css Wyświetl plik

122
     text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
122
     text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
123
     border: 0px;
123
     border: 0px;
124
     z-index: 2;
124
     z-index: 2;
125
+    text-align: center;
125
 }
126
 }
126
 
127
 
127
 #remoteVideos .nick {
128
 #remoteVideos .nick {
194
     text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
195
     text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
195
     border: 0px;
196
     border: 0px;
196
     z-index: 3;
197
     z-index: 3;
198
+    text-align: center;
197
 }
199
 }
198
 
200
 
199
 .videocontainer>span.videoMuted {
201
 .videocontainer>span.videoMuted {
245
     margin-right:auto;
247
     margin-right:auto;
246
     height:39px;
248
     height:39px;
247
     width:auto;
249
     width:auto;
248
-    overflow: hidden;
249
     background: linear-gradient(to bottom, rgba(103,103,103,.65) , rgba(0,0,0,.65));
250
     background: linear-gradient(to bottom, rgba(103,103,103,.65) , rgba(0,0,0,.65));
250
     -webkit-box-shadow: 0 0 2px #000000, 0 0 10px #000000;
251
     -webkit-box-shadow: 0 0 2px #000000, 0 0 10px #000000;
251
     border-bottom-left-radius: 12px;
252
     border-bottom-left-radius: 12px;

+ 18
- 13
index.html Wyświetl plik

20
     <script src="libs/colibri/colibri.focus.js?v=8"></script><!-- colibri focus implementation -->
20
     <script src="libs/colibri/colibri.focus.js?v=8"></script><!-- colibri focus implementation -->
21
     <script src="libs/colibri/colibri.session.js?v=1"></script>
21
     <script src="libs/colibri/colibri.session.js?v=1"></script>
22
     <script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
22
     <script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
23
+    <script src="libs/tooltip.js?v=1"></script><!-- bootstrap tooltip lib -->
24
+    <script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
23
     <script src="config.js?v=2"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
25
     <script src="config.js?v=2"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
24
     <script src="muc.js?v=11"></script><!-- simple MUC library -->
26
     <script src="muc.js?v=11"></script><!-- simple MUC library -->
25
     <script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
27
     <script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
44
     <link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
46
     <link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
45
     <link rel="stylesheet" href="css/modaldialog.css?v=3">
47
     <link rel="stylesheet" href="css/modaldialog.css?v=3">
46
     <link rel="stylesheet" href="css/popup_menu.css?v=1">
48
     <link rel="stylesheet" href="css/popup_menu.css?v=1">
49
+    <link rel="stylesheet" href="css/popover.css?v=1">
47
     <!--
50
     <!--
48
         Link used for inline installation of chrome desktop streaming extension,
51
         Link used for inline installation of chrome desktop streaming extension,
49
         is updated automatically from the code with the value defined in config.js -->
52
         is updated automatically from the code with the value defined in config.js -->
55
   <body>
58
   <body>
56
     <div id="header">
59
     <div id="header">
57
         <span id="toolbar">
60
         <span id="toolbar">
58
-            <a class="button" onclick='toggleAudio();'>
59
-                <i id="mute" title="Mute / unmute" class="icon-microphone"></i></a>
61
+            <a class="button" data-toggle="popover" data-placement="bottom" data-content="Mute / Unmute" onclick='toggleAudio();'>
62
+                <i id="mute" class="icon-microphone"></i></a>
60
             <div class="header_button_separator"></div>
63
             <div class="header_button_separator"></div>
61
-            <a class="button" onclick='buttonClick("#video", "icon-camera icon-camera-disabled");toggleVideo();'>
62
-                <i id="video" title="Start / stop camera" class="icon-camera"></i></a>
64
+            <a class="button" data-toggle="popover" data-placement="bottom" data-content="Start / stop camera" onclick='buttonClick("#video", "icon-camera icon-camera-disabled");toggleVideo();'>
65
+                <i id="video" class="icon-camera"></i></a>
63
             <div class="header_button_separator"></div>
66
             <div class="header_button_separator"></div>
64
-            <a class="button" onclick="openLockDialog();" title="Lock/unlock room"><i id="lockIcon" class="icon-security"></i></a>
67
+            <a class="button" data-toggle="popover" data-placement="bottom" data-content="Lock / unlock room" onclick="Toolbar.openLockDialog();">
68
+                <i id="lockIcon" class="icon-security"></i></a>
65
             <div class="header_button_separator"></div>
69
             <div class="header_button_separator"></div>
66
-            <a class="button" onclick="openLinkDialog();" title="Invite others"><i class="icon-link"></i></a>
70
+            <a class="button" data-toggle="popover" data-placement="bottom" data-content="Invite others" onclick="Toolbar.openLinkDialog();"><i class="icon-link"></i></a>
67
             <div class="header_button_separator"></div>
71
             <div class="header_button_separator"></div>
68
             <span class="toolbar_span">
72
             <span class="toolbar_span">
69
-                <a class="button" onclick='Chat.toggleChat();' title="Open chat"><i id="chatButton" class="icon-chat"></i></a>
73
+                <a class="button" data-toggle="popover" data-placement="bottom" data-content="Open / close chat" onclick='Chat.toggleChat();'><i id="chatButton" class="icon-chat"></i></a>
70
                 <span id="unreadMessages"></span>
74
                 <span id="unreadMessages"></span>
71
             </span>
75
             </span>
72
             <div class="header_button_separator"></div>
76
             <div class="header_button_separator"></div>
73
-            <a class="button" onclick='Prezi.openPreziDialog();' title="Share Prezi"><i class="icon-prezi"></i></a>
77
+            <a class="button" data-toggle="popover" data-placement="bottom" data-content="Share Prezi" onclick='Prezi.openPreziDialog();'><i class="icon-prezi"></i></a>
74
             <span id="etherpadButton">
78
             <span id="etherpadButton">
75
                 <div class="header_button_separator"></div>
79
                 <div class="header_button_separator"></div>
76
-                <a class="button" onclick='Etherpad.toggleEtherpad(0);' title="Open shared document"><i class="icon-share-doc"></i></a>
80
+                <a class="button" data-toggle="popover" data-placement="bottom" data-content="Shared document" onclick='Etherpad.toggleEtherpad(0);'><i class="icon-share-doc"></i></a>
77
             </span>
81
             </span>
78
             <div class="header_button_separator"></div>
82
             <div class="header_button_separator"></div>
79
             <span id="desktopsharing" style="display: none">
83
             <span id="desktopsharing" style="display: none">
80
-                <a class="button" onclick="toggleScreenSharing();" title="Share screen"><i class="icon-share-desktop"></i></a>
84
+                <a class="button" data-toggle="popover" data-placement="bottom" data-content="Share screen" onclick="toggleScreenSharing();"><i class="icon-share-desktop"></i></a>
81
                 <div class="header_button_separator"></div>
85
                 <div class="header_button_separator"></div>
82
             </span>
86
             </span>
83
-            <a class="button" onclick='buttonClick("#fullScreen", "icon-full-screen icon-exit-full-screen");Toolbar.toggleFullScreen();'><i id="fullScreen" title="Enter / Exit Full Screen" class="icon-full-screen"></i></a>
87
+            <a class="button" data-toggle="popover" data-placement="bottom" data-content="Enter / Exit Full Screen" onclick='buttonClick("#fullScreen", "icon-full-screen icon-exit-full-screen");Toolbar.toggleFullScreen();'>
88
+                <i id="fullScreen" class="icon-full-screen"></i></a>
84
         </span>
89
         </span>
85
     </div>
90
     </div>
86
     <div id="settings">
91
     <div id="settings">
108
                     <!--<video id="localVideo" autoplay oncontextmenu="return false;" muted></video> - is now per stream generated -->
113
                     <!--<video id="localVideo" autoplay oncontextmenu="return false;" muted></video> - is now per stream generated -->
109
                 </span>
114
                 </span>
110
                 <audio id="localAudio" autoplay oncontextmenu="return false;" muted></audio>
115
                 <audio id="localAudio" autoplay oncontextmenu="return false;" muted></audio>
111
-                <span class="focusindicator"></span>
116
+                <span class="focusindicator" data-content="The owner of&#10;this conference" data-toggle="popover" data-placement="top"></span>
112
             </span>
117
             </span>
113
             <audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
118
             <audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
114
             <audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
119
             <audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
127
         <audio id="chatNotification" src="sounds/incomingMessage.wav" preload="auto"></audio>
132
         <audio id="chatNotification" src="sounds/incomingMessage.wav" preload="auto"></audio>
128
         <textarea id="usermsg" placeholder='Enter text...' autofocus></textarea>
133
         <textarea id="usermsg" placeholder='Enter text...' autofocus></textarea>
129
     </div>
134
     </div>
130
-    <a id="downloadlog" onclick='dump(event.target);'><i title="Download support information" class="fa fa-cloud-download"></i></a>
135
+    <a id="downloadlog" onclick='dump(event.target);' data-toggle="popover" data-placement="right" data-content="Download logs" ><i class="fa fa-cloud-download"></i></a>
131
   </body>
136
   </body>
132
 </html>
137
 </html>

+ 110
- 0
libs/popover.js Wyświetl plik

1
+/* ========================================================================
2
+ * Bootstrap: popover.js v3.1.1
3
+ * http://getbootstrap.com/javascript/#popovers
4
+ * ========================================================================
5
+ * Copyright 2011-2014 Twitter, Inc.
6
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
7
+ * ======================================================================== */
8
+
9
+
10
++function ($) {
11
+  'use strict';
12
+
13
+  // POPOVER PUBLIC CLASS DEFINITION
14
+  // ===============================
15
+
16
+  var Popover = function (element, options) {
17
+    this.init('popover', element, options)
18
+  }
19
+
20
+  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
21
+
22
+  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
23
+    placement: 'right',
24
+    trigger: 'click',
25
+    content: '',
26
+    template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
27
+  })
28
+
29
+
30
+  // NOTE: POPOVER EXTENDS tooltip.js
31
+  // ================================
32
+
33
+  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
34
+
35
+  Popover.prototype.constructor = Popover
36
+
37
+  Popover.prototype.getDefaults = function () {
38
+    return Popover.DEFAULTS
39
+  }
40
+
41
+  Popover.prototype.setContent = function () {
42
+    var $tip    = this.tip()
43
+    var title   = this.getTitle()
44
+    var content = this.getContent()
45
+
46
+    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
47
+    $tip.find('.popover-content')[ // we use append for html objects to maintain js events
48
+      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
49
+    ](content)
50
+
51
+    $tip.removeClass('fade top bottom left right in')
52
+
53
+    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
54
+    // this manually by checking the contents.
55
+    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
56
+  }
57
+
58
+  Popover.prototype.hasContent = function () {
59
+    return this.getTitle() || this.getContent()
60
+  }
61
+
62
+  Popover.prototype.getContent = function () {
63
+    var $e = this.$element
64
+    var o  = this.options
65
+
66
+    return $e.attr('data-content')
67
+      || (typeof o.content == 'function' ?
68
+            o.content.call($e[0]) :
69
+            o.content)
70
+  }
71
+
72
+  Popover.prototype.arrow = function () {
73
+    return this.$arrow = this.$arrow || this.tip().find('.arrow')
74
+  }
75
+
76
+  Popover.prototype.tip = function () {
77
+    if (!this.$tip) this.$tip = $(this.options.template)
78
+    return this.$tip
79
+  }
80
+
81
+
82
+  // POPOVER PLUGIN DEFINITION
83
+  // =========================
84
+
85
+  var old = $.fn.popover
86
+
87
+  $.fn.popover = function (option) {
88
+    return this.each(function () {
89
+      var $this   = $(this)
90
+      var data    = $this.data('bs.popover')
91
+      var options = typeof option == 'object' && option
92
+
93
+      if (!data && option == 'destroy') return
94
+      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
95
+      if (typeof option == 'string') data[option]()
96
+    })
97
+  }
98
+
99
+  $.fn.popover.Constructor = Popover
100
+
101
+
102
+  // POPOVER NO CONFLICT
103
+  // ===================
104
+
105
+  $.fn.popover.noConflict = function () {
106
+    $.fn.popover = old
107
+    return this
108
+  }
109
+
110
+}(jQuery);

+ 399
- 0
libs/tooltip.js Wyświetl plik

1
+/* ========================================================================
2
+ * Bootstrap: tooltip.js v3.1.1
3
+ * http://getbootstrap.com/javascript/#tooltip
4
+ * Inspired by the original jQuery.tipsy by Jason Frame
5
+ * ========================================================================
6
+ * Copyright 2011-2014 Twitter, Inc.
7
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
8
+ * ======================================================================== */
9
+
10
+
11
++function ($) {
12
+  'use strict';
13
+
14
+  // TOOLTIP PUBLIC CLASS DEFINITION
15
+  // ===============================
16
+
17
+  var Tooltip = function (element, options) {
18
+    this.type       =
19
+    this.options    =
20
+    this.enabled    =
21
+    this.timeout    =
22
+    this.hoverState =
23
+    this.$element   = null
24
+
25
+    this.init('tooltip', element, options)
26
+  }
27
+
28
+  Tooltip.DEFAULTS = {
29
+    animation: true,
30
+    placement: 'top',
31
+    selector: false,
32
+    template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
33
+    trigger: 'hover focus',
34
+    title: '',
35
+    delay: 0,
36
+    html: false,
37
+    container: false
38
+  }
39
+
40
+  Tooltip.prototype.init = function (type, element, options) {
41
+    this.enabled  = true
42
+    this.type     = type
43
+    this.$element = $(element)
44
+    this.options  = this.getOptions(options)
45
+
46
+    var triggers = this.options.trigger.split(' ')
47
+
48
+    for (var i = triggers.length; i--;) {
49
+      var trigger = triggers[i]
50
+
51
+      if (trigger == 'click') {
52
+        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
53
+      } else if (trigger != 'manual') {
54
+        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
55
+        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
56
+
57
+        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
58
+        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
59
+      }
60
+    }
61
+
62
+    this.options.selector ?
63
+      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
64
+      this.fixTitle()
65
+  }
66
+
67
+  Tooltip.prototype.getDefaults = function () {
68
+    return Tooltip.DEFAULTS
69
+  }
70
+
71
+  Tooltip.prototype.getOptions = function (options) {
72
+    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
73
+
74
+    if (options.delay && typeof options.delay == 'number') {
75
+      options.delay = {
76
+        show: options.delay,
77
+        hide: options.delay
78
+      }
79
+    }
80
+
81
+    return options
82
+  }
83
+
84
+  Tooltip.prototype.getDelegateOptions = function () {
85
+    var options  = {}
86
+    var defaults = this.getDefaults()
87
+
88
+    this._options && $.each(this._options, function (key, value) {
89
+      if (defaults[key] != value) options[key] = value
90
+    })
91
+
92
+    return options
93
+  }
94
+
95
+  Tooltip.prototype.enter = function (obj) {
96
+    var self = obj instanceof this.constructor ?
97
+      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
98
+
99
+    clearTimeout(self.timeout)
100
+
101
+    self.hoverState = 'in'
102
+
103
+    if (!self.options.delay || !self.options.delay.show) return self.show()
104
+
105
+    self.timeout = setTimeout(function () {
106
+      if (self.hoverState == 'in') self.show()
107
+    }, self.options.delay.show)
108
+  }
109
+
110
+  Tooltip.prototype.leave = function (obj) {
111
+    var self = obj instanceof this.constructor ?
112
+      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
113
+
114
+    clearTimeout(self.timeout)
115
+
116
+    self.hoverState = 'out'
117
+
118
+    if (!self.options.delay || !self.options.delay.hide) return self.hide()
119
+
120
+    self.timeout = setTimeout(function () {
121
+      if (self.hoverState == 'out') self.hide()
122
+    }, self.options.delay.hide)
123
+  }
124
+
125
+  Tooltip.prototype.show = function () {
126
+    var e = $.Event('show.bs.' + this.type)
127
+
128
+    if (this.hasContent() && this.enabled) {
129
+      this.$element.trigger(e)
130
+
131
+      if (e.isDefaultPrevented()) return
132
+      var that = this;
133
+
134
+      var $tip = this.tip()
135
+
136
+      this.setContent()
137
+
138
+      if (this.options.animation) $tip.addClass('fade')
139
+
140
+      var placement = typeof this.options.placement == 'function' ?
141
+        this.options.placement.call(this, $tip[0], this.$element[0]) :
142
+        this.options.placement
143
+
144
+      var autoToken = /\s?auto?\s?/i
145
+      var autoPlace = autoToken.test(placement)
146
+      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
147
+
148
+      $tip
149
+        .detach()
150
+        .css({ top: 0, left: 0, display: 'block' })
151
+        .addClass(placement)
152
+
153
+      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
154
+
155
+      var pos          = this.getPosition()
156
+      var actualWidth  = $tip[0].offsetWidth
157
+      var actualHeight = $tip[0].offsetHeight
158
+
159
+      if (autoPlace) {
160
+        var $parent = this.$element.parent()
161
+
162
+        var orgPlacement = placement
163
+        var docScroll    = document.documentElement.scrollTop || document.body.scrollTop
164
+        var parentWidth  = this.options.container == 'body' ? window.innerWidth  : $parent.outerWidth()
165
+        var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
166
+        var parentLeft   = this.options.container == 'body' ? 0 : $parent.offset().left
167
+
168
+        placement = placement == 'bottom' && pos.top   + pos.height  + actualHeight - docScroll > parentHeight  ? 'top'    :
169
+                    placement == 'top'    && pos.top   - docScroll   - actualHeight < 0                         ? 'bottom' :
170
+                    placement == 'right'  && pos.right + actualWidth > parentWidth                              ? 'left'   :
171
+                    placement == 'left'   && pos.left  - actualWidth < parentLeft                               ? 'right'  :
172
+                    placement
173
+
174
+        $tip
175
+          .removeClass(orgPlacement)
176
+          .addClass(placement)
177
+      }
178
+
179
+      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
180
+
181
+      this.applyPlacement(calculatedOffset, placement)
182
+      this.hoverState = null
183
+
184
+      var complete = function() {
185
+        that.$element.trigger('shown.bs.' + that.type)
186
+      }
187
+
188
+      $.support.transition && this.$tip.hasClass('fade') ?
189
+        $tip
190
+          .one($.support.transition.end, complete)
191
+          .emulateTransitionEnd(150) :
192
+        complete()
193
+    }
194
+  }
195
+
196
+  Tooltip.prototype.applyPlacement = function (offset, placement) {
197
+    var replace
198
+    var $tip   = this.tip()
199
+    var width  = $tip[0].offsetWidth
200
+    var height = $tip[0].offsetHeight
201
+
202
+    // manually read margins because getBoundingClientRect includes difference
203
+    var marginTop = parseInt($tip.css('margin-top'), 10)
204
+    var marginLeft = parseInt($tip.css('margin-left'), 10)
205
+
206
+    // we must check for NaN for ie 8/9
207
+    if (isNaN(marginTop))  marginTop  = 0
208
+    if (isNaN(marginLeft)) marginLeft = 0
209
+
210
+    offset.top  = offset.top  + marginTop
211
+    offset.left = offset.left + marginLeft
212
+
213
+    // $.fn.offset doesn't round pixel values
214
+    // so we use setOffset directly with our own function B-0
215
+    $.offset.setOffset($tip[0], $.extend({
216
+      using: function (props) {
217
+        $tip.css({
218
+          top: Math.round(props.top),
219
+          left: Math.round(props.left)
220
+        })
221
+      }
222
+    }, offset), 0)
223
+
224
+    $tip.addClass('in')
225
+
226
+    // check to see if placing tip in new offset caused the tip to resize itself
227
+    var actualWidth  = $tip[0].offsetWidth
228
+    var actualHeight = $tip[0].offsetHeight
229
+
230
+    if (placement == 'top' && actualHeight != height) {
231
+      replace = true
232
+      offset.top = offset.top + height - actualHeight
233
+    }
234
+
235
+    if (/bottom|top/.test(placement)) {
236
+      var delta = 0
237
+
238
+      if (offset.left < 0) {
239
+        delta       = offset.left * -2
240
+        offset.left = 0
241
+
242
+        $tip.offset(offset)
243
+
244
+        actualWidth  = $tip[0].offsetWidth
245
+        actualHeight = $tip[0].offsetHeight
246
+      }
247
+
248
+      this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
249
+    } else {
250
+      this.replaceArrow(actualHeight - height, actualHeight, 'top')
251
+    }
252
+
253
+    if (replace) $tip.offset(offset)
254
+  }
255
+
256
+  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
257
+    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
258
+  }
259
+
260
+  Tooltip.prototype.setContent = function () {
261
+    var $tip  = this.tip()
262
+    var title = this.getTitle()
263
+
264
+    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
265
+    $tip.removeClass('fade in top bottom left right')
266
+  }
267
+
268
+  Tooltip.prototype.hide = function () {
269
+    var that = this
270
+    var $tip = this.tip()
271
+    var e    = $.Event('hide.bs.' + this.type)
272
+
273
+    function complete() {
274
+      if (that.hoverState != 'in') $tip.detach()
275
+      that.$element.trigger('hidden.bs.' + that.type)
276
+    }
277
+
278
+    this.$element.trigger(e)
279
+
280
+    if (e.isDefaultPrevented()) return
281
+
282
+    $tip.removeClass('in')
283
+
284
+    $.support.transition && this.$tip.hasClass('fade') ?
285
+      $tip
286
+        .one($.support.transition.end, complete)
287
+        .emulateTransitionEnd(150) :
288
+      complete()
289
+
290
+    this.hoverState = null
291
+
292
+    return this
293
+  }
294
+
295
+  Tooltip.prototype.fixTitle = function () {
296
+    var $e = this.$element
297
+    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
298
+      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
299
+    }
300
+  }
301
+
302
+  Tooltip.prototype.hasContent = function () {
303
+    return this.getTitle()
304
+  }
305
+
306
+  Tooltip.prototype.getPosition = function () {
307
+    var el = this.$element[0]
308
+    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
309
+      width: el.offsetWidth,
310
+      height: el.offsetHeight
311
+    }, this.$element.offset())
312
+  }
313
+
314
+  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
315
+    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
316
+           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
317
+           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
318
+        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
319
+  }
320
+
321
+  Tooltip.prototype.getTitle = function () {
322
+    var title
323
+    var $e = this.$element
324
+    var o  = this.options
325
+
326
+    title = $e.attr('data-original-title')
327
+      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
328
+
329
+    return title
330
+  }
331
+
332
+  Tooltip.prototype.tip = function () {
333
+    return this.$tip = this.$tip || $(this.options.template)
334
+  }
335
+
336
+  Tooltip.prototype.arrow = function () {
337
+    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
338
+  }
339
+
340
+  Tooltip.prototype.validate = function () {
341
+    if (!this.$element[0].parentNode) {
342
+      this.hide()
343
+      this.$element = null
344
+      this.options  = null
345
+    }
346
+  }
347
+
348
+  Tooltip.prototype.enable = function () {
349
+    this.enabled = true
350
+  }
351
+
352
+  Tooltip.prototype.disable = function () {
353
+    this.enabled = false
354
+  }
355
+
356
+  Tooltip.prototype.toggleEnabled = function () {
357
+    this.enabled = !this.enabled
358
+  }
359
+
360
+  Tooltip.prototype.toggle = function (e) {
361
+    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
362
+    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
363
+  }
364
+
365
+  Tooltip.prototype.destroy = function () {
366
+    clearTimeout(this.timeout)
367
+    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
368
+  }
369
+
370
+
371
+  // TOOLTIP PLUGIN DEFINITION
372
+  // =========================
373
+
374
+  var old = $.fn.tooltip
375
+
376
+  $.fn.tooltip = function (option) {
377
+    return this.each(function () {
378
+      var $this   = $(this)
379
+      var data    = $this.data('bs.tooltip')
380
+      var options = typeof option == 'object' && option
381
+
382
+      if (!data && option == 'destroy') return
383
+      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
384
+      if (typeof option == 'string') data[option]()
385
+    })
386
+  }
387
+
388
+  $.fn.tooltip.Constructor = Tooltip
389
+
390
+
391
+  // TOOLTIP NO CONFLICT
392
+  // ===================
393
+
394
+  $.fn.tooltip.noConflict = function () {
395
+    $.fn.tooltip = old
396
+    return this
397
+  }
398
+
399
+}(jQuery);

+ 8
- 1
util.js Wyświetl plik

57
         return window.innerWidth - chatspaceWidth;
57
         return window.innerWidth - chatspaceWidth;
58
     };
58
     };
59
 
59
 
60
-    my.imageToGrayScale = function(canvas) {
60
+    my.imageToGrayScale = function (canvas) {
61
         var context = canvas.getContext('2d');
61
         var context = canvas.getContext('2d');
62
         var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
62
         var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
63
         var pixels  = imgData.data;
63
         var pixels  = imgData.data;
74
         context.putImageData(imgData, 0, 0);
74
         context.putImageData(imgData, 0, 0);
75
     };
75
     };
76
 
76
 
77
+    my.setTooltip = function (element, tooltipText, position) {
78
+        element.setAttribute("data-content", tooltipText);
79
+        element.setAttribute("data-toggle", "popover");
80
+        element.setAttribute("data-placement", position);
81
+        element.setAttribute("data-html", true);
82
+    };
83
+
77
     return my;
84
     return my;
78
 }(Util || {}));
85
 }(Util || {}));

+ 13
- 3
videolayout.js Wyświetl plik

410
             if (!indicatorSpan || indicatorSpan.length === 0) {
410
             if (!indicatorSpan || indicatorSpan.length === 0) {
411
                 indicatorSpan = document.createElement('span');
411
                 indicatorSpan = document.createElement('span');
412
                 indicatorSpan.className = 'focusindicator';
412
                 indicatorSpan.className = 'focusindicator';
413
+                Util.setTooltip(indicatorSpan,
414
+                                "The owner of<br/>this conference",
415
+                                "top");
413
                 focusContainer.appendChild(indicatorSpan);
416
                 focusContainer.appendChild(indicatorSpan);
414
 
417
 
415
                 createFocusIndicatorElement(indicatorSpan);
418
                 createFocusIndicatorElement(indicatorSpan);
440
 
443
 
441
             var mutedIndicator = document.createElement('i');
444
             var mutedIndicator = document.createElement('i');
442
             mutedIndicator.className = 'icon-camera-disabled';
445
             mutedIndicator.className = 'icon-camera-disabled';
443
-            mutedIndicator.title = "Participant has stopped the camera.";
446
+            Util.setTooltip(mutedIndicator,
447
+                    "Participant has<br/>stopped the camera.",
448
+                    "top");
444
             videoMutedSpan.appendChild(mutedIndicator);
449
             videoMutedSpan.appendChild(mutedIndicator);
445
         }
450
         }
446
     };
451
     };
461
 
466
 
462
             audioMutedSpan = document.createElement('span');
467
             audioMutedSpan = document.createElement('span');
463
             audioMutedSpan.className = 'audioMuted';
468
             audioMutedSpan.className = 'audioMuted';
469
+            Util.setTooltip(audioMutedSpan,
470
+                    "Participant is muted",
471
+                    "top");
472
+
464
             if (videoMutedSpan) {
473
             if (videoMutedSpan) {
465
                 audioMutedSpan.right = '30px';
474
                 audioMutedSpan.right = '30px';
466
             }
475
             }
468
 
477
 
469
             var mutedIndicator = document.createElement('i');
478
             var mutedIndicator = document.createElement('i');
470
             mutedIndicator.className = 'icon-mic-disabled';
479
             mutedIndicator.className = 'icon-mic-disabled';
471
-            mutedIndicator.title = "Participant is muted";
472
             audioMutedSpan.appendChild(mutedIndicator);
480
             audioMutedSpan.appendChild(mutedIndicator);
473
         }
481
         }
474
     };
482
     };
705
     function createEditDisplayNameButton() {
713
     function createEditDisplayNameButton() {
706
         var editButton = document.createElement('a');
714
         var editButton = document.createElement('a');
707
         editButton.className = 'displayname';
715
         editButton.className = 'displayname';
716
+        Util.setTooltip(editButton,
717
+                        'Click to edit your<br/>display name',
718
+                        "top");
708
         editButton.innerHTML = '<i class="fa fa-pencil"></i>';
719
         editButton.innerHTML = '<i class="fa fa-pencil"></i>';
709
 
720
 
710
         return editButton;
721
         return editButton;
719
     function createFocusIndicatorElement(parentElement) {
730
     function createFocusIndicatorElement(parentElement) {
720
         var focusIndicator = document.createElement('i');
731
         var focusIndicator = document.createElement('i');
721
         focusIndicator.className = 'fa fa-star';
732
         focusIndicator.className = 'fa fa-star';
722
-        focusIndicator.title = "The owner of this conference";
723
         parentElement.appendChild(focusIndicator);
733
         parentElement.appendChild(focusIndicator);
724
     }
734
     }
725
 
735
 

Ładowanie…
Anuluj
Zapisz