소스 검색

Improved, more user friendly tooltips.

j8
yanas 11 년 전
부모
커밋
73cd3c04f6
9개의 변경된 파일679개의 추가작업 그리고 20개의 파일을 삭제
  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 파일 보기

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

+ 124
- 0
css/popover.css 파일 보기

@@ -0,0 +1,124 @@
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 파일 보기

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

+ 2
- 1
css/videolayout_default.css 파일 보기

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

+ 18
- 13
index.html 파일 보기

@@ -20,6 +20,8 @@
20 20
     <script src="libs/colibri/colibri.focus.js?v=8"></script><!-- colibri focus implementation -->
21 21
     <script src="libs/colibri/colibri.session.js?v=1"></script>
22 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 25
     <script src="config.js?v=2"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
24 26
     <script src="muc.js?v=11"></script><!-- simple MUC library -->
25 27
     <script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
@@ -44,6 +46,7 @@
44 46
     <link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
45 47
     <link rel="stylesheet" href="css/modaldialog.css?v=3">
46 48
     <link rel="stylesheet" href="css/popup_menu.css?v=1">
49
+    <link rel="stylesheet" href="css/popover.css?v=1">
47 50
     <!--
48 51
         Link used for inline installation of chrome desktop streaming extension,
49 52
         is updated automatically from the code with the value defined in config.js -->
@@ -55,32 +58,34 @@
55 58
   <body>
56 59
     <div id="header">
57 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 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 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 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 71
             <div class="header_button_separator"></div>
68 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 74
                 <span id="unreadMessages"></span>
71 75
             </span>
72 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 78
             <span id="etherpadButton">
75 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 81
             </span>
78 82
             <div class="header_button_separator"></div>
79 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 85
                 <div class="header_button_separator"></div>
82 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 89
         </span>
85 90
     </div>
86 91
     <div id="settings">
@@ -108,7 +113,7 @@
108 113
                     <!--<video id="localVideo" autoplay oncontextmenu="return false;" muted></video> - is now per stream generated -->
109 114
                 </span>
110 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 117
             </span>
113 118
             <audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
114 119
             <audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
@@ -127,6 +132,6 @@
127 132
         <audio id="chatNotification" src="sounds/incomingMessage.wav" preload="auto"></audio>
128 133
         <textarea id="usermsg" placeholder='Enter text...' autofocus></textarea>
129 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 136
   </body>
132 137
 </html>

+ 110
- 0
libs/popover.js 파일 보기

@@ -0,0 +1,110 @@
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 파일 보기

@@ -0,0 +1,399 @@
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 파일 보기

@@ -57,7 +57,7 @@ var Util = (function (my) {
57 57
         return window.innerWidth - chatspaceWidth;
58 58
     };
59 59
 
60
-    my.imageToGrayScale = function(canvas) {
60
+    my.imageToGrayScale = function (canvas) {
61 61
         var context = canvas.getContext('2d');
62 62
         var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
63 63
         var pixels  = imgData.data;
@@ -74,5 +74,12 @@ var Util = (function (my) {
74 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 84
     return my;
78 85
 }(Util || {}));

+ 13
- 3
videolayout.js 파일 보기

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

Loading…
취소
저장