├── .gitattributes
├── .gitignore
├── Gruntfile.js
├── README.md
├── dist
├── css
│ └── tipped.css
└── js
│ ├── tipped.js
│ └── tipped.min.js
├── example
├── css
│ └── style.css
└── index.html
├── package-lock.json
├── package.json
└── src
├── css
└── tipped.css
└── js
├── api.js
├── behaviors.js
├── collection.js
├── delegate.js
├── helpers
├── ajaxcache.js
├── bounds.js
├── browser.js
├── color.js
├── dimensions.js
├── helpers.js
├── mouse.js
├── position.js
├── requirements.js
├── spin.js
├── support.js
└── visible.js
├── options.js
├── setup.js
├── skin.js
├── skins.js
├── stem.js
├── tooltip.js
├── tooltip
├── active.js
├── bind.js
├── disable.js
├── display.js
├── is.js
├── layout.js
├── timers.js
└── update.js
├── tooltips.js
├── umd-head.js
├── umd-tail.js
└── voila
└── voila.custom.js
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules/
3 | .history
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | grunt.initConfig({
3 | pkg: grunt.file.readJSON("package.json"),
4 | dirs: {
5 | dest: "dist",
6 | },
7 |
8 | vars: {},
9 |
10 | concat: {
11 | options: { process: true },
12 | dist: {
13 | src: [
14 | "src/js/umd-head.js",
15 | "src/js/setup.js",
16 | "src/js/skins.js",
17 |
18 | // helpers
19 | "src/js/helpers/browser.js",
20 | "src/js/helpers/support.js",
21 | "src/js/helpers/helpers.js",
22 | "src/js/helpers/position.js",
23 | "src/js/helpers/bounds.js",
24 | "src/js/helpers/mouse.js",
25 | "src/js/helpers/color.js",
26 | "src/js/helpers/spin.js",
27 | "src/js/helpers/visible.js",
28 | "src/js/helpers/ajaxcache.js",
29 | "src/js/voila/voila.custom.js",
30 |
31 | // core
32 | "src/js/behaviors.js",
33 | "src/js/options.js",
34 | "src/js/skin.js",
35 | "src/js/stem.js",
36 | "src/js/tooltips.js",
37 |
38 | // tooltip
39 | "src/js/tooltip.js",
40 | "src/js/tooltip/display.js",
41 | "src/js/tooltip/update.js",
42 | "src/js/tooltip/layout.js",
43 | // tooltip (helpers)
44 | "src/js/tooltip/active.js",
45 | "src/js/tooltip/bind.js",
46 | "src/js/tooltip/disable.js",
47 | "src/js/tooltip/is.js",
48 | "src/js/tooltip/timers.js",
49 |
50 | "src/js/api.js",
51 | "src/js/delegate.js",
52 | "src/js/collection.js",
53 |
54 | "src/js/umd-tail.js",
55 | ],
56 | dest: "<%= dirs.dest %>/js/tipped.js",
57 | },
58 | },
59 |
60 | copy: {
61 | dist: {
62 | files: [
63 | {
64 | expand: true,
65 | cwd: "src/css/",
66 | src: ["**"],
67 | dest: "<%= dirs.dest %>/css/",
68 | },
69 | ],
70 | },
71 | },
72 |
73 | uglify: {
74 | dist: {
75 | options: {
76 | output: {
77 | comments: "some",
78 | },
79 | },
80 | src: ["<%= dirs.dest %>/js/tipped.js"],
81 | dest: "<%= dirs.dest %>/js/tipped.min.js",
82 | },
83 | },
84 |
85 | clean: {
86 | dist: "dist/",
87 | },
88 |
89 | watch: {
90 | scripts: {
91 | files: ["src/**/*.js", "src/**/*.css"],
92 | tasks: ["default"],
93 | options: {
94 | spawn: false,
95 | },
96 | },
97 | },
98 | });
99 |
100 | // Load plugins
101 | grunt.loadNpmTasks("grunt-contrib-concat");
102 | grunt.loadNpmTasks("grunt-contrib-copy");
103 | grunt.loadNpmTasks("grunt-contrib-uglify");
104 | grunt.loadNpmTasks("grunt-contrib-clean");
105 | grunt.loadNpmTasks("grunt-contrib-watch");
106 |
107 | grunt.registerTask("default", [
108 | "clean:dist",
109 | "concat:dist",
110 | "copy:dist",
111 | "uglify:dist",
112 | ]);
113 | };
114 |
--------------------------------------------------------------------------------
/dist/css/tipped.css:
--------------------------------------------------------------------------------
1 | .tpd-tooltip {
2 | position: absolute;
3 | }
4 |
5 | /* Fix for CSS frameworks that don't keep the use of box-sizing: border-box
6 | within their own namespace */
7 | .tpd-tooltip {
8 | box-sizing: content-box;
9 | }
10 | .tpd-tooltip [class^="tpd-"] {
11 | box-sizing: inherit;
12 | }
13 |
14 | /* Content */
15 | .tpd-content-wrapper {
16 | position: absolute;
17 | top: 0;
18 | left: 0;
19 | float: left;
20 | width: 100%;
21 | height: 100%;
22 | overflow: hidden;
23 | }
24 | .tpd-content-spacer,
25 | .tpd-content-relative,
26 | .tpd-content-relative-padder {
27 | float: left;
28 | position: relative;
29 | }
30 | .tpd-content-relative {
31 | width: 100%;
32 | }
33 |
34 | .tpd-content {
35 | float: left;
36 | clear: both;
37 | position: relative;
38 | padding: 10px;
39 | font-size: 11px;
40 | line-height: 16px;
41 | color: #fff;
42 | box-sizing: border-box !important;
43 | }
44 | .tpd-has-inner-close .tpd-content-relative .tpd-content {
45 | padding-right: 0 !important;
46 | }
47 | .tpd-tooltip .tpd-content-no-padding {
48 | padding: 0 !important;
49 | }
50 |
51 | .tpd-title-wrapper {
52 | float: left;
53 | position: relative;
54 | overflow: hidden;
55 | }
56 | .tpd-title-spacer {
57 | float: left;
58 | }
59 | .tpd-title-relative,
60 | .tpd-title-relative-padder {
61 | float: left;
62 | position: relative;
63 | }
64 | .tpd-title-relative {
65 | width: 100%;
66 | }
67 | .tpd-title {
68 | float: left;
69 | position: relative;
70 | font-size: 11px;
71 | line-height: 16px;
72 | padding: 10px;
73 | font-weight: bold;
74 | text-transform: uppercase;
75 | color: #fff;
76 | box-sizing: border-box !important;
77 | }
78 | .tpd-has-title-close .tpd-title {
79 | padding-right: 0 !important;
80 | }
81 | .tpd-close {
82 | position: absolute;
83 | top: 0;
84 | right: 0;
85 | width: 28px;
86 | height: 28px;
87 | cursor: pointer;
88 | overflow: hidden;
89 | color: #fff;
90 | }
91 | .tpd-close-icon {
92 | float: left;
93 | font-family: Arial, Baskerville, monospace;
94 | font-weight: normal;
95 | font-style: normal;
96 | text-decoration: none;
97 | width: 28px;
98 | height: 28px;
99 | font-size: 28px;
100 | line-height: 28px;
101 | text-align: center;
102 | }
103 |
104 | /* Skin */
105 | .tpd-skin {
106 | position: absolute;
107 | top: 0;
108 | left: 0;
109 | }
110 |
111 | .tpd-frames {
112 | position: absolute;
113 | top: 0;
114 | left: 0;
115 | }
116 | .tpd-frames .tpd-frame {
117 | float: left;
118 | width: 100%;
119 | height: 100%;
120 | clear: both;
121 | display: none;
122 | }
123 |
124 | .tpd-visible-frame-top .tpd-frame-top {
125 | display: block;
126 | }
127 | .tpd-visible-frame-bottom .tpd-frame-bottom {
128 | display: block;
129 | }
130 | .tpd-visible-frame-left .tpd-frame-left {
131 | display: block;
132 | }
133 | .tpd-visible-frame-right .tpd-frame-right {
134 | display: block;
135 | }
136 |
137 | .tpd-backgrounds {
138 | position: absolute;
139 | top: 0;
140 | left: 0;
141 | width: 100%;
142 | height: 100%;
143 | -webkit-transform-origin: 0% 0%;
144 | transform-origin: 0% 0%;
145 | }
146 | .tpd-background-shadow {
147 | position: absolute;
148 | top: 0;
149 | left: 0;
150 | width: 100%;
151 | height: 100%;
152 | background-color: transparent;
153 | pointer-events: none;
154 | }
155 | .tpd-no-shadow .tpd-skin .tpd-background-shadow {
156 | box-shadow: none !important;
157 | }
158 |
159 | .tpd-background-box {
160 | position: absolute;
161 | top: 0;
162 | left: 0;
163 | height: 100%;
164 | width: 100%;
165 | overflow: hidden;
166 | }
167 | /* only the top background box should be shown when not using a stem */
168 | .tpd-no-stem .tpd-background-box,
169 | .tpd-no-stem .tpd-shift-stem {
170 | display: none;
171 | }
172 | .tpd-no-stem .tpd-background-box-top {
173 | display: block;
174 | }
175 |
176 | .tpd-background-box-shift,
177 | .tpd-background-box-shift-further {
178 | position: relative;
179 | float: left;
180 | width: 100%;
181 | height: 100%;
182 | }
183 | .tpd-background {
184 | border-radius: 10px;
185 | float: left;
186 | clear: both;
187 | background: none;
188 | -webkit-background-clip: padding-box; /* Safari */
189 | background-clip: padding-box; /* IE9+, Firefox 4+, Opera, Chrome */
190 | border-style: solid;
191 | border-width: 1px;
192 | border-color: rgba(
193 | 255,
194 | 255,
195 | 255,
196 | 0.1
197 | ); /* opacity here bugs out in firefox, .tpd-background-content should have no opacity if this opacity is less than 1 */
198 | }
199 | .tpd-background-loading {
200 | display: none;
201 | }
202 | /* no radius */
203 | .tpd-no-radius
204 | .tpd-skin
205 | .tpd-frames
206 | .tpd-frame
207 | .tpd-backgrounds
208 | .tpd-background {
209 | border-radius: 0;
210 | }
211 | .tpd-background-title {
212 | float: left;
213 | clear: both;
214 | width: 100%;
215 | background-color: #282828;
216 | }
217 | .tpd-background-content {
218 | float: left;
219 | clear: both;
220 | width: 100%;
221 | background-color: #282828;
222 | }
223 | .tpd-background-border-hack {
224 | position: absolute;
225 | top: 0;
226 | left: 0;
227 | width: 100%;
228 | height: 100%;
229 | border-style: solid;
230 | }
231 |
232 | .tpd-background-box-top {
233 | top: 0;
234 | }
235 | .tpd-background-box-bottom {
236 | bottom: 0;
237 | }
238 | .tpd-background-box-left {
239 | left: 0;
240 | }
241 | .tpd-background-box-right {
242 | right: 0;
243 | }
244 |
245 | /* Skin / Stems */
246 | .tpd-shift-stem {
247 | position: absolute;
248 | top: 0;
249 | left: 0;
250 | overflow: hidden;
251 | }
252 | .tpd-shift-stem-side {
253 | position: absolute;
254 | }
255 | .tpd-frame-top .tpd-shift-stem-side,
256 | .tpd-frame-bottom .tpd-shift-stem-side {
257 | width: 100%;
258 | }
259 | .tpd-frame-left .tpd-shift-stem-side,
260 | .tpd-frame-right .tpd-shift-stem-side {
261 | height: 100%;
262 | }
263 |
264 | .tpd-stem {
265 | position: absolute;
266 | top: 0;
267 | left: 0;
268 | overflow: hidden; /* shows possible invalid subpx rendering */
269 | width: 16px; /* best cross browser stem: width = 2 x height (90deg angle) */
270 | height: 8px;
271 | margin-left: 3px; /* space from the side */
272 | margin-top: 2px; /* space between target and stem */
273 | -webkit-transform-origin: 0% 0%;
274 | transform-origin: 0% 0%;
275 | }
276 | /* remove margins once we're done measuring */
277 | .tpd-tooltip .tpd-skin .tpd-frames .tpd-frame .tpd-shift-stem .tpd-stem-reset {
278 | margin: 0 !important;
279 | }
280 |
281 | .tpd-stem-spacer {
282 | position: absolute;
283 | top: 0;
284 | left: 0;
285 | width: 100%;
286 | height: 100%;
287 | }
288 | .tpd-stem-reset .tpd-stem-spacer {
289 | margin-top: 0;
290 | }
291 |
292 | .tpd-stem-point {
293 | width: 100px;
294 | position: absolute;
295 | top: 0;
296 | left: 50%;
297 | }
298 | .tpd-stem-downscale,
299 | .tpd-stem-transform {
300 | float: left;
301 | width: 100%;
302 | height: 100%;
303 | -webkit-transform-origin: 0% 0%;
304 | transform-origin: 0% 0%;
305 | position: relative;
306 | }
307 |
308 | .tpd-stem-side {
309 | width: 50%;
310 | height: 100%;
311 | float: left;
312 | position: relative;
313 | overflow: hidden;
314 | }
315 | .tpd-stem-side-inversed {
316 | -webkit-transform: scale(-1, 1);
317 | transform: scale(-1, 1);
318 | }
319 | .tpd-stem-triangle {
320 | width: 0;
321 | height: 0;
322 | border-bottom-style: solid;
323 | border-left-color: transparent;
324 | border-left-style: solid;
325 | position: absolute;
326 | top: 0;
327 | left: 0;
328 | }
329 | .tpd-stem-border {
330 | width: 20px;
331 | height: 100%;
332 | position: absolute;
333 | top: 0;
334 | left: 50%;
335 | background-color: #fff; /* will become transparent */
336 | border-right-color: #fff;
337 | border-right-style: solid;
338 | border-right-width: 0;
339 | }
340 |
341 | .tpd-stem-border-corner {
342 | position: absolute;
343 | top: 0;
344 | left: 50%;
345 | height: 100%;
346 | border-right-style: solid;
347 | border-right-width: 0;
348 | }
349 |
350 | /* fixes rendering issue in IE */
351 | .tpd-stem * {
352 | z-index: 0;
353 | zoom: 1;
354 | }
355 |
356 | /* used by IE < 9 */
357 | .tpd-stem-border-center-offset,
358 | .tpd-stem-border-center-offset-inverse {
359 | float: left;
360 | position: relative;
361 | width: 100%;
362 | height: 100%;
363 | overflow: hidden;
364 | }
365 | .tpd-stem-notransform {
366 | float: left;
367 | width: 100%;
368 | height: 100%;
369 | position: relative;
370 | }
371 | .tpd-stem-notransform .tpd-stem-border {
372 | height: 100%;
373 | position: relative;
374 | float: left;
375 | top: 0;
376 | left: 0;
377 | margin: 0;
378 | }
379 | .tpd-stem-notransform .tpd-stem-border-center {
380 | position: absolute;
381 | }
382 | .tpd-stem-notransform .tpd-stem-border-corner {
383 | background: #fff;
384 | border: 0;
385 | top: auto;
386 | left: auto;
387 | }
388 | .tpd-stem-notransform .tpd-stem-border-center,
389 | .tpd-stem-notransform .tpd-stem-triangle {
390 | height: 0;
391 | border: 0;
392 | left: 50%;
393 | }
394 |
395 | /* transformations for left/right/bottom */
396 | .tpd-stem-transform-left {
397 | -webkit-transform: rotate(-90deg) scale(-1, 1);
398 | transform: rotate(-90deg) scale(-1, 1);
399 | }
400 | .tpd-stem-transform-right {
401 | -webkit-transform: rotate(90deg) translate(0, -100%);
402 | transform: rotate(90deg) translate(0, -100%);
403 | }
404 | .tpd-stem-transform-bottom {
405 | -webkit-transform: scale(1, -1) translate(0, -100%);
406 | transform: scale(1, -1) translate(0, -100%);
407 | }
408 |
409 | /* Spinner */
410 | .tpd-spinner {
411 | position: absolute;
412 | top: 50%;
413 | left: 50%;
414 | width: 46px;
415 | height: 36px;
416 | }
417 | .tpd-spinner-spin {
418 | position: relative;
419 | float: left;
420 | margin: 8px 0 0 13px;
421 | text-indent: -9999em;
422 | border-top: 2px solid rgba(255, 255, 255, 0.2);
423 | border-right: 2px solid rgba(255, 255, 255, 0.2);
424 | border-bottom: 2px solid rgba(255, 255, 255, 0.2);
425 | border-left: 2px solid #fff;
426 | -webkit-animation: tpd-spinner-animation 1.1s infinite linear;
427 | animation: tpd-spinner-animation 1.1s infinite linear;
428 | box-sizing: border-box !important;
429 | }
430 | .tpd-spinner-spin,
431 | .tpd-spinner-spin:after {
432 | border-radius: 50%;
433 | width: 20px;
434 | height: 20px;
435 | }
436 | @-webkit-keyframes tpd-spinner-animation {
437 | 0% {
438 | -webkit-transform: rotate(0deg);
439 | transform: rotate(0deg);
440 | }
441 | 100% {
442 | -webkit-transform: rotate(360deg);
443 | transform: rotate(360deg);
444 | }
445 | }
446 | @keyframes tpd-spinner-animation {
447 | 0% {
448 | -webkit-transform: rotate(0deg);
449 | transform: rotate(0deg);
450 | }
451 | 100% {
452 | -webkit-transform: rotate(360deg);
453 | transform: rotate(360deg);
454 | }
455 | }
456 |
457 | /* show the loader while loading and hide all the content */
458 | .tpd-is-loading .tpd-content-wrapper,
459 | .tpd-is-loading .tpd-title-wrapper {
460 | display: none;
461 | }
462 | .tpd-is-loading .tpd-background {
463 | display: none;
464 | }
465 | .tpd-is-loading .tpd-background-loading {
466 | display: block;
467 | }
468 |
469 | /* Resets while measuring content */
470 | .tpd-tooltip-measuring {
471 | top: 0;
472 | left: 0;
473 | position: absolute;
474 | max-width: 100%;
475 | width: 100%;
476 | }
477 | .tpd-tooltip-measuring .tpd-skin,
478 | .tpd-tooltip-measuring .tpd-spinner {
479 | display: none;
480 | }
481 |
482 | .tpd-tooltip-measuring .tpd-content-wrapper,
483 | .tpd-tooltip-measuring .tpd-title-wrapper {
484 | display: block;
485 | }
486 |
487 | /* Links */
488 | .tpd-tooltip a,
489 | .tpd-tooltip a:hover {
490 | color: #808080;
491 | text-decoration: underline;
492 | }
493 | .tpd-tooltip a:hover {
494 | color: #6c6c6c;
495 | }
496 |
497 | /*
498 | * Sizes
499 | */
500 | /* x-small */
501 | .tpd-size-x-small .tpd-content,
502 | .tpd-size-x-small .tpd-title {
503 | padding: 7px 8px;
504 | font-size: 10px;
505 | line-height: 15px;
506 | }
507 | .tpd-size-x-small .tpd-background {
508 | border-radius: 5px;
509 | }
510 | .tpd-size-x-small .tpd-stem {
511 | width: 12px;
512 | height: 6px;
513 | margin-left: 4px;
514 | margin-top: 2px; /* space between target and stem */
515 | }
516 | .tpd-size-x-small.tpd-no-radius .tpd-stem {
517 | margin-left: 7px;
518 | }
519 | .tpd-size-x-small .tpd-close {
520 | margin-bottom: 1px;
521 | }
522 | .tpd-size-x-small .tpd-spinner {
523 | width: 35px;
524 | height: 29px;
525 | }
526 | .tpd-size-x-small .tpd-spinner-spin {
527 | margin: 6px 0 0 9px;
528 | }
529 | .tpd-size-x-small .tpd-spinner-spin,
530 | .tpd-size-x-small .tpd-spinner-spin:after {
531 | width: 17px;
532 | height: 17px;
533 | }
534 |
535 | /* small */
536 | .tpd-size-small .tpd-content,
537 | .tpd-size-small .tpd-title {
538 | padding: 8px;
539 | font-size: 10px;
540 | line-height: 16px;
541 | }
542 | .tpd-size-small .tpd-background {
543 | border-radius: 6px;
544 | }
545 | .tpd-size-small .tpd-stem {
546 | width: 14px;
547 | height: 7px;
548 | margin-left: 5px;
549 | margin-top: 2px; /* space between target and stem */
550 | }
551 | .tpd-size-small.tpd-no-radius .tpd-stem {
552 | margin-left: 8px;
553 | }
554 | .tpd-size-small .tpd-close {
555 | margin: 2px 1px;
556 | }
557 | .tpd-size-small .tpd-spinner {
558 | width: 42px;
559 | height: 32px;
560 | }
561 | .tpd-size-small .tpd-spinner-spin {
562 | margin: 7px 0 0 13px;
563 | }
564 | .tpd-size-small .tpd-spinner-spin,
565 | .tpd-size-small .tpd-spinner-spin:after {
566 | width: 18px;
567 | height: 18px;
568 | }
569 |
570 | /* medium (default) */
571 | .tpd-size-medium .tpd-content,
572 | .tpd-size-medium .tpd-title {
573 | padding: 10px;
574 | font-size: 11px;
575 | line-height: 16px;
576 | }
577 | .tpd-size-medium .tpd-background {
578 | border-radius: 8px;
579 | }
580 | .tpd-size-medium .tpd-stem {
581 | width: 16px; /* best cross browser stem width is 2xheight, for a 90deg angle */
582 | height: 8px;
583 | margin-left: 6px; /* space from the side */
584 | margin-top: 2px; /* space between target and stem */
585 | }
586 | .tpd-size-medium.tpd-no-radius .tpd-stem {
587 | margin-left: 10px;
588 | }
589 | .tpd-size-medium .tpd-close {
590 | margin: 4px 2px;
591 | }
592 | /* ideal spinner dimensions don't cause movement op top and
593 | on the stem when switching to text using position:'topleft' */
594 | .tpd-size-medium .tpd-spinner {
595 | width: 50px;
596 | height: 36px;
597 | }
598 | .tpd-size-medium .tpd-spinner-spin {
599 | margin: 8px 0 0 15px;
600 | }
601 | .tpd-size-medium .tpd-spinner-spin,
602 | .tpd-size-medium .tpd-spinner-spin:after {
603 | width: 20px;
604 | height: 20px;
605 | }
606 |
607 | /* large */
608 | .tpd-size-large .tpd-content,
609 | .tpd-size-large .tpd-title {
610 | padding: 10px;
611 | font-size: 13px;
612 | line-height: 18px;
613 | }
614 | .tpd-size-large .tpd-background {
615 | border-radius: 8px;
616 | }
617 | .tpd-size-large .tpd-stem {
618 | width: 18px;
619 | height: 9px;
620 | margin-left: 7px;
621 | margin-top: 2px; /* space between target and stem */
622 | }
623 | .tpd-size-large.tpd-no-radius .tpd-stem {
624 | margin-left: 10px;
625 | }
626 | .tpd-size-large .tpd-close {
627 | margin: 5px 2px 5px 2px;
628 | }
629 | .tpd-size-large .tpd-spinner {
630 | width: 54px;
631 | height: 38px;
632 | }
633 | .tpd-size-large .tpd-spinner-spin {
634 | margin: 9px 0 0 17px;
635 | }
636 | .tpd-size-large .tpd-spinner-spin,
637 | .tpd-size-large .tpd-spinner-spin:after {
638 | width: 20px;
639 | height: 20px;
640 | }
641 |
642 | /* Skins */
643 | /* default (dark) */
644 | .tpd-skin-dark .tpd-content,
645 | .tpd-skin-dark .tpd-title,
646 | .tpd-skin-dark .tpd-close {
647 | color: #fff;
648 | }
649 | .tpd-skin-dark .tpd-background-content,
650 | .tpd-skin-dark .tpd-background-title {
651 | background-color: #282828;
652 | }
653 | .tpd-skin-dark .tpd-background {
654 | border-width: 1px;
655 | border-color: rgba(255, 255, 255, 0.1);
656 | }
657 | /* line below the title */
658 | .tpd-skin-dark .tpd-title-wrapper {
659 | border-bottom: 1px solid #404040;
660 | }
661 | /* spinner */
662 | .tpd-skin-dark .tpd-spinner-spin {
663 | border-color: rgba(255, 255, 255, 0.2);
664 | border-left-color: #fff;
665 | }
666 | /* links */
667 | .tpd-skin-dark a {
668 | color: #ccc;
669 | }
670 | .tpd-skin-dark a:hover {
671 | color: #c0c0c0;
672 | }
673 |
674 | /* light */
675 | .tpd-skin-light .tpd-content,
676 | .tpd-skin-light .tpd-title,
677 | .tpd-skin-light .tpd-close {
678 | color: #333;
679 | }
680 | .tpd-skin-light .tpd-background-content {
681 | background-color: #fff;
682 | }
683 | .tpd-skin-light .tpd-background {
684 | border-width: 1px;
685 | border-color: rgba(0, 0, 0, 0.3);
686 | }
687 | .tpd-skin-light .tpd-background-title {
688 | background-color: #f7f7f7;
689 | }
690 | .tpd-skin-light .tpd-title-wrapper {
691 | border-bottom: 1px solid #c0c0c0;
692 | }
693 | .tpd-skin-light .tpd-background-shadow {
694 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
695 | }
696 | /* fallback for no/disabled shadow */
697 | .tpd-skin-light.tpd-no-shadow .tpd-background {
698 | border-color: rgba(100, 100, 100, 0.3);
699 | }
700 | .tpd-skin-light .tpd-spinner-spin {
701 | border-color: rgba(51, 51, 51, 0.2);
702 | border-left-color: #333;
703 | }
704 | .tpd-skin-light a {
705 | color: #808080;
706 | }
707 | .tpd-skin-light a:hover {
708 | color: #6c6c6c;
709 | }
710 |
711 | /* gray */
712 | .tpd-skin-gray .tpd-content,
713 | .tpd-skin-gray .tpd-title,
714 | .tpd-skin-gray .tpd-close {
715 | color: #fff;
716 | }
717 | .tpd-skin-gray .tpd-background-content,
718 | .tpd-skin-gray .tpd-background-title {
719 | background-color: #727272;
720 | }
721 | .tpd-skin-gray .tpd-background {
722 | border-width: 1px;
723 | border-color: rgba(255, 255, 255, 0.1);
724 | }
725 | .tpd-skin-gray .tpd-title-wrapper {
726 | border-bottom: 1px solid #505050;
727 | }
728 | .tpd-skin-gray .tpd-spinner-spin {
729 | border-color: rgba(255, 255, 255, 0.2);
730 | border-left-color: #fff;
731 | }
732 | .tpd-skin-gray a {
733 | color: #ccc;
734 | }
735 | .tpd-skin-gray a:hover {
736 | color: #b6b6b6;
737 | }
738 |
739 | /* red */
740 | .tpd-skin-red .tpd-content,
741 | .tpd-skin-red .tpd-title,
742 | .tpd-skin-red .tpd-close {
743 | color: #fff;
744 | }
745 | .tpd-skin-red .tpd-background-content {
746 | background-color: #e13c37;
747 | }
748 | .tpd-skin-red .tpd-background {
749 | border-width: 1px;
750 | border-color: rgba(12, 0, 0, 0.6);
751 | }
752 | .tpd-skin-red .tpd-background-title {
753 | background-color: #e13c37;
754 | }
755 | .tpd-skin-red .tpd-title-wrapper {
756 | border-bottom: 1px solid #a30500;
757 | }
758 | .tpd-skin-red .tpd-background-shadow {
759 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
760 | }
761 | .tpd-skin-red .tpd-spinner-spin {
762 | border-color: rgba(255, 255, 255, 0.2);
763 | border-left-color: #fff;
764 | }
765 | .tpd-skin-red a {
766 | color: #ddd;
767 | }
768 | .tpd-skin-red a:hover {
769 | color: #c6c6c6;
770 | }
771 |
772 | /* green */
773 | .tpd-skin-green .tpd-content,
774 | .tpd-skin-green .tpd-title,
775 | .tpd-skin-green .tpd-close {
776 | color: #fff;
777 | }
778 | .tpd-skin-green .tpd-background-content {
779 | background-color: #4aab3a;
780 | }
781 | .tpd-skin-green .tpd-background {
782 | border-width: 1px;
783 | border-color: rgba(0, 12, 0, 0.6);
784 | }
785 | .tpd-skin-green .tpd-background-title {
786 | background-color: #4aab3a;
787 | }
788 | .tpd-skin-green .tpd-title-wrapper {
789 | border-bottom: 1px solid #127c00;
790 | }
791 | .tpd-skin-green .tpd-background-shadow {
792 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
793 | }
794 | .tpd-skin-green .tpd-spinner-spin {
795 | border-color: rgba(255, 255, 255, 0.2);
796 | border-left-color: #fff;
797 | }
798 | .tpd-skin-green a {
799 | color: #ddd;
800 | }
801 | .tpd-skin-green a:hover {
802 | color: #c6c6c6;
803 | }
804 |
805 | /* blue */
806 | .tpd-skin-blue .tpd-content,
807 | .tpd-skin-blue .tpd-title,
808 | .tpd-skin-blue .tpd-close {
809 | color: #fff;
810 | }
811 | .tpd-skin-blue .tpd-background-content {
812 | background-color: #45a3e3;
813 | }
814 | .tpd-skin-blue .tpd-background {
815 | border-width: 1px;
816 | border-color: rgba(0, 0, 12, 0.6);
817 | }
818 | .tpd-skin-blue .tpd-background-title {
819 | background-color: #45a3e3;
820 | }
821 | .tpd-skin-blue .tpd-title-wrapper {
822 | border-bottom: 1px solid #1674b4;
823 | }
824 | .tpd-skin-blue .tpd-background-shadow {
825 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
826 | }
827 | .tpd-skin-blue .tpd-spinner-spin {
828 | border-color: rgba(255, 255, 255, 0.2);
829 | border-left-color: #fff;
830 | }
831 | .tpd-skin-blue a {
832 | color: #ddd;
833 | }
834 | .tpd-skin-blue a:hover {
835 | color: #c6c6c6;
836 | }
837 |
838 | /* lightyellow */
839 | .tpd-skin-lightyellow .tpd-content,
840 | .tpd-skin-lightyellow .tpd-title,
841 | .tpd-skin-lightyellow .tpd-close {
842 | color: #333;
843 | }
844 | .tpd-skin-lightyellow .tpd-background-content {
845 | background-color: #ffffa9;
846 | }
847 | .tpd-skin-lightyellow .tpd-background {
848 | border-width: 1px;
849 | border-color: rgba(8, 8, 0, 0.35);
850 | }
851 | .tpd-skin-lightyellow .tpd-background-title {
852 | background-color: #ffffa9;
853 | }
854 | .tpd-skin-lightyellow .tpd-title-wrapper {
855 | border-bottom: 1px solid #a7a697;
856 | }
857 | .tpd-skin-lightyellow .tpd-background-shadow {
858 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
859 | }
860 | .tpd-skin-lightyellow .tpd-spinner-spin {
861 | border-color: rgba(51, 51, 51, 0.2);
862 | border-left-color: #333;
863 | }
864 | .tpd-skin-lightyellow a {
865 | color: #777;
866 | }
867 | .tpd-skin-lightyellow a:hover {
868 | color: #868686;
869 | }
870 |
871 | /* lightblue */
872 | .tpd-skin-lightblue .tpd-content,
873 | .tpd-skin-lightblue .tpd-title,
874 | .tpd-skin-lightblue .tpd-close {
875 | color: #333;
876 | }
877 | .tpd-skin-lightblue .tpd-background-content {
878 | background-color: #bce5ff;
879 | }
880 | .tpd-skin-lightblue .tpd-background {
881 | border-width: 1px;
882 | border-color: rgba(0, 0, 8, 0.35);
883 | }
884 | .tpd-skin-lightblue .tpd-background-title {
885 | background-color: #bce5ff;
886 | }
887 | .tpd-skin-lightblue .tpd-title-wrapper {
888 | border-bottom: 1px solid #909b9f;
889 | }
890 | .tpd-skin-lightblue .tpd-background-shadow {
891 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
892 | }
893 | .tpd-skin-lightblue .tpd-spinner-spin {
894 | border-color: rgba(51, 51, 51, 0.2);
895 | border-left-color: #333;
896 | }
897 | .tpd-skin-lightblue a {
898 | color: #777;
899 | }
900 | .tpd-skin-lightblue a:hover {
901 | color: #868686;
902 | }
903 |
904 | /* lightpink */
905 | .tpd-skin-lightpink .tpd-content,
906 | .tpd-skin-lightpink .tpd-title,
907 | .tpd-skin-lightpink .tpd-close {
908 | color: #333;
909 | }
910 | .tpd-skin-lightpink .tpd-background-content {
911 | background-color: #ffc4bf;
912 | }
913 | .tpd-skin-lightpink .tpd-background {
914 | border-width: 1px;
915 | border-color: rgba(8, 0, 0, 0.35);
916 | }
917 | .tpd-skin-lightpink .tpd-background-title {
918 | background-color: #ffc4bf;
919 | }
920 | .tpd-skin-lightpink .tpd-title-wrapper {
921 | border-bottom: 1px solid #a08f8f;
922 | }
923 | .tpd-skin-lightpink .tpd-background-shadow {
924 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
925 | }
926 | .tpd-skin-lightpink .tpd-spinner-spin {
927 | border-color: rgba(51, 51, 51, 0.2);
928 | border-left-color: #333;
929 | }
930 | .tpd-skin-lightpink a {
931 | color: #777;
932 | }
933 | .tpd-skin-lightpink a:hover {
934 | color: #868686;
935 | }
936 |
--------------------------------------------------------------------------------
/example/css/style.css:
--------------------------------------------------------------------------------
1 | /* RESET */
2 | html,
3 | body,
4 | div,
5 | ul,
6 | ol,
7 | li,
8 | dl,
9 | dt,
10 | dd,
11 | h1,
12 | h2,
13 | h3,
14 | h4,
15 | h5,
16 | h6,
17 | pre,
18 | form,
19 | p,
20 | blockquote,
21 | fieldset,
22 | input {
23 | margin: 0;
24 | padding: 0;
25 | }
26 | h1,
27 | h2,
28 | h3,
29 | h4,
30 | h5,
31 | h6,
32 | pre,
33 | code,
34 | address,
35 | caption,
36 | cite,
37 | code,
38 | th {
39 | font-size: 1em;
40 | font-weight: normal;
41 | font-style: normal;
42 | }
43 | ul,
44 | ol {
45 | list-style: none;
46 | }
47 | fieldset,
48 | img {
49 | border: none;
50 | }
51 | caption,
52 | th {
53 | text-align: left;
54 | }
55 | table {
56 | border-collapse: collapse;
57 | border-spacing: 0;
58 | }
59 |
60 | html {
61 | font: 14px/22px "BemboStd-Regular", Georgia, Times, "Times New Roman", serif;
62 | }
63 | body {
64 | font: 14px/22px "BemboStd-Regular", Georgia, Times, "Times New Roman", serif;
65 | background-color: #646461;
66 | background: #fff;
67 | color: #333;
68 | }
69 | p {
70 | margin-bottom: 32px;
71 | clear: both;
72 | }
73 | a {
74 | color: #0088cc;
75 | text-decoration: none;
76 | outline-style: none;
77 | background: #f0f8fd;
78 | }
79 | a:hover {
80 | text-decoration: underline;
81 | }
82 |
83 | /* box-sizing*/
84 | html {
85 | box-sizing: border-box;
86 | }
87 | *,
88 | *:before,
89 | *:after {
90 | box-sizing: inherit;
91 | }
92 |
93 | #page {
94 | clear: both;
95 | width: 100%;
96 | padding: 5rem 2rem;
97 | font-size: inherit;
98 | }
99 |
100 | .demonstrations {
101 | display: flex;
102 | flex-wrap: wrap;
103 | width: 100%;
104 | max-width: 300px;
105 | }
106 | .demonstrations .box {
107 | position: relative;
108 | overflow: hidden;
109 | height: 60px;
110 | width: calc((100% - (6 * 5px)) / 3);
111 | margin: 5px;
112 | line-height: 60px;
113 | background: #ccc;
114 | cursor: pointer;
115 | font-style: italic;
116 | font-family: Georgia, Times, "Times New Roman", serif;
117 | color: #444;
118 | text-shadow: 0 1px 0 rgb(255 255 255);
119 | text-align: center;
120 | }
121 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Tipped
5 |
6 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 |
45 |
46 |
47 |
small
48 |
medium
49 |
large
50 |
51 |
x-small
52 |
medium ×
53 |
large
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@staaky/tipped",
3 | "title": "Tipped",
4 | "version": "4.8.1",
5 | "description": "A complete Tooltip solution based on jQuery",
6 | "author": {
7 | "name": "Nick Stakenburg",
8 | "url": "https://github.com/staaky"
9 | },
10 | "main": "dist/js/tipped.js",
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/staaky/tipped.git"
14 | },
15 | "keywords": [
16 | "tooltip",
17 | "tooltips",
18 | "responsive",
19 | "jquery",
20 | "jquery-plugin"
21 | ],
22 | "license": "CC-BY-4.0",
23 | "scripts": {
24 | "build": "grunt",
25 | "update": "ncu -u"
26 | },
27 | "devDependencies": {
28 | "grunt": "^1.4.1",
29 | "grunt-contrib-clean": "^2.0.0",
30 | "grunt-contrib-concat": "^1.0.1",
31 | "grunt-contrib-copy": "^1.0.0",
32 | "grunt-contrib-uglify": "^5.0.1",
33 | "grunt-contrib-watch": "^1.1.0",
34 | "npm-check-updates": "^11.8.5",
35 | "prettier": "2.4.0"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/css/tipped.css:
--------------------------------------------------------------------------------
1 | .tpd-tooltip {
2 | position: absolute;
3 | }
4 |
5 | /* Fix for CSS frameworks that don't keep the use of box-sizing: border-box
6 | within their own namespace */
7 | .tpd-tooltip {
8 | box-sizing: content-box;
9 | }
10 | .tpd-tooltip [class^="tpd-"] {
11 | box-sizing: inherit;
12 | }
13 |
14 | /* Content */
15 | .tpd-content-wrapper {
16 | position: absolute;
17 | top: 0;
18 | left: 0;
19 | float: left;
20 | width: 100%;
21 | height: 100%;
22 | overflow: hidden;
23 | }
24 | .tpd-content-spacer,
25 | .tpd-content-relative,
26 | .tpd-content-relative-padder {
27 | float: left;
28 | position: relative;
29 | }
30 | .tpd-content-relative {
31 | width: 100%;
32 | }
33 |
34 | .tpd-content {
35 | float: left;
36 | clear: both;
37 | position: relative;
38 | padding: 10px;
39 | font-size: 11px;
40 | line-height: 16px;
41 | color: #fff;
42 | box-sizing: border-box !important;
43 | }
44 | .tpd-has-inner-close .tpd-content-relative .tpd-content {
45 | padding-right: 0 !important;
46 | }
47 | .tpd-tooltip .tpd-content-no-padding {
48 | padding: 0 !important;
49 | }
50 |
51 | .tpd-title-wrapper {
52 | float: left;
53 | position: relative;
54 | overflow: hidden;
55 | }
56 | .tpd-title-spacer {
57 | float: left;
58 | }
59 | .tpd-title-relative,
60 | .tpd-title-relative-padder {
61 | float: left;
62 | position: relative;
63 | }
64 | .tpd-title-relative {
65 | width: 100%;
66 | }
67 | .tpd-title {
68 | float: left;
69 | position: relative;
70 | font-size: 11px;
71 | line-height: 16px;
72 | padding: 10px;
73 | font-weight: bold;
74 | text-transform: uppercase;
75 | color: #fff;
76 | box-sizing: border-box !important;
77 | }
78 | .tpd-has-title-close .tpd-title {
79 | padding-right: 0 !important;
80 | }
81 | .tpd-close {
82 | position: absolute;
83 | top: 0;
84 | right: 0;
85 | width: 28px;
86 | height: 28px;
87 | cursor: pointer;
88 | overflow: hidden;
89 | color: #fff;
90 | }
91 | .tpd-close-icon {
92 | float: left;
93 | font-family: Arial, Baskerville, monospace;
94 | font-weight: normal;
95 | font-style: normal;
96 | text-decoration: none;
97 | width: 28px;
98 | height: 28px;
99 | font-size: 28px;
100 | line-height: 28px;
101 | text-align: center;
102 | }
103 |
104 | /* Skin */
105 | .tpd-skin {
106 | position: absolute;
107 | top: 0;
108 | left: 0;
109 | }
110 |
111 | .tpd-frames {
112 | position: absolute;
113 | top: 0;
114 | left: 0;
115 | }
116 | .tpd-frames .tpd-frame {
117 | float: left;
118 | width: 100%;
119 | height: 100%;
120 | clear: both;
121 | display: none;
122 | }
123 |
124 | .tpd-visible-frame-top .tpd-frame-top {
125 | display: block;
126 | }
127 | .tpd-visible-frame-bottom .tpd-frame-bottom {
128 | display: block;
129 | }
130 | .tpd-visible-frame-left .tpd-frame-left {
131 | display: block;
132 | }
133 | .tpd-visible-frame-right .tpd-frame-right {
134 | display: block;
135 | }
136 |
137 | .tpd-backgrounds {
138 | position: absolute;
139 | top: 0;
140 | left: 0;
141 | width: 100%;
142 | height: 100%;
143 | -webkit-transform-origin: 0% 0%;
144 | transform-origin: 0% 0%;
145 | }
146 | .tpd-background-shadow {
147 | position: absolute;
148 | top: 0;
149 | left: 0;
150 | width: 100%;
151 | height: 100%;
152 | background-color: transparent;
153 | pointer-events: none;
154 | }
155 | .tpd-no-shadow .tpd-skin .tpd-background-shadow {
156 | box-shadow: none !important;
157 | }
158 |
159 | .tpd-background-box {
160 | position: absolute;
161 | top: 0;
162 | left: 0;
163 | height: 100%;
164 | width: 100%;
165 | overflow: hidden;
166 | }
167 | /* only the top background box should be shown when not using a stem */
168 | .tpd-no-stem .tpd-background-box,
169 | .tpd-no-stem .tpd-shift-stem {
170 | display: none;
171 | }
172 | .tpd-no-stem .tpd-background-box-top {
173 | display: block;
174 | }
175 |
176 | .tpd-background-box-shift,
177 | .tpd-background-box-shift-further {
178 | position: relative;
179 | float: left;
180 | width: 100%;
181 | height: 100%;
182 | }
183 | .tpd-background {
184 | border-radius: 10px;
185 | float: left;
186 | clear: both;
187 | background: none;
188 | -webkit-background-clip: padding-box; /* Safari */
189 | background-clip: padding-box; /* IE9+, Firefox 4+, Opera, Chrome */
190 | border-style: solid;
191 | border-width: 1px;
192 | border-color: rgba(
193 | 255,
194 | 255,
195 | 255,
196 | 0.1
197 | ); /* opacity here bugs out in firefox, .tpd-background-content should have no opacity if this opacity is less than 1 */
198 | }
199 | .tpd-background-loading {
200 | display: none;
201 | }
202 | /* no radius */
203 | .tpd-no-radius
204 | .tpd-skin
205 | .tpd-frames
206 | .tpd-frame
207 | .tpd-backgrounds
208 | .tpd-background {
209 | border-radius: 0;
210 | }
211 | .tpd-background-title {
212 | float: left;
213 | clear: both;
214 | width: 100%;
215 | background-color: #282828;
216 | }
217 | .tpd-background-content {
218 | float: left;
219 | clear: both;
220 | width: 100%;
221 | background-color: #282828;
222 | }
223 | .tpd-background-border-hack {
224 | position: absolute;
225 | top: 0;
226 | left: 0;
227 | width: 100%;
228 | height: 100%;
229 | border-style: solid;
230 | }
231 |
232 | .tpd-background-box-top {
233 | top: 0;
234 | }
235 | .tpd-background-box-bottom {
236 | bottom: 0;
237 | }
238 | .tpd-background-box-left {
239 | left: 0;
240 | }
241 | .tpd-background-box-right {
242 | right: 0;
243 | }
244 |
245 | /* Skin / Stems */
246 | .tpd-shift-stem {
247 | position: absolute;
248 | top: 0;
249 | left: 0;
250 | overflow: hidden;
251 | }
252 | .tpd-shift-stem-side {
253 | position: absolute;
254 | }
255 | .tpd-frame-top .tpd-shift-stem-side,
256 | .tpd-frame-bottom .tpd-shift-stem-side {
257 | width: 100%;
258 | }
259 | .tpd-frame-left .tpd-shift-stem-side,
260 | .tpd-frame-right .tpd-shift-stem-side {
261 | height: 100%;
262 | }
263 |
264 | .tpd-stem {
265 | position: absolute;
266 | top: 0;
267 | left: 0;
268 | overflow: hidden; /* shows possible invalid subpx rendering */
269 | width: 16px; /* best cross browser stem: width = 2 x height (90deg angle) */
270 | height: 8px;
271 | margin-left: 3px; /* space from the side */
272 | margin-top: 2px; /* space between target and stem */
273 | -webkit-transform-origin: 0% 0%;
274 | transform-origin: 0% 0%;
275 | }
276 | /* remove margins once we're done measuring */
277 | .tpd-tooltip .tpd-skin .tpd-frames .tpd-frame .tpd-shift-stem .tpd-stem-reset {
278 | margin: 0 !important;
279 | }
280 |
281 | .tpd-stem-spacer {
282 | position: absolute;
283 | top: 0;
284 | left: 0;
285 | width: 100%;
286 | height: 100%;
287 | }
288 | .tpd-stem-reset .tpd-stem-spacer {
289 | margin-top: 0;
290 | }
291 |
292 | .tpd-stem-point {
293 | width: 100px;
294 | position: absolute;
295 | top: 0;
296 | left: 50%;
297 | }
298 | .tpd-stem-downscale,
299 | .tpd-stem-transform {
300 | float: left;
301 | width: 100%;
302 | height: 100%;
303 | -webkit-transform-origin: 0% 0%;
304 | transform-origin: 0% 0%;
305 | position: relative;
306 | }
307 |
308 | .tpd-stem-side {
309 | width: 50%;
310 | height: 100%;
311 | float: left;
312 | position: relative;
313 | overflow: hidden;
314 | }
315 | .tpd-stem-side-inversed {
316 | -webkit-transform: scale(-1, 1);
317 | transform: scale(-1, 1);
318 | }
319 | .tpd-stem-triangle {
320 | width: 0;
321 | height: 0;
322 | border-bottom-style: solid;
323 | border-left-color: transparent;
324 | border-left-style: solid;
325 | position: absolute;
326 | top: 0;
327 | left: 0;
328 | }
329 | .tpd-stem-border {
330 | width: 20px;
331 | height: 100%;
332 | position: absolute;
333 | top: 0;
334 | left: 50%;
335 | background-color: #fff; /* will become transparent */
336 | border-right-color: #fff;
337 | border-right-style: solid;
338 | border-right-width: 0;
339 | }
340 |
341 | .tpd-stem-border-corner {
342 | position: absolute;
343 | top: 0;
344 | left: 50%;
345 | height: 100%;
346 | border-right-style: solid;
347 | border-right-width: 0;
348 | }
349 |
350 | /* fixes rendering issue in IE */
351 | .tpd-stem * {
352 | z-index: 0;
353 | zoom: 1;
354 | }
355 |
356 | /* used by IE < 9 */
357 | .tpd-stem-border-center-offset,
358 | .tpd-stem-border-center-offset-inverse {
359 | float: left;
360 | position: relative;
361 | width: 100%;
362 | height: 100%;
363 | overflow: hidden;
364 | }
365 | .tpd-stem-notransform {
366 | float: left;
367 | width: 100%;
368 | height: 100%;
369 | position: relative;
370 | }
371 | .tpd-stem-notransform .tpd-stem-border {
372 | height: 100%;
373 | position: relative;
374 | float: left;
375 | top: 0;
376 | left: 0;
377 | margin: 0;
378 | }
379 | .tpd-stem-notransform .tpd-stem-border-center {
380 | position: absolute;
381 | }
382 | .tpd-stem-notransform .tpd-stem-border-corner {
383 | background: #fff;
384 | border: 0;
385 | top: auto;
386 | left: auto;
387 | }
388 | .tpd-stem-notransform .tpd-stem-border-center,
389 | .tpd-stem-notransform .tpd-stem-triangle {
390 | height: 0;
391 | border: 0;
392 | left: 50%;
393 | }
394 |
395 | /* transformations for left/right/bottom */
396 | .tpd-stem-transform-left {
397 | -webkit-transform: rotate(-90deg) scale(-1, 1);
398 | transform: rotate(-90deg) scale(-1, 1);
399 | }
400 | .tpd-stem-transform-right {
401 | -webkit-transform: rotate(90deg) translate(0, -100%);
402 | transform: rotate(90deg) translate(0, -100%);
403 | }
404 | .tpd-stem-transform-bottom {
405 | -webkit-transform: scale(1, -1) translate(0, -100%);
406 | transform: scale(1, -1) translate(0, -100%);
407 | }
408 |
409 | /* Spinner */
410 | .tpd-spinner {
411 | position: absolute;
412 | top: 50%;
413 | left: 50%;
414 | width: 46px;
415 | height: 36px;
416 | }
417 | .tpd-spinner-spin {
418 | position: relative;
419 | float: left;
420 | margin: 8px 0 0 13px;
421 | text-indent: -9999em;
422 | border-top: 2px solid rgba(255, 255, 255, 0.2);
423 | border-right: 2px solid rgba(255, 255, 255, 0.2);
424 | border-bottom: 2px solid rgba(255, 255, 255, 0.2);
425 | border-left: 2px solid #fff;
426 | -webkit-animation: tpd-spinner-animation 1.1s infinite linear;
427 | animation: tpd-spinner-animation 1.1s infinite linear;
428 | box-sizing: border-box !important;
429 | }
430 | .tpd-spinner-spin,
431 | .tpd-spinner-spin:after {
432 | border-radius: 50%;
433 | width: 20px;
434 | height: 20px;
435 | }
436 | @-webkit-keyframes tpd-spinner-animation {
437 | 0% {
438 | -webkit-transform: rotate(0deg);
439 | transform: rotate(0deg);
440 | }
441 | 100% {
442 | -webkit-transform: rotate(360deg);
443 | transform: rotate(360deg);
444 | }
445 | }
446 | @keyframes tpd-spinner-animation {
447 | 0% {
448 | -webkit-transform: rotate(0deg);
449 | transform: rotate(0deg);
450 | }
451 | 100% {
452 | -webkit-transform: rotate(360deg);
453 | transform: rotate(360deg);
454 | }
455 | }
456 |
457 | /* show the loader while loading and hide all the content */
458 | .tpd-is-loading .tpd-content-wrapper,
459 | .tpd-is-loading .tpd-title-wrapper {
460 | display: none;
461 | }
462 | .tpd-is-loading .tpd-background {
463 | display: none;
464 | }
465 | .tpd-is-loading .tpd-background-loading {
466 | display: block;
467 | }
468 |
469 | /* Resets while measuring content */
470 | .tpd-tooltip-measuring {
471 | top: 0;
472 | left: 0;
473 | position: absolute;
474 | max-width: 100%;
475 | width: 100%;
476 | }
477 | .tpd-tooltip-measuring .tpd-skin,
478 | .tpd-tooltip-measuring .tpd-spinner {
479 | display: none;
480 | }
481 |
482 | .tpd-tooltip-measuring .tpd-content-wrapper,
483 | .tpd-tooltip-measuring .tpd-title-wrapper {
484 | display: block;
485 | }
486 |
487 | /* Links */
488 | .tpd-tooltip a,
489 | .tpd-tooltip a:hover {
490 | color: #808080;
491 | text-decoration: underline;
492 | }
493 | .tpd-tooltip a:hover {
494 | color: #6c6c6c;
495 | }
496 |
497 | /*
498 | * Sizes
499 | */
500 | /* x-small */
501 | .tpd-size-x-small .tpd-content,
502 | .tpd-size-x-small .tpd-title {
503 | padding: 7px 8px;
504 | font-size: 10px;
505 | line-height: 15px;
506 | }
507 | .tpd-size-x-small .tpd-background {
508 | border-radius: 5px;
509 | }
510 | .tpd-size-x-small .tpd-stem {
511 | width: 12px;
512 | height: 6px;
513 | margin-left: 4px;
514 | margin-top: 2px; /* space between target and stem */
515 | }
516 | .tpd-size-x-small.tpd-no-radius .tpd-stem {
517 | margin-left: 7px;
518 | }
519 | .tpd-size-x-small .tpd-close {
520 | margin-bottom: 1px;
521 | }
522 | .tpd-size-x-small .tpd-spinner {
523 | width: 35px;
524 | height: 29px;
525 | }
526 | .tpd-size-x-small .tpd-spinner-spin {
527 | margin: 6px 0 0 9px;
528 | }
529 | .tpd-size-x-small .tpd-spinner-spin,
530 | .tpd-size-x-small .tpd-spinner-spin:after {
531 | width: 17px;
532 | height: 17px;
533 | }
534 |
535 | /* small */
536 | .tpd-size-small .tpd-content,
537 | .tpd-size-small .tpd-title {
538 | padding: 8px;
539 | font-size: 10px;
540 | line-height: 16px;
541 | }
542 | .tpd-size-small .tpd-background {
543 | border-radius: 6px;
544 | }
545 | .tpd-size-small .tpd-stem {
546 | width: 14px;
547 | height: 7px;
548 | margin-left: 5px;
549 | margin-top: 2px; /* space between target and stem */
550 | }
551 | .tpd-size-small.tpd-no-radius .tpd-stem {
552 | margin-left: 8px;
553 | }
554 | .tpd-size-small .tpd-close {
555 | margin: 2px 1px;
556 | }
557 | .tpd-size-small .tpd-spinner {
558 | width: 42px;
559 | height: 32px;
560 | }
561 | .tpd-size-small .tpd-spinner-spin {
562 | margin: 7px 0 0 13px;
563 | }
564 | .tpd-size-small .tpd-spinner-spin,
565 | .tpd-size-small .tpd-spinner-spin:after {
566 | width: 18px;
567 | height: 18px;
568 | }
569 |
570 | /* medium (default) */
571 | .tpd-size-medium .tpd-content,
572 | .tpd-size-medium .tpd-title {
573 | padding: 10px;
574 | font-size: 11px;
575 | line-height: 16px;
576 | }
577 | .tpd-size-medium .tpd-background {
578 | border-radius: 8px;
579 | }
580 | .tpd-size-medium .tpd-stem {
581 | width: 16px; /* best cross browser stem width is 2xheight, for a 90deg angle */
582 | height: 8px;
583 | margin-left: 6px; /* space from the side */
584 | margin-top: 2px; /* space between target and stem */
585 | }
586 | .tpd-size-medium.tpd-no-radius .tpd-stem {
587 | margin-left: 10px;
588 | }
589 | .tpd-size-medium .tpd-close {
590 | margin: 4px 2px;
591 | }
592 | /* ideal spinner dimensions don't cause movement op top and
593 | on the stem when switching to text using position:'topleft' */
594 | .tpd-size-medium .tpd-spinner {
595 | width: 50px;
596 | height: 36px;
597 | }
598 | .tpd-size-medium .tpd-spinner-spin {
599 | margin: 8px 0 0 15px;
600 | }
601 | .tpd-size-medium .tpd-spinner-spin,
602 | .tpd-size-medium .tpd-spinner-spin:after {
603 | width: 20px;
604 | height: 20px;
605 | }
606 |
607 | /* large */
608 | .tpd-size-large .tpd-content,
609 | .tpd-size-large .tpd-title {
610 | padding: 10px;
611 | font-size: 13px;
612 | line-height: 18px;
613 | }
614 | .tpd-size-large .tpd-background {
615 | border-radius: 8px;
616 | }
617 | .tpd-size-large .tpd-stem {
618 | width: 18px;
619 | height: 9px;
620 | margin-left: 7px;
621 | margin-top: 2px; /* space between target and stem */
622 | }
623 | .tpd-size-large.tpd-no-radius .tpd-stem {
624 | margin-left: 10px;
625 | }
626 | .tpd-size-large .tpd-close {
627 | margin: 5px 2px 5px 2px;
628 | }
629 | .tpd-size-large .tpd-spinner {
630 | width: 54px;
631 | height: 38px;
632 | }
633 | .tpd-size-large .tpd-spinner-spin {
634 | margin: 9px 0 0 17px;
635 | }
636 | .tpd-size-large .tpd-spinner-spin,
637 | .tpd-size-large .tpd-spinner-spin:after {
638 | width: 20px;
639 | height: 20px;
640 | }
641 |
642 | /* Skins */
643 | /* default (dark) */
644 | .tpd-skin-dark .tpd-content,
645 | .tpd-skin-dark .tpd-title,
646 | .tpd-skin-dark .tpd-close {
647 | color: #fff;
648 | }
649 | .tpd-skin-dark .tpd-background-content,
650 | .tpd-skin-dark .tpd-background-title {
651 | background-color: #282828;
652 | }
653 | .tpd-skin-dark .tpd-background {
654 | border-width: 1px;
655 | border-color: rgba(255, 255, 255, 0.1);
656 | }
657 | /* line below the title */
658 | .tpd-skin-dark .tpd-title-wrapper {
659 | border-bottom: 1px solid #404040;
660 | }
661 | /* spinner */
662 | .tpd-skin-dark .tpd-spinner-spin {
663 | border-color: rgba(255, 255, 255, 0.2);
664 | border-left-color: #fff;
665 | }
666 | /* links */
667 | .tpd-skin-dark a {
668 | color: #ccc;
669 | }
670 | .tpd-skin-dark a:hover {
671 | color: #c0c0c0;
672 | }
673 |
674 | /* light */
675 | .tpd-skin-light .tpd-content,
676 | .tpd-skin-light .tpd-title,
677 | .tpd-skin-light .tpd-close {
678 | color: #333;
679 | }
680 | .tpd-skin-light .tpd-background-content {
681 | background-color: #fff;
682 | }
683 | .tpd-skin-light .tpd-background {
684 | border-width: 1px;
685 | border-color: rgba(0, 0, 0, 0.3);
686 | }
687 | .tpd-skin-light .tpd-background-title {
688 | background-color: #f7f7f7;
689 | }
690 | .tpd-skin-light .tpd-title-wrapper {
691 | border-bottom: 1px solid #c0c0c0;
692 | }
693 | .tpd-skin-light .tpd-background-shadow {
694 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
695 | }
696 | /* fallback for no/disabled shadow */
697 | .tpd-skin-light.tpd-no-shadow .tpd-background {
698 | border-color: rgba(100, 100, 100, 0.3);
699 | }
700 | .tpd-skin-light .tpd-spinner-spin {
701 | border-color: rgba(51, 51, 51, 0.2);
702 | border-left-color: #333;
703 | }
704 | .tpd-skin-light a {
705 | color: #808080;
706 | }
707 | .tpd-skin-light a:hover {
708 | color: #6c6c6c;
709 | }
710 |
711 | /* gray */
712 | .tpd-skin-gray .tpd-content,
713 | .tpd-skin-gray .tpd-title,
714 | .tpd-skin-gray .tpd-close {
715 | color: #fff;
716 | }
717 | .tpd-skin-gray .tpd-background-content,
718 | .tpd-skin-gray .tpd-background-title {
719 | background-color: #727272;
720 | }
721 | .tpd-skin-gray .tpd-background {
722 | border-width: 1px;
723 | border-color: rgba(255, 255, 255, 0.1);
724 | }
725 | .tpd-skin-gray .tpd-title-wrapper {
726 | border-bottom: 1px solid #505050;
727 | }
728 | .tpd-skin-gray .tpd-spinner-spin {
729 | border-color: rgba(255, 255, 255, 0.2);
730 | border-left-color: #fff;
731 | }
732 | .tpd-skin-gray a {
733 | color: #ccc;
734 | }
735 | .tpd-skin-gray a:hover {
736 | color: #b6b6b6;
737 | }
738 |
739 | /* red */
740 | .tpd-skin-red .tpd-content,
741 | .tpd-skin-red .tpd-title,
742 | .tpd-skin-red .tpd-close {
743 | color: #fff;
744 | }
745 | .tpd-skin-red .tpd-background-content {
746 | background-color: #e13c37;
747 | }
748 | .tpd-skin-red .tpd-background {
749 | border-width: 1px;
750 | border-color: rgba(12, 0, 0, 0.6);
751 | }
752 | .tpd-skin-red .tpd-background-title {
753 | background-color: #e13c37;
754 | }
755 | .tpd-skin-red .tpd-title-wrapper {
756 | border-bottom: 1px solid #a30500;
757 | }
758 | .tpd-skin-red .tpd-background-shadow {
759 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
760 | }
761 | .tpd-skin-red .tpd-spinner-spin {
762 | border-color: rgba(255, 255, 255, 0.2);
763 | border-left-color: #fff;
764 | }
765 | .tpd-skin-red a {
766 | color: #ddd;
767 | }
768 | .tpd-skin-red a:hover {
769 | color: #c6c6c6;
770 | }
771 |
772 | /* green */
773 | .tpd-skin-green .tpd-content,
774 | .tpd-skin-green .tpd-title,
775 | .tpd-skin-green .tpd-close {
776 | color: #fff;
777 | }
778 | .tpd-skin-green .tpd-background-content {
779 | background-color: #4aab3a;
780 | }
781 | .tpd-skin-green .tpd-background {
782 | border-width: 1px;
783 | border-color: rgba(0, 12, 0, 0.6);
784 | }
785 | .tpd-skin-green .tpd-background-title {
786 | background-color: #4aab3a;
787 | }
788 | .tpd-skin-green .tpd-title-wrapper {
789 | border-bottom: 1px solid #127c00;
790 | }
791 | .tpd-skin-green .tpd-background-shadow {
792 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
793 | }
794 | .tpd-skin-green .tpd-spinner-spin {
795 | border-color: rgba(255, 255, 255, 0.2);
796 | border-left-color: #fff;
797 | }
798 | .tpd-skin-green a {
799 | color: #ddd;
800 | }
801 | .tpd-skin-green a:hover {
802 | color: #c6c6c6;
803 | }
804 |
805 | /* blue */
806 | .tpd-skin-blue .tpd-content,
807 | .tpd-skin-blue .tpd-title,
808 | .tpd-skin-blue .tpd-close {
809 | color: #fff;
810 | }
811 | .tpd-skin-blue .tpd-background-content {
812 | background-color: #45a3e3;
813 | }
814 | .tpd-skin-blue .tpd-background {
815 | border-width: 1px;
816 | border-color: rgba(0, 0, 12, 0.6);
817 | }
818 | .tpd-skin-blue .tpd-background-title {
819 | background-color: #45a3e3;
820 | }
821 | .tpd-skin-blue .tpd-title-wrapper {
822 | border-bottom: 1px solid #1674b4;
823 | }
824 | .tpd-skin-blue .tpd-background-shadow {
825 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
826 | }
827 | .tpd-skin-blue .tpd-spinner-spin {
828 | border-color: rgba(255, 255, 255, 0.2);
829 | border-left-color: #fff;
830 | }
831 | .tpd-skin-blue a {
832 | color: #ddd;
833 | }
834 | .tpd-skin-blue a:hover {
835 | color: #c6c6c6;
836 | }
837 |
838 | /* lightyellow */
839 | .tpd-skin-lightyellow .tpd-content,
840 | .tpd-skin-lightyellow .tpd-title,
841 | .tpd-skin-lightyellow .tpd-close {
842 | color: #333;
843 | }
844 | .tpd-skin-lightyellow .tpd-background-content {
845 | background-color: #ffffa9;
846 | }
847 | .tpd-skin-lightyellow .tpd-background {
848 | border-width: 1px;
849 | border-color: rgba(8, 8, 0, 0.35);
850 | }
851 | .tpd-skin-lightyellow .tpd-background-title {
852 | background-color: #ffffa9;
853 | }
854 | .tpd-skin-lightyellow .tpd-title-wrapper {
855 | border-bottom: 1px solid #a7a697;
856 | }
857 | .tpd-skin-lightyellow .tpd-background-shadow {
858 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
859 | }
860 | .tpd-skin-lightyellow .tpd-spinner-spin {
861 | border-color: rgba(51, 51, 51, 0.2);
862 | border-left-color: #333;
863 | }
864 | .tpd-skin-lightyellow a {
865 | color: #777;
866 | }
867 | .tpd-skin-lightyellow a:hover {
868 | color: #868686;
869 | }
870 |
871 | /* lightblue */
872 | .tpd-skin-lightblue .tpd-content,
873 | .tpd-skin-lightblue .tpd-title,
874 | .tpd-skin-lightblue .tpd-close {
875 | color: #333;
876 | }
877 | .tpd-skin-lightblue .tpd-background-content {
878 | background-color: #bce5ff;
879 | }
880 | .tpd-skin-lightblue .tpd-background {
881 | border-width: 1px;
882 | border-color: rgba(0, 0, 8, 0.35);
883 | }
884 | .tpd-skin-lightblue .tpd-background-title {
885 | background-color: #bce5ff;
886 | }
887 | .tpd-skin-lightblue .tpd-title-wrapper {
888 | border-bottom: 1px solid #909b9f;
889 | }
890 | .tpd-skin-lightblue .tpd-background-shadow {
891 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
892 | }
893 | .tpd-skin-lightblue .tpd-spinner-spin {
894 | border-color: rgba(51, 51, 51, 0.2);
895 | border-left-color: #333;
896 | }
897 | .tpd-skin-lightblue a {
898 | color: #777;
899 | }
900 | .tpd-skin-lightblue a:hover {
901 | color: #868686;
902 | }
903 |
904 | /* lightpink */
905 | .tpd-skin-lightpink .tpd-content,
906 | .tpd-skin-lightpink .tpd-title,
907 | .tpd-skin-lightpink .tpd-close {
908 | color: #333;
909 | }
910 | .tpd-skin-lightpink .tpd-background-content {
911 | background-color: #ffc4bf;
912 | }
913 | .tpd-skin-lightpink .tpd-background {
914 | border-width: 1px;
915 | border-color: rgba(8, 0, 0, 0.35);
916 | }
917 | .tpd-skin-lightpink .tpd-background-title {
918 | background-color: #ffc4bf;
919 | }
920 | .tpd-skin-lightpink .tpd-title-wrapper {
921 | border-bottom: 1px solid #a08f8f;
922 | }
923 | .tpd-skin-lightpink .tpd-background-shadow {
924 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
925 | }
926 | .tpd-skin-lightpink .tpd-spinner-spin {
927 | border-color: rgba(51, 51, 51, 0.2);
928 | border-left-color: #333;
929 | }
930 | .tpd-skin-lightpink a {
931 | color: #777;
932 | }
933 | .tpd-skin-lightpink a:hover {
934 | color: #868686;
935 | }
936 |
--------------------------------------------------------------------------------
/src/js/api.js:
--------------------------------------------------------------------------------
1 | $.extend(Tipped, {
2 | init: function () {
3 | Tooltips.init();
4 | },
5 |
6 | create: function (element, content) {
7 | var options = $.extend({}, arguments[2] || {}),
8 | tooltips = [];
9 |
10 | // initialize tooltips
11 | if (_.isElement(element)) {
12 | tooltips.push(new Tooltip(element, content, options));
13 | } else {
14 | // assume selector
15 | $(element).each(function (i, el) {
16 | tooltips.push(new Tooltip(el, content, options));
17 | });
18 | }
19 |
20 | return new Collection(tooltips);
21 | },
22 |
23 | get: function (selector) {
24 | var tooltips = Tooltips.get(selector);
25 | return new Collection(tooltips);
26 | },
27 |
28 | findElement: function (element) {
29 | return Tooltips.findElement(element);
30 | },
31 |
32 | hideAll: function () {
33 | Tooltips.hideAll();
34 | return this;
35 | },
36 |
37 | setDefaultSkin: function (name) {
38 | Tooltips.setDefaultSkin(name);
39 | return this;
40 | },
41 |
42 | visible: function (selector) {
43 | if (_.isElement(selector)) {
44 | return Tooltips.isVisibleByElement(selector);
45 | } else if (typeof selector !== "undefined") {
46 | var elements = $(selector),
47 | visible = 0;
48 | $.each(elements, function (i, element) {
49 | if (Tooltips.isVisibleByElement(element)) visible++;
50 | });
51 | return visible;
52 | } else {
53 | return Tooltips.getVisible().length;
54 | }
55 | },
56 |
57 | clearAjaxCache: function () {
58 | Tooltips.clearAjaxCache();
59 | return this;
60 | },
61 |
62 | refresh: function (selector, doneCallback, progressCallback) {
63 | Tooltips.refresh(selector, doneCallback, progressCallback);
64 | return this;
65 | },
66 |
67 | setStartingZIndex: function (index) {
68 | Tooltips.setStartingZIndex(index);
69 | return this;
70 | },
71 |
72 | remove: function (selector) {
73 | Tooltips.remove(selector);
74 | return this;
75 | },
76 | });
77 |
78 | $.each("show hide toggle disable enable".split(" "), function (i, name) {
79 | Tipped[name] = function (selector) {
80 | this.get(selector)[name]();
81 | return this;
82 | };
83 | });
84 |
--------------------------------------------------------------------------------
/src/js/behaviors.js:
--------------------------------------------------------------------------------
1 | Tipped.Behaviors = {
2 | hide: {
3 | showOn: {
4 | element: "mouseenter",
5 | tooltip: false,
6 | },
7 | hideOn: {
8 | element: "mouseleave",
9 | tooltip: "mouseenter",
10 | },
11 | },
12 |
13 | mouse: {
14 | showOn: {
15 | element: "mouseenter",
16 | tooltip: false,
17 | },
18 | hideOn: {
19 | element: "mouseleave",
20 | tooltip: "mouseenter",
21 | },
22 | target: "mouse",
23 | showDelay: 100,
24 | fadeIn: 0,
25 | hideDelay: 0,
26 | fadeOut: 0,
27 | },
28 |
29 | sticky: {
30 | showOn: {
31 | element: "mouseenter",
32 | tooltip: "mouseenter",
33 | },
34 | hideOn: {
35 | element: "mouseleave",
36 | tooltip: "mouseleave",
37 | },
38 | // more show delay solves issues positioning at the initial mouse
39 | // position when elements span multiple lines/line-breaks, since
40 | // the mouse won't be positioning close to the edge
41 | showDelay: 150,
42 | target: "mouse",
43 | fixed: true,
44 | },
45 | };
46 |
--------------------------------------------------------------------------------
/src/js/collection.js:
--------------------------------------------------------------------------------
1 | function Collection() {
2 | this.initialize.apply(this, _slice.call(arguments));
3 | }
4 |
5 | $.extend(Collection.prototype, {
6 | initialize: function (tooltips) {
7 | this.tooltips = tooltips;
8 | return this;
9 | },
10 |
11 | items: function () {
12 | // everytime we grab a tooltip collection we'll clear the mouse buffer
13 | // this way it's never passed onto the elements
14 | $.each(this.tooltips, function (i, tooltip) {
15 | tooltip.is("api", true);
16 | });
17 |
18 | return this.tooltips;
19 | },
20 |
21 | refresh: function () {
22 | $.each(this._tooltips, function (_i, tooltip) {
23 | if (tooltip.is("visible")) {
24 | tooltip.refresh();
25 | }
26 | });
27 | return this;
28 | },
29 |
30 | remove: function () {
31 | Tooltips.removeTooltips(this.tooltips);
32 |
33 | // clear tooltips on this collection
34 | this.tooltips = [];
35 |
36 | return this;
37 | },
38 | });
39 |
40 | $.each("show hide toggle disable enable".split(" "), function (_i, name) {
41 | Collection.prototype[name] = function () {
42 | $.each(this.tooltips, function (_j, tooltip) {
43 | tooltip.is("api", true);
44 | tooltip[name]();
45 | });
46 | return this;
47 | };
48 | });
49 |
--------------------------------------------------------------------------------
/src/js/delegate.js:
--------------------------------------------------------------------------------
1 | $.extend(Tipped, {
2 | delegate: function () {
3 | Delegations.add.apply(Delegations, _slice.call(arguments));
4 | },
5 |
6 | undelegate: function () {
7 | Delegations.remove.apply(Delegations, _slice.call(arguments));
8 | },
9 | });
10 |
11 | var Delegations = {
12 | _uid: 0,
13 | _delegations: {},
14 |
15 | add: function (selector, content, options) {
16 | var options;
17 | if (typeof content === "object" && !_.isElement(content)) {
18 | options = content;
19 | content = null;
20 | } else {
21 | options = arguments[2] || {};
22 | }
23 |
24 | var uid = ++this._uid;
25 |
26 | var ttOptions = Options.create($.extend({}, options));
27 |
28 | this._delegations[uid] = {
29 | uid: uid,
30 | selector: selector,
31 | content: content,
32 | options: ttOptions,
33 | };
34 |
35 | var handler = function (event) {
36 | // store the uid so we don't create a second tooltip
37 | $(this).addClass("tpd-delegation-uid-" + uid);
38 |
39 | // now create the tooltip
40 | var tooltip = new Tooltip(this, content, options);
41 |
42 | // store any cached pageX/Y on it
43 | tooltip._cache.event = event;
44 |
45 | tooltip.setActive();
46 |
47 | tooltip.showDelayed();
48 | };
49 |
50 | this._delegations[uid].removeTitleHandler = this.removeTitle.bind(this);
51 | $(document).on(
52 | "mouseenter",
53 | selector + ":not(.tpd-delegation-uid-" + uid + ")",
54 | this._delegations[uid].removeTitleHandler
55 | );
56 |
57 | this._delegations[uid].handler = handler;
58 | $(document).on(
59 | ttOptions.showOn.element,
60 | selector + ":not(.tpd-delegation-uid-" + uid + ")",
61 | handler
62 | );
63 | },
64 |
65 | // puts the title into data-tipped-restore-title,
66 | // this way tooltip creation picks up on it
67 | // without showing the native title tooltip
68 | removeTitle: function (event) {
69 | var element = event.currentTarget;
70 |
71 | var title = $(element).attr("title");
72 |
73 | // backup title
74 | if (title) {
75 | $(element).data("tipped-restore-title", title);
76 | $(element)[0].setAttribute("title", ""); // IE needs setAttribute
77 | }
78 | },
79 |
80 | remove: function (selector) {
81 | $.each(
82 | this._delegations,
83 | function (uid, delegation) {
84 | if (delegation.selector === selector) {
85 | $(document)
86 | .off(
87 | "mouseenter",
88 | selector + ":not(.tpd-delegation-uid-" + uid + ")",
89 | delegation.removeTitleHandler
90 | )
91 | .off(
92 | delegation.options.showOn.element,
93 | selector + ":not(.tpd-delegation-uid-" + uid + ")",
94 | delegation.handler
95 | );
96 | delete this._delegations[uid];
97 | }
98 | }.bind(this)
99 | );
100 | },
101 |
102 | removeAll: function () {
103 | $.each(
104 | this._delegations,
105 | function (uid, delegation) {
106 | $(document)
107 | .off(
108 | "mouseenter",
109 | delegation.selector + ":not(.tpd-delegation-uid-" + uid + ")",
110 | delegation.removeTitleHandler
111 | )
112 | .off(
113 | delegation.options.showOn.element,
114 | delegation.selector + ":not(.tpd-delegation-uid-" + uid + ")",
115 | delegation.handler
116 | );
117 | delete this._delegations[uid];
118 | }.bind(this)
119 | );
120 | },
121 | };
122 |
--------------------------------------------------------------------------------
/src/js/helpers/ajaxcache.js:
--------------------------------------------------------------------------------
1 | var AjaxCache = (function () {
2 | var cache = [];
3 |
4 | return {
5 | // return an update object to pass onto tooltip.update()
6 | get: function (ajax) {
7 | var entry = null;
8 | for (var i = 0; i < cache.length; i++) {
9 | if (
10 | cache[i] &&
11 | cache[i].url === ajax.url &&
12 | (cache[i].type || "GET").toUpperCase() ===
13 | (ajax.type || "GET").toUpperCase() &&
14 | $.param(cache[i].data || {}) === $.param(ajax.data || {})
15 | ) {
16 | entry = cache[i];
17 | }
18 | }
19 | return entry;
20 | },
21 |
22 | set: function (ajax, callbackName, args) {
23 | var entry = this.get(ajax);
24 | if (!entry) {
25 | entry = $.extend({ callbacks: {} }, ajax);
26 | cache.push(entry);
27 | }
28 |
29 | entry.callbacks[callbackName] = args;
30 | },
31 |
32 | remove: function (url) {
33 | for (var i = 0; i < cache.length; i++) {
34 | if (cache[i] && cache[i].url === url) {
35 | delete cache[i];
36 | }
37 | }
38 | },
39 |
40 | clear: function () {
41 | cache = [];
42 | },
43 | };
44 | })();
45 |
--------------------------------------------------------------------------------
/src/js/helpers/bounds.js:
--------------------------------------------------------------------------------
1 | var Bounds = {
2 | viewport: function () {
3 | var vp;
4 | if (Browser.MobileSafari || (Browser.Android && Browser.Gecko)) {
5 | vp = { width: window.innerWidth, height: window.innerHeight };
6 | } else {
7 | vp = {
8 | height: $(window).height(),
9 | width: $(window).width(),
10 | };
11 | }
12 |
13 | return vp;
14 | },
15 | };
16 |
--------------------------------------------------------------------------------
/src/js/helpers/browser.js:
--------------------------------------------------------------------------------
1 | var Browser = (function (uA) {
2 | function getVersion(identifier) {
3 | var version = new RegExp(identifier + "([\\d.]+)").exec(uA);
4 | return version ? parseFloat(version[1]) : true;
5 | }
6 |
7 | return {
8 | IE:
9 | !!(window.attachEvent && uA.indexOf("Opera") === -1) &&
10 | getVersion("MSIE "),
11 | Opera:
12 | uA.indexOf("Opera") > -1 &&
13 | ((!!window.opera && opera.version && parseFloat(opera.version())) ||
14 | 7.55),
15 | WebKit: uA.indexOf("AppleWebKit/") > -1 && getVersion("AppleWebKit/"),
16 | Gecko:
17 | uA.indexOf("Gecko") > -1 &&
18 | uA.indexOf("KHTML") === -1 &&
19 | getVersion("rv:"),
20 | MobileSafari: !!uA.match(/Apple.*Mobile.*Safari/),
21 | Chrome: uA.indexOf("Chrome") > -1 && getVersion("Chrome/"),
22 | ChromeMobile: uA.indexOf("CrMo") > -1 && getVersion("CrMo/"),
23 | Android: uA.indexOf("Android") > -1 && getVersion("Android "),
24 | IEMobile: uA.indexOf("IEMobile") > -1 && getVersion("IEMobile/"),
25 | };
26 | })(navigator.userAgent);
27 |
--------------------------------------------------------------------------------
/src/js/helpers/color.js:
--------------------------------------------------------------------------------
1 | var Color = (function () {
2 | var names = {
3 | _default: "#000000",
4 | aqua: "#00ffff",
5 | black: "#000000",
6 | blue: "#0000ff",
7 | fuchsia: "#ff00ff",
8 | gray: "#808080",
9 | green: "#008000",
10 | lime: "#00ff00",
11 | maroon: "#800000",
12 | navy: "#000080",
13 | olive: "#808000",
14 | purple: "#800080",
15 | red: "#ff0000",
16 | silver: "#c0c0c0",
17 | teal: "#008080",
18 | white: "#ffffff",
19 | yellow: "#ffff00",
20 | };
21 |
22 | function hex(x) {
23 | return ("0" + parseInt(x).toString(16)).slice(-2);
24 | }
25 |
26 | function rgb2hex(rgb) {
27 | rgb = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))?\)$/);
28 | return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
29 | }
30 |
31 | return {
32 | toRGB: function (str) {
33 | if (/^rgba?\(/.test(str)) {
34 | return rgb2hex(str);
35 | } else {
36 | // first try color name to hex
37 | if (names[str]) str = names[str];
38 |
39 | // assume already hex, just normalize #rgb #rrggbb
40 | var hex = str.replace("#", "");
41 | if (!/^(?:[0-9a-fA-F]{3}){1,2}$/.test(hex)) return names._default;
42 |
43 | if (hex.length == 3) {
44 | hex =
45 | hex.charAt(0) +
46 | hex.charAt(0) +
47 | hex.charAt(1) +
48 | hex.charAt(1) +
49 | hex.charAt(2) +
50 | hex.charAt(2);
51 | }
52 |
53 | return "#" + hex;
54 | }
55 | },
56 | };
57 | })();
58 |
--------------------------------------------------------------------------------
/src/js/helpers/dimensions.js:
--------------------------------------------------------------------------------
1 | var Dimensions = {
2 | _count: 0,
3 |
4 | // dimensions are returned as the 1st parameter of the callback
5 | get: function (url, options, callback) {
6 | if (typeof options === "function") {
7 | callback = options;
8 | options = {};
9 | }
10 | options = $.extend(
11 | {
12 | type: "image",
13 | lifetime: 1000 * 60 * 5,
14 | },
15 | options || {}
16 | );
17 |
18 | var cache = Dimensions.cache.get(url),
19 | type = options.type,
20 | data = { type: type, callback: callback };
21 |
22 | var img;
23 | if (!cache) {
24 | // nothing in cache, go check
25 | switch (type) {
26 | case "image":
27 | img = new Image();
28 | img.onload = function () {
29 | img.onload = function () {};
30 | cache = {
31 | dimensions: {
32 | width: img.width,
33 | height: img.height,
34 | },
35 | };
36 |
37 | data.image = img;
38 |
39 | Dimensions.cache.set(url, cache.dimensions, data);
40 | if (callback) {
41 | callback(cache.dimensions, data);
42 | }
43 | };
44 |
45 | img.src = url;
46 | break;
47 | }
48 | } else {
49 | img = cache.data.image;
50 | // we return cloned dimensions so the value can't be modified
51 | if (callback) {
52 | callback($.extend({}, cache.dimensions), cache.data);
53 | }
54 | }
55 |
56 | return img;
57 | },
58 | };
59 |
60 | Dimensions.Cache = function () {
61 | return this.initialize.apply(this, _slice.call(arguments));
62 | };
63 | $.extend(Dimensions.Cache.prototype, {
64 | initialize: function () {
65 | this.cache = [];
66 | },
67 |
68 | get: function (url) {
69 | var entry = null;
70 | for (var i = 0; i < this.cache.length; i++) {
71 | if (this.cache[i] && this.cache[i].url === url) entry = this.cache[i];
72 | }
73 | return entry;
74 | },
75 |
76 | set: function (url, dimensions, data) {
77 | this.remove(url);
78 | this.cache.push({ url: url, dimensions: dimensions, data: data });
79 | },
80 |
81 | remove: function (url) {
82 | for (var i = 0; i < this.cache.length; i++) {
83 | if (this.cache[i] && this.cache[i].url === url) {
84 | delete this.cache[i];
85 | }
86 | }
87 | },
88 |
89 | // forcefully inject a cache entry or extend the data of existing cache
90 | inject: function (data) {
91 | var entry = get(data.url);
92 |
93 | if (entry) {
94 | $.extend(entry, data);
95 | } else {
96 | this.cache.push(data);
97 | }
98 | },
99 | });
100 |
101 | Dimensions.cache = new Dimensions.Cache();
102 |
103 | //Loading
104 | Dimensions.Loading = function () {
105 | return this.initialize.apply(this, _slice.call(arguments));
106 | };
107 | $.extend(Dimensions.Loading.prototype, {
108 | initialize: function () {
109 | this.cache = [];
110 | },
111 |
112 | set: function (url, data) {
113 | this.clear(url);
114 | this.cache.push({ url: url, data: data });
115 | },
116 |
117 | get: function (url) {
118 | var entry = null;
119 | for (var i = 0; i < this.cache.length; i++) {
120 | if (this.cache[i] && this.cache[i].url === url) entry = this.cache[i];
121 | }
122 | return entry;
123 | },
124 |
125 | clear: function (url) {
126 | var cache = this.cache;
127 |
128 | for (var i = 0; i < cache.length; i++) {
129 | if (cache[i] && cache[i].url === url && cache[i].data) {
130 | var data = cache[i].data;
131 | switch (data.type) {
132 | case "image":
133 | if (data.image && data.image.onload) {
134 | data.image.onload = function () {};
135 | }
136 | break;
137 | }
138 | delete cache[i];
139 | }
140 | }
141 | },
142 | });
143 |
144 | Dimensions.loading = new Dimensions.Loading();
145 |
--------------------------------------------------------------------------------
/src/js/helpers/helpers.js:
--------------------------------------------------------------------------------
1 | var _slice = Array.prototype.slice;
2 |
3 | var _ = {
4 | wrap: function (fn, wrapper) {
5 | var __fn = fn;
6 | return function () {
7 | var args = [__fn.bind(this)].concat(_slice.call(arguments));
8 | return wrapper.apply(this, args);
9 | };
10 | },
11 |
12 | // is
13 | isElement: function (object) {
14 | return object && object.nodeType === 1;
15 | },
16 |
17 | isText: function (object) {
18 | return object && object.nodeType === 3;
19 | },
20 |
21 | isDocumentFragment: function (object) {
22 | return object && object.nodeType === 11;
23 | },
24 |
25 | delay: function (fn, ms) {
26 | var args = _slice.call(arguments, 2);
27 | return setTimeout(function () {
28 | return fn.apply(fn, args);
29 | }, ms);
30 | },
31 |
32 | defer: function (fn) {
33 | return _.delay.apply(this, [fn, 1].concat(_slice.call(arguments, 1)));
34 | },
35 |
36 | // Event
37 | pointer: function (event) {
38 | return { x: event.pageX, y: event.pageY };
39 | },
40 |
41 | element: {
42 | isAttached: (function () {
43 | function findTopAncestor(element) {
44 | // Walk up the DOM tree until we are at the top
45 | var ancestor = element;
46 | while (ancestor && ancestor.parentNode) {
47 | ancestor = ancestor.parentNode;
48 | }
49 | return ancestor;
50 | }
51 |
52 | return function (element) {
53 | var topAncestor = findTopAncestor(element);
54 | return !!(topAncestor && topAncestor.body);
55 | };
56 | })(),
57 | },
58 | };
59 |
60 | function degrees(radian) {
61 | return (radian * 180) / Math.PI;
62 | }
63 |
64 | function radian(degrees) {
65 | return (degrees * Math.PI) / 180;
66 | }
67 |
68 | function sec(x) {
69 | return 1 / Math.cos(x);
70 | }
71 |
72 | function sfcc(c) {
73 | return String.fromCharCode.apply(String, c.replace(" ", "").split(","));
74 | }
75 |
76 | //deep extend
77 | function deepExtend(destination, source) {
78 | for (var property in source) {
79 | if (
80 | source[property] &&
81 | source[property].constructor &&
82 | source[property].constructor === Object
83 | ) {
84 | destination[property] = $.extend({}, destination[property]) || {};
85 | deepExtend(destination[property], source[property]);
86 | } else {
87 | destination[property] = source[property];
88 | }
89 | }
90 | return destination;
91 | }
92 |
93 | var getUID = (function () {
94 | var count = 0,
95 | _prefix = "_tipped-uid-";
96 |
97 | return function (prefix) {
98 | prefix = prefix || _prefix;
99 |
100 | count++;
101 | // raise the count as long as we find a conflicting element on the page
102 | while (document.getElementById(prefix + count)) {
103 | count++;
104 | }
105 | return prefix + count;
106 | };
107 | })();
108 |
--------------------------------------------------------------------------------
/src/js/helpers/mouse.js:
--------------------------------------------------------------------------------
1 | var Mouse = {
2 | _buffer: { pageX: 0, pageY: 0 },
3 | _dimensions: {
4 | width: 30, // should both be even
5 | height: 30,
6 | },
7 | _shift: {
8 | x: 2,
9 | y: 10, // correction so the tooltip doesn't appear on top of the mouse
10 | },
11 |
12 | // a modified version of the actual position, to match the box
13 | getPosition: function (event) {
14 | var position = this.getActualPosition(event);
15 |
16 | return {
17 | left:
18 | position.left -
19 | Math.round(this._dimensions.width * 0.5) +
20 | this._shift.x,
21 | top:
22 | position.top -
23 | Math.round(this._dimensions.height * 0.5) +
24 | this._shift.y,
25 | };
26 | },
27 |
28 | getActualPosition: function (event) {
29 | var position =
30 | event && typeof event.pageX === "number" ? event : this._buffer;
31 |
32 | return {
33 | left: position.pageX,
34 | top: position.pageY,
35 | };
36 | },
37 |
38 | getDimensions: function () {
39 | return this._dimensions;
40 | },
41 | };
42 |
--------------------------------------------------------------------------------
/src/js/helpers/position.js:
--------------------------------------------------------------------------------
1 | var Position = {
2 | positions: [
3 | "topleft",
4 | "topmiddle",
5 | "topright",
6 | "righttop",
7 | "rightmiddle",
8 | "rightbottom",
9 | "bottomright",
10 | "bottommiddle",
11 | "bottomleft",
12 | "leftbottom",
13 | "leftmiddle",
14 | "lefttop",
15 | ],
16 |
17 | regex: {
18 | toOrientation:
19 | /^(top|left|bottom|right)(top|left|bottom|right|middle|center)$/,
20 | horizontal: /^(top|bottom)/,
21 | isCenter: /(middle|center)/,
22 | side: /^(top|bottom|left|right)/,
23 | },
24 |
25 | toDimension: (function () {
26 | var translate = {
27 | top: "height",
28 | left: "width",
29 | bottom: "height",
30 | right: "width",
31 | };
32 |
33 | return function (position) {
34 | return translate[position];
35 | };
36 | })(),
37 |
38 | isCenter: function (position) {
39 | return !!position.toLowerCase().match(this.regex.isCenter);
40 | },
41 |
42 | isCorner: function (position) {
43 | return !this.isCenter(position);
44 | },
45 |
46 | //returns 'horizontal' or 'vertical' based on the options object
47 | getOrientation: function (position) {
48 | return position.toLowerCase().match(this.regex.horizontal)
49 | ? "horizontal"
50 | : "vertical";
51 | },
52 |
53 | getSide: function (position) {
54 | var side = null,
55 | matches = position.toLowerCase().match(this.regex.side);
56 | if (matches && matches[1]) side = matches[1];
57 | return side;
58 | },
59 |
60 | split: function (position) {
61 | return position.toLowerCase().match(this.regex.toOrientation);
62 | },
63 |
64 | _flip: {
65 | top: "bottom",
66 | bottom: "top",
67 | left: "right",
68 | right: "left",
69 | },
70 | flip: function (position, corner) {
71 | var split = this.split(position);
72 |
73 | if (corner) {
74 | return this.inverseCornerPlane(
75 | this.flip(this.inverseCornerPlane(position))
76 | );
77 | } else {
78 | return this._flip[split[1]] + split[2];
79 | }
80 | },
81 |
82 | inverseCornerPlane: function (position) {
83 | if (Position.isCorner(position)) {
84 | var split = this.split(position);
85 | return split[2] + split[1];
86 | } else {
87 | return position;
88 | }
89 | },
90 |
91 | adjustOffsetBasedOnPosition: function (
92 | offset,
93 | defaultTargetPosition,
94 | targetPosition
95 | ) {
96 | var adjustedOffset = $.extend({}, offset);
97 | var orientationXY = { horizontal: "x", vertical: "y" };
98 | var inverseXY = { x: "y", y: "x" };
99 |
100 | var inverseSides = {
101 | top: { right: "x" },
102 | bottom: { left: "x" },
103 | left: { bottom: "y" },
104 | right: { top: "y" },
105 | };
106 |
107 | var defaultOrientation = Position.getOrientation(defaultTargetPosition);
108 | if (defaultOrientation === Position.getOrientation(targetPosition)) {
109 | // we're on the same orientation
110 | // inverse when needed
111 | if (
112 | Position.getSide(defaultTargetPosition) !==
113 | Position.getSide(targetPosition)
114 | ) {
115 | var inverse = inverseXY[orientationXY[defaultOrientation]];
116 | adjustedOffset[inverse] *= -1;
117 | }
118 | } else {
119 | // moving to a side
120 | // flipXY
121 | var fx = adjustedOffset.x;
122 | adjustedOffset.x = adjustedOffset.y;
123 | adjustedOffset.y = fx;
124 |
125 | // inversing x or y might be required based on movement
126 | var inverseSide =
127 | inverseSides[Position.getSide(defaultTargetPosition)][
128 | Position.getSide(targetPosition)
129 | ];
130 | if (inverseSide) {
131 | adjustedOffset[inverseSide] *= -1;
132 | }
133 |
134 | // nullify x or y
135 | // move to left/right (vertical) = nullify y
136 | adjustedOffset[
137 | orientationXY[Position.getOrientation(targetPosition)]
138 | ] = 0;
139 | }
140 |
141 | return adjustedOffset;
142 | },
143 |
144 | getBoxFromPoints: function (x1, y1, x2, y2) {
145 | var minX = Math.min(x1, x2),
146 | maxX = Math.max(x1, x2),
147 | minY = Math.min(y1, y2),
148 | maxY = Math.max(y1, y2);
149 |
150 | return {
151 | left: minX,
152 | top: minY,
153 | width: Math.max(maxX - minX, 0),
154 | height: Math.max(maxY - minY, 0),
155 | };
156 | },
157 |
158 | isPointWithinBox: function (x1, y1, bx1, by1, bx2, by2) {
159 | var box = this.getBoxFromPoints(bx1, by1, bx2, by2);
160 |
161 | return (
162 | x1 >= box.left &&
163 | x1 <= box.left + box.width &&
164 | y1 >= box.top &&
165 | y1 <= box.top + box.height
166 | );
167 | },
168 | isPointWithinBoxLayout: function (x, y, layout) {
169 | return this.isPointWithinBox(
170 | x,
171 | y,
172 | layout.position.left,
173 | layout.position.top,
174 | layout.position.left + layout.dimensions.width,
175 | layout.position.top + layout.dimensions.height
176 | );
177 | },
178 |
179 | getDistance: function (x1, y1, x2, y2) {
180 | return Math.sqrt(
181 | Math.pow(Math.abs(x2 - x1), 2) + Math.pow(Math.abs(y2 - y1), 2)
182 | );
183 | },
184 |
185 | intersectsLine: (function () {
186 | var ccw = function (x1, y1, x2, y2, x3, y3) {
187 | var cw = (y3 - y1) * (x2 - x1) - (y2 - y1) * (x3 - x1);
188 | return cw > 0 ? true : cw < 0 ? false : true;
189 | };
190 |
191 | return function (x1, y1, x2, y2, x3, y3, x4, y4, isReturnPosition) {
192 | if (!isReturnPosition) {
193 | /* http://www.bryceboe.com/2006/10/23/line-segment-intersection-algorithm */
194 | return (
195 | ccw(x1, y1, x3, y3, x4, y4) != ccw(x2, y2, x3, y3, x4, y4) &&
196 | ccw(x1, y1, x2, y2, x3, y3) != ccw(x1, y1, x2, y2, x4, y4)
197 | );
198 | }
199 |
200 | /* http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect/1968345#1968345 */
201 | var s1_x, s1_y, s2_x, s2_y;
202 | s1_x = x2 - x1;
203 | s1_y = y2 - y1;
204 | s2_x = x4 - x3;
205 | s2_y = y4 - y3;
206 |
207 | var s, t;
208 | s = (-s1_y * (x1 - x3) + s1_x * (y1 - y3)) / (-s2_x * s1_y + s1_x * s2_y);
209 | t = (s2_x * (y1 - y3) - s2_y * (x1 - x3)) / (-s2_x * s1_y + s1_x * s2_y);
210 |
211 | if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
212 | // Collision detected
213 | var atX = x1 + t * s1_x;
214 | var atY = y1 + t * s1_y;
215 | return { x: atX, y: atY };
216 | }
217 |
218 | return false; // No collision
219 | };
220 | })(),
221 | };
222 |
--------------------------------------------------------------------------------
/src/js/helpers/requirements.js:
--------------------------------------------------------------------------------
1 | var Requirements = {
2 | scripts: {
3 | jQuery: {
4 | required: "1.7",
5 | available: window.jQuery && jQuery.fn.jquery,
6 | },
7 | },
8 |
9 | check: (function () {
10 | // Version check, works with 1.2.10.99_beta2 notations
11 | var VERSION_STRING = /^(\d+(\.?\d+){0,3})([A-Za-z_-]+[A-Za-z0-9]+)?/;
12 |
13 | function convertVersionString(versionString) {
14 | var vA = versionString.match(VERSION_STRING),
15 | nA = (vA && vA[1] && vA[1].split(".")) || [],
16 | v = 0;
17 | for (var i = 0, l = nA.length; i < l; i++)
18 | v += parseInt(nA[i] * Math.pow(10, 6 - i * 2));
19 |
20 | return vA && vA[3] ? v - 1 : v;
21 | }
22 |
23 | return function require(script) {
24 | if (
25 | !this.scripts[script].available ||
26 | (convertVersionString(this.scripts[script].available) <
27 | convertVersionString(this.scripts[script].required) &&
28 | !this.scripts[script].notified)
29 | ) {
30 | // mark this alert so it only shows up once
31 | this.scripts[script].notified = true;
32 | warn(
33 | "Tipped requires " + script + " >= " + this.scripts[script].required
34 | );
35 | }
36 | };
37 | })(),
38 | };
39 |
--------------------------------------------------------------------------------
/src/js/helpers/spin.js:
--------------------------------------------------------------------------------
1 | // Spin
2 | // Create pure CSS based spinners
3 | function Spin() {
4 | return this.initialize.apply(this, _slice.call(arguments));
5 | }
6 |
7 | // mark as supported
8 | Spin.supported = Support.css.transform && Support.css.animation;
9 |
10 | $.extend(Spin.prototype, {
11 | initialize: function () {
12 | this.options = $.extend({}, arguments[0] || {});
13 |
14 | this.build();
15 | this.start();
16 | },
17 |
18 | build: function () {
19 | var d = (this.options.length + this.options.radius) * 2;
20 | var dimensions = { height: d, width: d };
21 |
22 | this.element = $("").addClass("tpd-spin").css(dimensions);
23 |
24 | this.element.append(
25 | (this._rotate = $("
").addClass("tpd-spin-rotate"))
26 | );
27 |
28 | this.element.css({
29 | "margin-left": -0.5 * dimensions.width,
30 | "margin-top": -0.5 * dimensions.height,
31 | });
32 |
33 | var lines = this.options.lines;
34 |
35 | // insert 12 frames
36 | for (var i = 0; i < lines; i++) {
37 | var frame, line;
38 | this._rotate.append(
39 | (frame = $("
")
40 | .addClass("tpd-spin-frame")
41 | .append((line = $("
").addClass("tpd-spin-line"))))
42 | );
43 |
44 | line.css({
45 | "background-color": this.options.color,
46 | width: this.options.width,
47 | height: this.options.length,
48 | "margin-left": -0.5 * this.options.width,
49 | "border-radius": Math.round(0.5 * this.options.width),
50 | });
51 |
52 | frame.css({ opacity: ((1 / lines) * (i + 1)).toFixed(2) });
53 |
54 | var transformCSS = {};
55 | transformCSS[Support.css.prefixed("transform")] =
56 | "rotate(" + (360 / lines) * (i + 1) + "deg)";
57 | frame.css(transformCSS);
58 | }
59 | },
60 |
61 | start: function () {
62 | var rotateCSS = {};
63 | rotateCSS[Support.css.prefixed("animation")] =
64 | "tpd-spin 1s infinite steps(" + this.options.lines + ")";
65 | this._rotate.css(rotateCSS);
66 | },
67 |
68 | stop: function () {
69 | var rotateCSS = {};
70 | rotateCSS[Support.css.prefixed("animation")] = "none";
71 | this._rotate.css(rotateCSS);
72 | this.element.detach();
73 | },
74 | });
75 |
--------------------------------------------------------------------------------
/src/js/helpers/support.js:
--------------------------------------------------------------------------------
1 | var Support = (function () {
2 | var testElement = document.createElement("div"),
3 | domPrefixes = "Webkit Moz O ms Khtml".split(" ");
4 |
5 | function prefixed(property) {
6 | return testAllProperties(property, "prefix");
7 | }
8 |
9 | function testProperties(properties, prefixed) {
10 | for (var i in properties) {
11 | if (testElement.style[properties[i]] !== undefined) {
12 | return prefixed === "prefix" ? properties[i] : true;
13 | }
14 | }
15 | return false;
16 | }
17 |
18 | function testAllProperties(property, prefixed) {
19 | var ucProperty = property.charAt(0).toUpperCase() + property.substr(1),
20 | properties = (
21 | property +
22 | " " +
23 | domPrefixes.join(ucProperty + " ") +
24 | ucProperty
25 | ).split(" ");
26 |
27 | return testProperties(properties, prefixed);
28 | }
29 |
30 | // feature detect
31 | return {
32 | css: {
33 | animation: testAllProperties("animation"),
34 | transform: testAllProperties("transform"),
35 | prefixed: prefixed,
36 | },
37 |
38 | shadow:
39 | testAllProperties("boxShadow") && testAllProperties("pointerEvents"),
40 |
41 | touch: (function () {
42 | try {
43 | return !!(
44 | "ontouchstart" in window ||
45 | (window.DocumentTouch && document instanceof DocumentTouch)
46 | ); // firefox for Android
47 | } catch (e) {
48 | return false;
49 | }
50 | })(),
51 | };
52 | })();
53 |
--------------------------------------------------------------------------------
/src/js/helpers/visible.js:
--------------------------------------------------------------------------------
1 | function Visible() {
2 | return this.initialize.apply(this, _slice.call(arguments));
3 | }
4 |
5 | $.extend(Visible.prototype, {
6 | initialize: function (elements) {
7 | elements = Array.isArray(elements) ? elements : [elements]; // ensure array
8 | this.elements = elements;
9 |
10 | this._restore = [];
11 | $.each(
12 | elements,
13 | function (_i, element) {
14 | var visible = $(element).is(":visible");
15 |
16 | if (!visible) {
17 | $(element).show();
18 | }
19 |
20 | this._restore.push({
21 | element: element,
22 | visible: visible,
23 | });
24 | }.bind(this)
25 | );
26 | return this;
27 | },
28 |
29 | restore: function () {
30 | $.each(this._restore, function (i, entry) {
31 | if (!entry.visible) {
32 | $(entry.element).show();
33 | }
34 | });
35 |
36 | this._restore = null;
37 | },
38 | });
39 |
--------------------------------------------------------------------------------
/src/js/options.js:
--------------------------------------------------------------------------------
1 | var Options = {
2 | create: (function () {
3 | var BASE, RESET;
4 |
5 | // hideOn helper
6 | function toDisplayObject(input, display) {
7 | var on;
8 | if (typeof input === "string") {
9 | on = {
10 | element:
11 | (RESET[display] && RESET[display].element) || BASE[display].element,
12 | event: input,
13 | };
14 | } else {
15 | on = deepExtend($.extend({}, BASE[display]), input);
16 | }
17 |
18 | return on;
19 | }
20 |
21 | // hideOn helper
22 | function initialize(options) {
23 | BASE = Tipped.Skins.base;
24 | RESET = deepExtend($.extend({}, BASE), Tipped.Skins["reset"]);
25 | initialize = create;
26 | return create(options);
27 | }
28 |
29 | function middleize(position) {
30 | if (position.match(/^(top|left|bottom|right)$/)) {
31 | position += "middle";
32 | }
33 |
34 | position.replace("center", "middle").replace(" ", "");
35 |
36 | return position;
37 | }
38 |
39 | function presetiffy(options) {
40 | var preset, behavior;
41 | if (options.behavior && (behavior = Tipped.Behaviors[options.behavior])) {
42 | preset = deepExtend($.extend({}, behavior), options);
43 | } else {
44 | preset = options;
45 | }
46 |
47 | return preset;
48 | }
49 |
50 | function create(options) {
51 | var selected_skin = options.skin
52 | ? options.skin
53 | : Tooltips.options.defaultSkin;
54 | var SELECTED = $.extend({}, Tipped.Skins[selected_skin] || {});
55 | // make sure the skin option is set
56 | if (!SELECTED.skin) {
57 | SELECTED.skin = Tooltips.options.defaultSkin || "dark";
58 | }
59 |
60 | var MERGED_SELECTED = deepExtend(
61 | $.extend({}, RESET),
62 | presetiffy(SELECTED)
63 | ); // work presets into selected skin
64 |
65 | var MERGED = deepExtend(
66 | $.extend({}, MERGED_SELECTED),
67 | presetiffy(options)
68 | ); // also work presets into the given options
69 |
70 | // Ajax
71 | if (MERGED.ajax) {
72 | var RESET_ajax = RESET.ajax || {},
73 | BASE_ajax = BASE.ajax;
74 |
75 | if (typeof MERGED.ajax === "boolean") {
76 | // true
77 | MERGED.ajax = {
78 | //method: RESET_ajax.type || BASE_ajax.type
79 | };
80 | }
81 | // otherwise it must be an object
82 | MERGED.ajax = deepExtend($.extend({}, BASE_ajax), MERGED.ajax);
83 | }
84 |
85 | var position;
86 | var targetPosition = (targetPosition =
87 | (MERGED.position && MERGED.position.target) ||
88 | (typeof MERGED.position === "string" && MERGED.position) ||
89 | (RESET.position && RESET.position.target) ||
90 | (typeof RESET.position === "string" && RESET.position) ||
91 | (BASE.position && BASE.position.target) ||
92 | BASE.position);
93 | targetPosition = middleize(targetPosition);
94 |
95 | var tooltipPosition =
96 | (MERGED.position && MERGED.position.tooltip) ||
97 | (RESET.position && RESET.position.tooltip) ||
98 | (BASE.position && BASE.position.tooltip) ||
99 | Tooltips.Position.getInversedPosition(targetPosition);
100 | tooltipPosition = middleize(tooltipPosition);
101 |
102 | if (MERGED.position) {
103 | if (typeof MERGED.position === "string") {
104 | MERGED.position = middleize(MERGED.position);
105 | position = {
106 | target: MERGED.position,
107 | tooltip: Tooltips.Position.getTooltipPositionFromTarget(
108 | MERGED.position
109 | ),
110 | };
111 | } else {
112 | // object
113 | position = { tooltip: tooltipPosition, target: targetPosition };
114 | if (MERGED.position.tooltip) {
115 | position.tooltip = middleize(MERGED.position.tooltip);
116 | }
117 | if (MERGED.position.target) {
118 | position.target = middleize(MERGED.position.target);
119 | }
120 | }
121 | } else {
122 | position = {
123 | tooltip: tooltipPosition,
124 | target: targetPosition,
125 | };
126 | }
127 |
128 | // make sure the 2 positions are on the same plane when centered
129 | // this aligns the sweet spot when repositioning based on the stem
130 | if (
131 | Position.isCorner(position.target) &&
132 | Position.getOrientation(position.target) !==
133 | Position.getOrientation(position.tooltip)
134 | ) {
135 | // switch over the target only, cause we shouldn't be resetting the stem on the tooltip
136 | position.target = Position.inverseCornerPlane(position.target);
137 | }
138 |
139 | // if we're hooking to the mouse we want the center
140 | if (MERGED.target === "mouse") {
141 | var orientation = Position.getOrientation(position.target);
142 |
143 | // force center alignment on the mouse
144 | if (orientation === "horizontal") {
145 | position.target = position.target.replace(/(left|right)/, "middle");
146 | } else {
147 | position.target = position.target.replace(/(top|bottom)/, "middle");
148 | }
149 | }
150 |
151 | // if the target is the mouse we set the position to 'bottomright' so the position system can work with it
152 | MERGED.position = position;
153 |
154 | // Offset
155 | var offset;
156 | if (MERGED.target === "mouse") {
157 | // get the offset of the base class
158 | offset = $.extend({}, BASE.offset);
159 | $.extend(offset, Tipped.Skins["reset"].offset || {});
160 |
161 | if (options.skin) {
162 | $.extend(
163 | offset,
164 | (
165 | Tipped.Skins[options.skin] ||
166 | Tipped.Skins[Tooltips.options.defaultSkin] ||
167 | {}
168 | ).offset || {}
169 | );
170 | }
171 |
172 | // find out what the offset should be
173 | offset = Position.adjustOffsetBasedOnPosition(
174 | BASE.offset,
175 | BASE.position,
176 | position.target,
177 | true
178 | );
179 |
180 | // now put any given options on top of that
181 | if (options.offset) {
182 | offset = $.extend(offset, options.offset || {});
183 | }
184 | } else {
185 | offset = {
186 | x: MERGED.offset.x,
187 | y: MERGED.offset.y,
188 | };
189 | }
190 |
191 | MERGED.offset = offset;
192 |
193 | // hideOnClickOutside
194 | if (MERGED.hideOn && MERGED.hideOn === "click-outside") {
195 | MERGED.hideOnClickOutside = true;
196 | MERGED.hideOn = false;
197 | MERGED.fadeOut = 0; // instantly fadeout for better UI
198 | }
199 |
200 | if (MERGED.showOn) {
201 | // showOn and hideOn should not abide by inheritance,
202 | // otherwise we'd always have the BASE/RESET object for it as starting point
203 | var showOn = MERGED.showOn;
204 |
205 | if (typeof showOn === "string") {
206 | showOn = { element: showOn };
207 | }
208 |
209 | MERGED.showOn = showOn;
210 | }
211 |
212 | if (MERGED.hideOn) {
213 | var hideOn = MERGED.hideOn;
214 |
215 | if (typeof hideOn === "string") {
216 | hideOn = { element: hideOn };
217 | }
218 |
219 | MERGED.hideOn = hideOn;
220 | }
221 |
222 | // normalize inline
223 | if (MERGED.inline) {
224 | if (typeof MERGED.inline !== "string") {
225 | MERGED.inline = false;
226 | }
227 | }
228 |
229 | // fadeIn 0 on IE < 9 to prevent text transform during fade
230 | if (Browser.IE && Browser.IE < 9) {
231 | $.extend(MERGED, { fadeIn: 0, fadeOut: 0, hideDelay: 0 });
232 | }
233 |
234 | if (MERGED.spinner) {
235 | if (!Spin.supported) {
236 | MERGED.spinner = false;
237 | } else {
238 | if (typeof MERGED.spinner === "boolean") {
239 | MERGED.spinner = RESET.spinner || BASE.spinner || {};
240 | }
241 | }
242 | }
243 |
244 | if (!MERGED.container) {
245 | MERGED.container = document.body;
246 | }
247 |
248 | if (MERGED.containment) {
249 | if (typeof MERGED.containment === "string") {
250 | MERGED.containment = {
251 | selector: MERGED.containment,
252 | padding:
253 | (RESET.containment && RESET.containment.padding) ||
254 | (BASE.padding && BASE.containment.padding),
255 | };
256 | }
257 | }
258 |
259 | // normalize shadow, setting it to true should only mean it's enabled when supported
260 | if (MERGED.shadow) {
261 | MERGED.shadow = Support.shadow;
262 | }
263 |
264 | return MERGED;
265 | }
266 |
267 | return initialize;
268 | })(),
269 | };
270 |
--------------------------------------------------------------------------------
/src/js/setup.js:
--------------------------------------------------------------------------------
1 | var Tipped = {};
2 |
3 | $.extend(Tipped, {
4 | version: "<%= pkg.version %>",
5 | });
6 |
--------------------------------------------------------------------------------
/src/js/skin.js:
--------------------------------------------------------------------------------
1 | function Skin() {
2 | this.initialize.apply(this, _slice.call(arguments));
3 | }
4 |
5 | $.extend(Skin.prototype, {
6 | initialize: function (tooltip) {
7 | this.tooltip = tooltip;
8 | this.element = tooltip._skin;
9 |
10 | // classes to further style the tooltip
11 | var options = this.tooltip.options;
12 | this.tooltip._tooltip[(options.shadow ? "remove" : "add") + "Class"](
13 | "tpd-no-shadow"
14 | )
15 | [(options.radius ? "remove" : "add") + "Class"]("tpd-no-radius")
16 | [(options.stem ? "remove" : "add") + "Class"]("tpd-no-stem");
17 |
18 | // we should get radius and border when initializing
19 | var frames, bg, bgc, spinner;
20 | var prefixedRadius = Support.css.prefixed("borderTopLeftRadius");
21 |
22 | this.element
23 | .append(
24 | (frames = $("
")
25 | .addClass("tpd-frames")
26 | .append(
27 | $("
")
28 | .addClass("tpd-frame")
29 | .append(
30 | $("
")
31 | .addClass("tpd-backgrounds")
32 | .append(
33 | (bg = $("
")
34 | .addClass("tpd-background")
35 | .append(
36 | (bgc = $("
").addClass("tpd-background-content"))
37 | ))
38 | )
39 | )
40 | ))
41 | )
42 | .append((spinner = $("
").addClass("tpd-spinner")));
43 |
44 | // REQUIRED FOR IE < 8
45 | bg.css({ width: 999, height: 999, zoom: 1 });
46 |
47 | this._css = {
48 | border: parseFloat(bg.css("border-top-width")),
49 | radius: parseFloat(prefixedRadius ? bg.css(prefixedRadius) : 0),
50 | padding: parseFloat(tooltip._content.css("padding-top")),
51 | borderColor: bg.css("border-top-color"),
52 | //spacing: parseFloat(this.element.css('margin-top')),
53 | // borderOpacity: .5 // IE pre rgba fallback can be inserted here
54 | backgroundColor: bgc.css("background-color"),
55 | backgroundOpacity: bgc.css("opacity"),
56 | spinner: {
57 | dimensions: {
58 | width: spinner.innerWidth(),
59 | height: spinner.innerHeight(),
60 | },
61 | },
62 | };
63 |
64 | spinner.remove();
65 | frames.remove();
66 |
67 | this._side = Position.getSide(tooltip.options.position.tooltip) || "top";
68 |
69 | this._vars = {};
70 | },
71 |
72 | destroy: function () {
73 | if (!this.frames) return;
74 |
75 | // remove all the stems
76 | $.each(
77 | "top right bottom left".split(" "),
78 | function (_i, side) {
79 | if (this["stem_" + side]) this["stem_" + side].destroy();
80 | }.bind(this)
81 | );
82 |
83 | this.frames.remove();
84 | this.frames = null;
85 | },
86 |
87 | build: function () {
88 | // if already build exit
89 | if (this.frames) return;
90 |
91 | this.element.append((this.frames = $("
").addClass("tpd-frames")));
92 |
93 | $.each(
94 | "top right bottom left".split(" "),
95 | function (_i, side) {
96 | this.insertFrame(side);
97 | }.bind(this)
98 | );
99 |
100 | // insert a spinner, if we haven't already
101 | if (!this._spinner) {
102 | this.tooltip._tooltip.append(
103 | (this._spinner = $("
")
104 | .addClass("tpd-spinner")
105 | .hide()
106 | .append($("
").addClass("tpd-spinner-spin")))
107 | );
108 | }
109 | },
110 |
111 | _frame: (function () {
112 | var backgrounds;
113 |
114 | var frame = $("
")
115 | .addClass("tpd-frame")
116 | // background
117 | .append(
118 | (backgrounds = $("
")
119 | .addClass("tpd-backgrounds")
120 | .append($("
").addClass("tpd-background-shadow")))
121 | )
122 | .append(
123 | $("
")
124 | .addClass("tpd-shift-stem")
125 | .append(
126 | $("
").addClass(
127 | "tpd-shift-stem-side tpd-shift-stem-side-before"
128 | )
129 | )
130 | .append($("
").addClass("tpd-stem"))
131 | .append(
132 | $("
").addClass("tpd-shift-stem-side tpd-shift-stem-side-after")
133 | )
134 | );
135 |
136 | $.each(
137 | "top right bottom left".split(" "),
138 | function (_i, s) {
139 | backgrounds.append(
140 | $("
")
141 | .addClass("tpd-background-box tpd-background-box-" + s)
142 | .append(
143 | $("
")
144 | .addClass("tpd-background-box-shift")
145 | .append(
146 | $("
")
147 | .addClass("tpd-background-box-shift-further")
148 | .append(
149 | $("
")
150 | .addClass("tpd-background")
151 | .append($("
").addClass("tpd-background-title"))
152 | .append($("
").addClass("tpd-background-content"))
153 | )
154 | .append(
155 | $("
").addClass(
156 | "tpd-background tpd-background-loading"
157 | )
158 | )
159 | .append(
160 | $("
").addClass("tpd-background-border-hack").hide()
161 | )
162 | )
163 | )
164 | );
165 | }.bind(this)
166 | );
167 |
168 | return frame;
169 | })(),
170 |
171 | _getFrame: function (side) {
172 | var frame = this._frame.clone();
173 |
174 | // class
175 | frame.addClass("tpd-frame-" + side);
176 |
177 | // put border radius on shadow
178 | frame
179 | .find(".tpd-background-shadow")
180 | .css({ "border-radius": this._css.radius });
181 |
182 | // mark side on stem
183 | if (this.tooltip.options.stem) {
184 | frame.find(".tpd-stem").attr("data-stem-position", side);
185 | }
186 |
187 | // radius on background layers
188 | var innerBackgroundRadius = Math.max(
189 | this._css.radius - this._css.border,
190 | 0
191 | );
192 | frame.find(".tpd-background-title").css({
193 | "border-top-left-radius": innerBackgroundRadius,
194 | "border-top-right-radius": innerBackgroundRadius,
195 | });
196 | frame.find(".tpd-background-content").css({
197 | "border-bottom-left-radius": innerBackgroundRadius,
198 | "border-bottom-right-radius": innerBackgroundRadius,
199 | });
200 | frame.find(".tpd-background-loading").css({
201 | "border-radius": innerBackgroundRadius,
202 | });
203 |
204 | // adjust the dimensions of the shift sides
205 | var ss = { backgroundColor: this._css.borderColor };
206 | var orientation = Position.getOrientation(side),
207 | isHorizontal = orientation === "horizontal";
208 | ss[isHorizontal ? "height" : "width"] = this._css.border + "px";
209 | var inverse = {
210 | top: "bottom",
211 | bottom: "top",
212 | left: "right",
213 | right: "left",
214 | };
215 | ss[inverse[side]] = 0;
216 | frame.find(".tpd-shift-stem-side").css(ss);
217 |
218 | return frame;
219 | },
220 |
221 | insertFrame: function (side) {
222 | var frame = (this["frame_" + side] = this._getFrame(side));
223 | this.frames.append(frame);
224 |
225 | if (this.tooltip.options.stem) {
226 | var stem = frame.find(".tpd-stem");
227 | this["stem_" + side] = new Stem(stem, this, {});
228 | }
229 | },
230 |
231 | // Loading
232 | startLoading: function () {
233 | if (!this.tooltip.supportsLoading) return;
234 | this.build(); // make sure the tooltip is build
235 |
236 | // resize to the dimensions of the spinner the first time a tooltip is shown
237 | if (!this._spinner && !this.tooltip.is("resize-to-content")) {
238 | this.setDimensions(this._css.spinner.dimensions); // this creates ._spinner
239 | }
240 |
241 | if (this._spinner) {
242 | this._spinner.show();
243 | }
244 | },
245 |
246 | // the idea behind stopLoading is that dimensions are set right after calling this function
247 | // that's why we don't set the manually here
248 | stopLoading: function () {
249 | if (!this.tooltip.supportsLoading || !this._spinner) return;
250 | this.build(); // make sure the tooltip is build
251 |
252 | this._spinner.hide();
253 | },
254 |
255 | // updates the background of the currently active side
256 | updateBackground: function () {
257 | var frame = this._vars.frames[this._side];
258 |
259 | var backgroundDimensions = $.extend({}, frame.background.dimensions);
260 |
261 | if (this.tooltip.title && !this.tooltip.is("loading")) {
262 | // show both background children
263 | this.element
264 | .find(".tpd-background-title, .tpd-background-content")
265 | .show();
266 |
267 | // remove background color and replace it with transparent
268 | this.element
269 | .find(".tpd-background")
270 | .css({ "background-color": "transparent" });
271 |
272 | var contentDimensions = $.extend({}, backgroundDimensions);
273 | var innerBackgroundRadius = Math.max(
274 | this._css.radius - this._css.border,
275 | 0
276 | );
277 | var contentRadius = {
278 | "border-top-left-radius": innerBackgroundRadius,
279 | "border-top-right-radius": innerBackgroundRadius,
280 | "border-bottom-left-radius": innerBackgroundRadius,
281 | "border-bottom-right-radius": innerBackgroundRadius,
282 | };
283 |
284 | // measure the title
285 | var visible = new Visible(this.tooltip._tooltip);
286 |
287 | var titleHeight = this.tooltip._titleWrapper.innerHeight(); // without margins
288 |
289 | contentDimensions.height -= titleHeight;
290 |
291 | // set all title dimensions
292 | this.element.find(".tpd-background-title").css({
293 | height: titleHeight,
294 | width: backgroundDimensions.width,
295 | });
296 |
297 | // remove radius at the top
298 | contentRadius["border-top-left-radius"] = 0;
299 | contentRadius["border-top-right-radius"] = 0;
300 |
301 | visible.restore();
302 |
303 | // set all content dimensions
304 | // set correct radius
305 | this.element
306 | .find(".tpd-background-content")
307 | .css(contentDimensions)
308 | .css(contentRadius);
309 |
310 | // loading indicator
311 | this.element.find(".tpd-background-loading").css({
312 | "background-color": this._css.backgroundColor,
313 | });
314 | } else {
315 | // no title or close button creates a bar at the top
316 | // set background color only for better px handling in the corners
317 | // show both background children
318 | this.element
319 | .find(".tpd-background-title, .tpd-background-content")
320 | .hide();
321 |
322 | this.element
323 | .find(".tpd-background")
324 | .css({ "background-color": this._css.backgroundColor });
325 | }
326 |
327 | // border fix, required as a workaround for the following bugs:
328 | // https://bugzilla.mozilla.org/show_bug.cgi?id=929979
329 | // https://code.google.com/p/chromium/issues/detail?id=320330
330 | if (this._css.border) {
331 | this.element
332 | .find(".tpd-background")
333 | .css({ "border-color": "transparent" });
334 |
335 | this.element
336 | .find(".tpd-background-border-hack")
337 | // scaled
338 | .css({
339 | width: backgroundDimensions.width,
340 | height: backgroundDimensions.height,
341 | "border-radius": this._css.radius,
342 | "border-width": this._css.border,
343 | "border-color": this._css.borderColor,
344 | })
345 | .show();
346 | }
347 | },
348 |
349 | // update dimensions of the currently active side
350 | // background + stem
351 | paint: function () {
352 | // don't update if we've already rendered the dimensions at current stem position
353 | if (
354 | this._paintedDimensions &&
355 | this._paintedDimensions.width === this._dimensions.width &&
356 | this._paintedDimensions.height === this._dimensions.height &&
357 | this._paintedStemPosition === this._stemPosition
358 | ) {
359 | return;
360 | }
361 |
362 | // store these to prevent future updates at the same dimensions
363 | this._paintedDimensions = this._dimensions;
364 | this._paintedStemPosition = this._stemPosition;
365 |
366 | // visible side, hide others
367 | this.element
368 | .removeClass(
369 | "tpd-visible-frame-top tpd-visible-frame-bottom tpd-visible-frame-left tpd-visible-frame-right"
370 | )
371 | .addClass("tpd-visible-frame-" + this._side);
372 |
373 | var frame = this._vars.frames[this._side];
374 |
375 | // set dimensions
376 | var backgroundDimensions = $.extend({}, frame.background.dimensions);
377 | this.element.find(".tpd-background").css(backgroundDimensions);
378 | this.element.find(".tpd-background-shadow").css({
379 | width: backgroundDimensions.width + 2 * this._css.border,
380 | height: backgroundDimensions.height + 2 * this._css.border,
381 | });
382 |
383 | // update background to the correct display method
384 | this.updateBackground();
385 |
386 | this.element
387 | .find(".tpd-background-box-shift, .tpd-background-box-shift-further")
388 | .removeAttr("style");
389 |
390 | // dimensions of the skin
391 | this.element
392 | .add(this.frames)
393 | // and the tooltip
394 | .add(this.tooltip._tooltip)
395 | .css(frame.dimensions);
396 |
397 | // resize every frame
398 | var name = this._side,
399 | value = this._vars.frames[name];
400 | var f = this.element.find(".tpd-frame-" + this._side),
401 | fdimensions = this._vars.frames[name].dimensions;
402 |
403 | f.css(fdimensions);
404 |
405 | // background
406 | f.find(".tpd-backgrounds").css(
407 | $.extend({}, value.background.position, {
408 | width: fdimensions.width - value.background.position.left,
409 | height: fdimensions.height - value.background.position.top,
410 | })
411 | );
412 |
413 | // find the position of this frame
414 | // adjust the backgrounds
415 | var orientation = Position.getOrientation(name);
416 |
417 | // no stem only shows the top frame (using CSS)
418 | // with a stem we have to make adjustments
419 | if (this.tooltip.options.stem) {
420 | // position the shiftstem
421 | f.find(".tpd-shift-stem").css(
422 | $.extend({}, value.shift.dimensions, value.shift.position)
423 | );
424 |
425 | if (orientation === "vertical") {
426 | // left or right
427 | // top or bottom
428 | // make top/bottom side small
429 | var smallBoxes = f.find(
430 | ".tpd-background-box-top, .tpd-background-box-bottom"
431 | );
432 | smallBoxes.css({
433 | height: this._vars.cut,
434 | width: this._css.border,
435 | });
436 |
437 | // align the bottom side with the bottom
438 | f.find(".tpd-background-box-bottom")
439 | .css({
440 | top: value.dimensions.height - this._vars.cut,
441 | })
442 | // shift right side back
443 | .find(".tpd-background-box-shift")
444 | .css({
445 | "margin-top": -1 * value.dimensions.height + this._vars.cut,
446 | });
447 |
448 | // both sides should now be moved left or right depending on the current side
449 | var moveSmallBy =
450 | name === "right"
451 | ? value.dimensions.width - value.stemPx - this._css.border
452 | : 0;
453 | smallBoxes
454 | .css({
455 | left: moveSmallBy,
456 | })
457 | .find(".tpd-background-box-shift")
458 | .css({
459 | // inverse of the above
460 | "margin-left": -1 * moveSmallBy,
461 | });
462 |
463 | // hide the background that will be replaced by the stemshift when we have a stem
464 | f.find(
465 | ".tpd-background-box-" + (name == "left" ? "left" : "right")
466 | ).hide();
467 |
468 | // resize the other one
469 | if (name === "right") {
470 | // top can be resized to height - border
471 | f.find(".tpd-background-box-left").css({
472 | width: value.dimensions.width - value.stemPx - this._css.border,
473 | });
474 | } else {
475 | f.find(".tpd-background-box-right")
476 | .css({
477 | "margin-left": this._css.border, //,
478 | //height: (value.dimensions.height - value.stemPx - this._vars.border) + 'px'
479 | })
480 | .find(".tpd-background-box-shift")
481 | .css({
482 | "margin-left": -1 * this._css.border,
483 | });
484 | }
485 |
486 | // left or right should be shifted to the center
487 | // depending on which side is used
488 | var smallBox = f.find(".tpd-background-box-" + this._side);
489 | smallBox.css({
490 | height: value.dimensions.height - 2 * this._vars.cut, // resize
491 | "margin-top": this._vars.cut,
492 | });
493 | smallBox.find(".tpd-background-box-shift").css({
494 | "margin-top": -1 * this._vars.cut,
495 | });
496 | } else {
497 | // top or bottom
498 | // make left and right side small
499 | var smallBoxes = f.find(
500 | ".tpd-background-box-left, .tpd-background-box-right"
501 | );
502 | smallBoxes.css({
503 | width: this._vars.cut,
504 | height: this._css.border,
505 | });
506 |
507 | // align the right side with the right
508 | f.find(".tpd-background-box-right")
509 | .css({
510 | left: value.dimensions.width - this._vars.cut,
511 | })
512 | // shift right side back
513 | .find(".tpd-background-box-shift")
514 | .css({
515 | "margin-left": -1 * value.dimensions.width + this._vars.cut,
516 | });
517 |
518 | // both sides should now be moved up or down depending on the current side
519 | var moveSmallBy =
520 | name === "bottom"
521 | ? value.dimensions.height - value.stemPx - this._css.border
522 | : 0;
523 | smallBoxes
524 | .css({
525 | top: moveSmallBy,
526 | })
527 | .find(".tpd-background-box-shift")
528 | .css({
529 | // inverse of the above
530 | "margin-top": -1 * moveSmallBy,
531 | });
532 |
533 | // hide the background that will be replaced by the stemshift
534 | f.find(
535 | ".tpd-background-box-" + (name === "top" ? "top" : "bottom")
536 | ).hide();
537 |
538 | // resize the other one
539 | if (name === "bottom") {
540 | // top can be resized to height - border
541 | f.find(".tpd-background-box-top").css({
542 | height: value.dimensions.height - value.stemPx - this._css.border,
543 | });
544 | } else {
545 | f.find(".tpd-background-box-bottom")
546 | .css({
547 | "margin-top": this._css.border,
548 | })
549 | .find(".tpd-background-box-shift")
550 | .css({
551 | "margin-top": -1 * this._css.border,
552 | });
553 | }
554 |
555 | // top or bottom should be shifted to the center
556 | // depending on which side is used
557 | var smallBox = f.find(".tpd-background-box-" + this._side);
558 | smallBox.css({
559 | width: value.dimensions.width - 2 * this._vars.cut,
560 | "margin-left": this._vars.cut,
561 | });
562 | smallBox.find(".tpd-background-box-shift").css({
563 | "margin-left": -1 * this._vars.cut,
564 | });
565 | }
566 | }
567 |
568 | // position the loader
569 | var fb = frame.background,
570 | fbp = fb.position,
571 | fbd = fb.dimensions;
572 | this._spinner.css({
573 | top:
574 | fbp.top +
575 | this._css.border +
576 | (fbd.height * 0.5 - this._css.spinner.dimensions.height * 0.5),
577 | left:
578 | fbp.left +
579 | this._css.border +
580 | (fbd.width * 0.5 - this._css.spinner.dimensions.width * 0.5),
581 | });
582 | },
583 |
584 | getVars: function () {
585 | var padding = this._css.padding,
586 | radius = this._css.radius,
587 | border = this._css.border;
588 |
589 | var maxStemHeight = this._vars.maxStemHeight || 0;
590 | var dimensions = $.extend({}, this._dimensions || {});
591 | var vars = {
592 | frames: {},
593 | dimensions: dimensions,
594 | maxStemHeight: maxStemHeight,
595 | };
596 |
597 | // set the cut
598 | vars.cut = Math.max(this._css.border, this._css.radius) || 0;
599 |
600 | var stemDimensions = { width: 0, height: 0 };
601 | var stemOffset = 0;
602 | var stemPx = 0;
603 |
604 | if (this.tooltip.options.stem) {
605 | stemDimensions = this.stem_top.getMath().dimensions.outside;
606 | stemOffset = this.stem_top._css.offset;
607 | stemPx = Math.max(stemDimensions.height - this._css.border, 0); // the height we assume the stem is should never be negative
608 | }
609 |
610 | // store for later use
611 | vars.stemDimensions = stemDimensions;
612 | vars.stemOffset = stemOffset;
613 |
614 | // positition the background and resize the outer frame
615 | $.each(
616 | "top right bottom left".split(" "),
617 | function (_i, side) {
618 | var orientation = Position.getOrientation(side),
619 | isLR = orientation === "vertical";
620 |
621 | var frameDimensions = {
622 | width: dimensions.width + 2 * border,
623 | height: dimensions.height + 2 * border,
624 | };
625 |
626 | var shiftWidth =
627 | frameDimensions[isLR ? "height" : "width"] - 2 * vars.cut;
628 |
629 | var frame = {
630 | dimensions: frameDimensions,
631 | stemPx: stemPx,
632 | position: { top: 0, left: 0 },
633 | background: {
634 | dimensions: $.extend({}, dimensions),
635 | position: { top: 0, left: 0 },
636 | },
637 | };
638 | vars.frames[side] = frame;
639 |
640 | // adjust width or height of frame based on orientation
641 | frame.dimensions[isLR ? "width" : "height"] += stemPx;
642 |
643 | if (side === "top" || side === "left") {
644 | frame.background.position[side] += stemPx;
645 | }
646 |
647 | $.extend(frame, {
648 | shift: {
649 | position: { top: 0, left: 0 },
650 | dimensions: {
651 | width: isLR ? stemDimensions.height : shiftWidth,
652 | height: isLR ? shiftWidth : stemDimensions.height,
653 | },
654 | },
655 | });
656 |
657 | switch (side) {
658 | case "top":
659 | case "bottom":
660 | frame.shift.position.left += vars.cut;
661 |
662 | if (side === "bottom") {
663 | frame.shift.position.top +=
664 | frameDimensions.height - border - stemPx;
665 | }
666 | break;
667 | case "left":
668 | case "right":
669 | frame.shift.position.top += vars.cut;
670 |
671 | if (side === "right") {
672 | frame.shift.position.left +=
673 | frameDimensions.width - border - stemPx;
674 | }
675 | break;
676 | }
677 | }.bind(this)
678 | );
679 |
680 | // add connections
681 | vars.connections = {};
682 | $.each(
683 | Position.positions,
684 | function (_i, position) {
685 | vars.connections[position] = this.getConnectionLayout(position, vars);
686 | }.bind(this)
687 | );
688 |
689 | return vars;
690 | },
691 |
692 | setDimensions: function (dimensions) {
693 | this.build();
694 |
695 | // don't update if nothing changed
696 | var d = this._dimensions;
697 | if (d && d.width === dimensions.width && d.height === dimensions.height) {
698 | return;
699 | }
700 |
701 | this._dimensions = dimensions;
702 | this._vars = this.getVars();
703 | },
704 |
705 | setSide: function (side) {
706 | this._side = side;
707 | this._vars = this.getVars();
708 | },
709 |
710 | // gets position and offset of the given stem
711 | getConnectionLayout: function (position, vars) {
712 | var side = Position.getSide(position),
713 | orientation = Position.getOrientation(position),
714 | dimensions = vars.dimensions,
715 | cut = vars.cut; // where the stem starts
716 |
717 | var stem = this["stem_" + side],
718 | stemOffset = vars.stemOffset,
719 | stemWidth = this.tooltip.options.stem
720 | ? stem.getMath().dimensions.outside.width
721 | : 0,
722 | stemMiddleFromSide = cut + stemOffset + stemWidth * 0.5;
723 |
724 | // at the end of this function we should know how much the stem is able to shift
725 | var layout = {
726 | stem: {},
727 | };
728 | var move = {
729 | left: 0,
730 | right: 0,
731 | up: 0,
732 | down: 0,
733 | };
734 |
735 | var stemConnection = { top: 0, left: 0 },
736 | connection = { top: 0, left: 0 };
737 |
738 | var frame = vars.frames[side],
739 | stemMiddleFromSide = 0;
740 |
741 | // top/bottom
742 | if (orientation == "horizontal") {
743 | var width = frame.dimensions.width;
744 |
745 | if (this.tooltip.options.stem) {
746 | width = frame.shift.dimensions.width;
747 |
748 | // if there's not enough width for twice the stemOffset, calculate what is available, divide the width
749 | if (width - stemWidth < 2 * stemOffset) {
750 | stemOffset = Math.floor((width - stemWidth) * 0.5) || 0;
751 | }
752 |
753 | stemMiddleFromSide = cut + stemOffset + stemWidth * 0.5;
754 | }
755 |
756 | var availableWidth = width - 2 * stemOffset;
757 |
758 | var split = Position.split(position);
759 | var left = stemOffset;
760 | switch (split[2]) {
761 | case "left":
762 | move.right = availableWidth - stemWidth;
763 |
764 | stemConnection.left = stemMiddleFromSide;
765 | break;
766 | case "middle":
767 | left += Math.round(availableWidth * 0.5 - stemWidth * 0.5);
768 |
769 | move.left = left - stemOffset;
770 | move.right = left - stemOffset;
771 |
772 | stemConnection.left = connection.left = Math.round(
773 | frame.dimensions.width * 0.5
774 | );
775 | //connection.left = stemConnection.left;
776 | break;
777 | case "right":
778 | left += availableWidth - stemWidth;
779 |
780 | move.left = availableWidth - stemWidth;
781 |
782 | stemConnection.left = frame.dimensions.width - stemMiddleFromSide;
783 | connection.left = frame.dimensions.width;
784 | break;
785 | }
786 |
787 | // if we're working with the bottom stems we have to add the height to the connection
788 | if (split[1] === "bottom") {
789 | stemConnection.top += frame.dimensions.height;
790 | connection.top += frame.dimensions.height;
791 | }
792 |
793 | $.extend(layout.stem, {
794 | position: { left: left },
795 | before: { width: left },
796 | after: {
797 | left: left + stemWidth,
798 | //right: 0, // seems to work better in Chrome (subpixel bug)
799 | // but it fails in oldIE, se we add overlap to compensate
800 | width: width - left - stemWidth + 1,
801 | },
802 | });
803 | } else {
804 | // we are dealing with height
805 | var height = frame.dimensions.height;
806 |
807 | if (this.tooltip.options.stem) {
808 | height = frame.shift.dimensions.height;
809 |
810 | if (height - stemWidth < 2 * stemOffset) {
811 | stemOffset = Math.floor((height - stemWidth) * 0.5) || 0;
812 | }
813 |
814 | stemMiddleFromSide = cut + stemOffset + stemWidth * 0.5;
815 | }
816 |
817 | var availableHeight = height - 2 * stemOffset;
818 |
819 | var split = Position.split(position);
820 | var top = stemOffset;
821 | switch (split[2]) {
822 | case "top":
823 | move.down = availableHeight - stemWidth;
824 |
825 | stemConnection.top = stemMiddleFromSide;
826 | break;
827 | case "middle":
828 | top += Math.round(availableHeight * 0.5 - stemWidth * 0.5);
829 |
830 | move.up = top - stemOffset;
831 | move.down = top - stemOffset;
832 |
833 | stemConnection.top = connection.top = Math.round(
834 | frame.dimensions.height * 0.5
835 | );
836 | break;
837 | case "bottom":
838 | top += availableHeight - stemWidth;
839 |
840 | move.up = availableHeight - stemWidth;
841 |
842 | stemConnection.top = frame.dimensions.height - stemMiddleFromSide;
843 | connection.top = frame.dimensions.height;
844 | break;
845 | }
846 |
847 | // if we're working with the right stems we have to add the height to the connection
848 | if (split[1] === "right") {
849 | stemConnection.left += frame.dimensions.width;
850 | connection.left += frame.dimensions.width;
851 | }
852 |
853 | $.extend(layout.stem, {
854 | position: { top: top },
855 | before: { height: top },
856 | after: {
857 | top: top + stemWidth,
858 | height: height - top - stemWidth + 1,
859 | },
860 | });
861 | }
862 |
863 | // store movement and connection
864 | layout.move = move;
865 | layout.stem.connection = stemConnection;
866 | layout.connection = connection;
867 |
868 | return layout;
869 | },
870 |
871 | // sets the stem as one of the available 12 positions
872 | // we also need to call this function without a stem because it sets
873 | // connections
874 | setStemPosition: function (stemPosition, shift) {
875 | if (this._stemPosition !== stemPosition) {
876 | this._stemPosition = stemPosition;
877 | var side = Position.getSide(stemPosition);
878 | this.setSide(side);
879 | }
880 |
881 | // actual positioning
882 | if (this.tooltip.options.stem) {
883 | this.setStemShift(stemPosition, shift);
884 | }
885 | },
886 |
887 | setStemShift: function (stemPosition, shift) {
888 | var _shift = this._shift,
889 | _dimensions = this._dimensions;
890 | // return if we have the same shift on the same dimensions
891 | if (
892 | _shift &&
893 | _shift.stemPosition === stemPosition &&
894 | _shift.shift.x === shift.x &&
895 | _shift.shift.y === shift.y &&
896 | _dimensions &&
897 | _shift.dimensions.width === _dimensions.width &&
898 | _shift.dimensions.height === _dimensions.height
899 | ) {
900 | return;
901 | }
902 | this._shift = {
903 | stemPosition: stemPosition,
904 | shift: shift,
905 | dimensions: _dimensions,
906 | };
907 |
908 | var side = Position.getSide(stemPosition),
909 | xy = { horizontal: "x", vertical: "y" }[
910 | Position.getOrientation(stemPosition)
911 | ],
912 | leftWidth = {
913 | x: { left: "left", width: "width" },
914 | y: { left: "top", width: "height" },
915 | }[xy],
916 | stem = this["stem_" + side],
917 | layout = deepExtend({}, this._vars.connections[stemPosition].stem);
918 |
919 | // only use offset in the orientation of this position
920 | if (shift && shift[xy] !== 0) {
921 | layout.before[leftWidth["width"]] += shift[xy];
922 | layout.position[leftWidth["left"]] += shift[xy];
923 | layout.after[leftWidth["left"]] += shift[xy];
924 | layout.after[leftWidth["width"]] -= shift[xy];
925 | }
926 |
927 | // actual positioning
928 | stem.element.css(layout.position);
929 | stem.element.siblings(".tpd-shift-stem-side-before").css(layout.before);
930 | stem.element.siblings(".tpd-shift-stem-side-after").css(layout.after);
931 | },
932 | });
933 |
--------------------------------------------------------------------------------
/src/js/skins.js:
--------------------------------------------------------------------------------
1 | Tipped.Skins = {
2 | // base skin, don't modify! (create custom skins in a separate file)
3 | base: {
4 | afterUpdate: false,
5 | ajax: {},
6 | cache: true,
7 | container: false,
8 | containment: {
9 | selector: "viewport",
10 | padding: 5,
11 | },
12 | close: false,
13 | detach: true,
14 | fadeIn: 200,
15 | fadeOut: 200,
16 | showDelay: 75,
17 | hideDelay: 25,
18 | hideAfter: false,
19 | hideOn: { element: "mouseleave" },
20 | hideOthers: false,
21 | position: "top",
22 | inline: false,
23 | offset: { x: 0, y: 0 },
24 | onHide: false,
25 | onShow: false,
26 | padding: true,
27 | radius: true,
28 | shadow: true,
29 | showOn: { element: "mousemove" },
30 | size: "medium",
31 | spinner: true,
32 | stem: true,
33 | target: "element",
34 | voila: true,
35 | },
36 |
37 | // Every other skin inherits from this one
38 | reset: {
39 | ajax: false,
40 | hideOn: {
41 | element: "mouseleave",
42 | tooltip: "mouseleave",
43 | },
44 | showOn: {
45 | element: "mouseenter",
46 | tooltip: "mouseenter",
47 | },
48 | },
49 | };
50 |
51 | $.each(
52 | "dark light gray red green blue lightyellow lightblue lightpink".split(" "),
53 | function (i, s) {
54 | Tipped.Skins[s] = {};
55 | }
56 | );
57 |
--------------------------------------------------------------------------------
/src/js/stem.js:
--------------------------------------------------------------------------------
1 | function Stem() {
2 | this.initialize.apply(this, _slice.call(arguments));
3 | }
4 |
5 | $.extend(Stem.prototype, {
6 | initialize: function (element, skin) {
7 | this.element = $(element);
8 | if (!this.element[0]) return;
9 |
10 | this.skin = skin;
11 |
12 | this.element.removeClass("tpd-stem-reset"); // for correct offset
13 | this._css = $.extend({}, skin._css, {
14 | width: this.element.innerWidth(),
15 | height: this.element.innerHeight(),
16 | offset: parseFloat(this.element.css("margin-left")), // side
17 | spacing: parseFloat(this.element.css("margin-top")),
18 | });
19 | this.element.addClass("tpd-stem-reset");
20 |
21 | this.options = $.extend({}, arguments[2] || {});
22 |
23 | this._position = this.element.attr("data-stem-position") || "top";
24 | this._m = 100; // multiplier, improves rendering when scaling everything down
25 |
26 | this.build();
27 | },
28 |
29 | destroy: function () {
30 | this.element.html("");
31 | },
32 |
33 | build: function () {
34 | this.destroy();
35 |
36 | // figure out low opacity based on the background color
37 | var backgroundColor = this._css.backgroundColor,
38 | alpha =
39 | backgroundColor.indexOf("rgba") > -1 &&
40 | parseFloat(backgroundColor.replace(/^.*,(.+)\)/, "$1")),
41 | hasLowOpacityTriangle = alpha && alpha < 1;
42 |
43 | // if the triangle doesn't have opacity or when we don't have to deal with a border
44 | // we can get away with a better way to draw the stem.
45 | // otherwise we need to draw the border as a seperate element, but that
46 | // can only happen on browsers with support for transforms
47 | this._useTransform = hasLowOpacityTriangle && Support.css.transform;
48 | if (!this._css.border) this._useTransform = false;
49 | this[(this._useTransform ? "build" : "buildNo") + "Transform"]();
50 | },
51 |
52 | buildTransform: function () {
53 | this.element.append(
54 | (this.spacer = $("
")
55 | .addClass("tpd-stem-spacer")
56 | .append(
57 | (this.downscale = $("
")
58 | .addClass("tpd-stem-downscale")
59 | .append(
60 | (this.transform = $("
")
61 | .addClass("tpd-stem-transform")
62 | .append(
63 | (this.first = $("
")
64 | .addClass("tpd-stem-side")
65 | .append(
66 | (this.border = $("
").addClass("tpd-stem-border"))
67 | )
68 | .append($("
").addClass("tpd-stem-border-corner"))
69 | .append($("
").addClass("tpd-stem-triangle")))
70 | ))
71 | ))
72 | ))
73 | );
74 | this.transform.append(
75 | (this.last = this.first.clone().addClass("tpd-stem-side-inversed"))
76 | );
77 | this.sides = this.first.add(this.last);
78 |
79 | var math = this.getMath(),
80 | md = math.dimensions,
81 | _m = this._m,
82 | _side = Position.getSide(this._position);
83 |
84 | //if (!math.enabled) return;
85 |
86 | this.element.find(".tpd-stem-spacer").css({
87 | width: _flip ? md.inside.height : md.inside.width,
88 | height: _flip ? md.inside.width : md.inside.height,
89 | });
90 | if (_side === "top" || _side === "left") {
91 | var _scss = {};
92 | if (_side === "top") {
93 | _scss.bottom = 0;
94 | _scss.top = "auto";
95 | } else if (_side === "left") {
96 | _scss.right = 0;
97 | _scss.left = "auto";
98 | }
99 |
100 | this.element.find(".tpd-stem-spacer").css(_scss);
101 | }
102 |
103 | this.transform.css({
104 | width: md.inside.width * _m,
105 | height: md.inside.height * _m,
106 | });
107 |
108 | // adjust the dimensions of the element to that of the
109 | var _transform = Support.css.prefixed("transform");
110 |
111 | // triangle
112 | var triangleStyle = {
113 | "background-color": "transparent",
114 | "border-bottom-color": this._css.backgroundColor,
115 | "border-left-width": md.inside.width * 0.5 * _m,
116 | "border-bottom-width": md.inside.height * _m,
117 | };
118 | triangleStyle[_transform] = "translate(" + math.border * _m + "px, 0)";
119 | this.element.find(".tpd-stem-triangle").css(triangleStyle);
120 |
121 | // border
122 | // first convert color to rgb + opacity
123 | // otherwise we'd be working with a border that overlays the background
124 | var borderColor = this._css.borderColor;
125 | alpha =
126 | borderColor.indexOf("rgba") > -1 &&
127 | parseFloat(borderColor.replace(/^.*,(.+)\)/, "$1"));
128 | if (alpha && alpha < 1) {
129 | // turn the borderColor into a color without alpha
130 | borderColor = (
131 | borderColor.substring(0, borderColor.lastIndexOf(",")) + ")"
132 | ).replace("rgba", "rgb");
133 | } else {
134 | alpha = 1;
135 | }
136 |
137 | var borderStyle = {
138 | "background-color": "transparent",
139 | "border-right-width": math.border * _m,
140 | width: math.border * _m,
141 | "margin-left": -2 * math.border * _m,
142 | "border-color": borderColor,
143 | opacity: alpha,
144 | };
145 | borderStyle[_transform] =
146 | "skew(" +
147 | math.skew +
148 | "deg) translate(" +
149 | math.border * _m +
150 | "px, " +
151 | -1 * this._css.border * _m +
152 | "px)";
153 | this.element.find(".tpd-stem-border").css(borderStyle);
154 |
155 | var borderColor = this._css.borderColor;
156 | alpha =
157 | borderColor.indexOf("rgba") > -1 &&
158 | parseFloat(borderColor.replace(/^.*,(.+)\)/, "$1"));
159 | if (alpha && alpha < 1) {
160 | // turn the borderColor into a color without alpha
161 | borderColor = (
162 | borderColor.substring(0, borderColor.lastIndexOf(",")) + ")"
163 | ).replace("rgba", "rgb");
164 | } else {
165 | alpha = 1;
166 | }
167 |
168 | var borderCornerStyle = {
169 | width: math.border * _m,
170 | "border-right-width": math.border * _m,
171 | "border-right-color": borderColor,
172 | background: borderColor,
173 | opacity: alpha,
174 | // setting opacity here causes a flicker in firefox, it's set in css now
175 | // 'opacity': this._css.borderOpacity,
176 | "margin-left": -2 * math.border * _m,
177 | };
178 | borderCornerStyle[_transform] =
179 | "skew(" +
180 | math.skew +
181 | "deg) translate(" +
182 | math.border * _m +
183 | "px, " +
184 | (md.inside.height - this._css.border) * _m +
185 | "px)";
186 |
187 | this.element.find(".tpd-stem-border-corner").css(borderCornerStyle);
188 |
189 | // measurements are done, now flip things if needed
190 | this.setPosition(this._position);
191 |
192 | // now downscale to improve subpixel rendering
193 | if (_m > 1) {
194 | var t = {};
195 | t[_transform] = "scale(" + 1 / _m + "," + 1 / _m + ")";
196 | this.downscale.css(t);
197 | }
198 | // switch around the visible dimensions if needed
199 | var _flip = /^(left|right)$/.test(this._position);
200 |
201 | if (!this._css.border) {
202 | this.element.find(".tpd-stem-border, .tpd-stem-border-corner").hide();
203 | }
204 |
205 | this.element.css({
206 | width: _flip ? md.outside.height : md.outside.width,
207 | height: _flip ? md.outside.width : md.outside.height,
208 | });
209 | },
210 |
211 | buildNoTransform: function () {
212 | this.element.append(
213 | (this.spacer = $("
")
214 | .addClass("tpd-stem-spacer")
215 | .append(
216 | $("
")
217 | .addClass("tpd-stem-notransform")
218 | .append(
219 | $("
")
220 | .addClass("tpd-stem-border")
221 | .append($("
").addClass("tpd-stem-border-corner"))
222 | .append(
223 | $("
")
224 | .addClass("tpd-stem-border-center-offset")
225 | .append(
226 | $("
")
227 | .addClass("tpd-stem-border-center-offset-inverse")
228 | .append($("
").addClass("tpd-stem-border-center"))
229 | )
230 | )
231 | )
232 | .append($("
").addClass("tpd-stem-triangle"))
233 | ))
234 | );
235 |
236 | var math = this.getMath(),
237 | md = math.dimensions;
238 |
239 | var _flip = /^(left|right)$/.test(this._position),
240 | _bottom = /^(bottom)$/.test(this._position),
241 | _right = /^(right)$/.test(this._position),
242 | _side = Position.getSide(this._position);
243 |
244 | this.element.css({
245 | width: _flip ? md.outside.height : md.outside.width,
246 | height: _flip ? md.outside.width : md.outside.height,
247 | });
248 |
249 | // handle spacer
250 | this.element
251 | .find(".tpd-stem-notransform")
252 | .add(this.element.find(".tpd-stem-spacer"))
253 | .css({
254 | width: _flip ? md.inside.height : md.inside.width,
255 | height: _flip ? md.inside.width : md.inside.height,
256 | });
257 | if (_side === "top" || _side === "left") {
258 | var _scss = {};
259 | if (_side === "top") {
260 | _scss.bottom = 0;
261 | _scss.top = "auto";
262 | } else if (_side === "left") {
263 | _scss.right = 0;
264 | _scss.left = "auto";
265 | }
266 |
267 | this.element.find(".tpd-stem-spacer").css(_scss);
268 | }
269 |
270 | // resets
271 | this.element.find(".tpd-stem-border").css({
272 | width: "100%",
273 | background: "transparent",
274 | });
275 |
276 | // == on bottom
277 | var borderCornerStyle = {
278 | opacity: 1,
279 | };
280 |
281 | borderCornerStyle[_flip ? "height" : "width"] = "100%";
282 | borderCornerStyle[_flip ? "width" : "height"] = this._css.border;
283 | borderCornerStyle[_bottom ? "top" : "bottom"] = 0;
284 |
285 | $.extend(borderCornerStyle, !_right ? { right: 0 } : { left: 0 });
286 |
287 | this.element.find(".tpd-stem-border-corner").css(borderCornerStyle);
288 |
289 | // border /\
290 | // top or bottom
291 | var borderStyle = {
292 | width: 0,
293 | "background-color": "transparent",
294 | opacity: 1,
295 | };
296 |
297 | var borderSideCSS = md.inside.width * 0.5 + "px solid transparent";
298 |
299 | var triangleStyle = { "background-color": "transparent" };
300 | var triangleSideCSS =
301 | md.inside.width * 0.5 - math.border + "px solid transparent";
302 |
303 | if (!_flip) {
304 | var shared = {
305 | "margin-left": -0.5 * md.inside.width,
306 | "border-left": borderSideCSS,
307 | "border-right": borderSideCSS,
308 | };
309 |
310 | // ==
311 | $.extend(borderStyle, shared);
312 | borderStyle[_bottom ? "border-top" : "border-bottom"] =
313 | md.inside.height + "px solid " + this._css.borderColor;
314 |
315 | // /\
316 | $.extend(triangleStyle, shared);
317 | triangleStyle[_bottom ? "border-top" : "border-bottom"] =
318 | md.inside.height + "px solid " + this._css.backgroundColor;
319 | triangleStyle[!_bottom ? "top" : "bottom"] = math.top;
320 | triangleStyle[_bottom ? "top" : "bottom"] = "auto";
321 |
322 | // add offset
323 | this.element
324 | .find(".tpd-stem-border-center-offset")
325 | .css({
326 | "margin-top": -1 * this._css.border * (_bottom ? -1 : 1),
327 | })
328 | .find(".tpd-stem-border-center-offset-inverse")
329 | .css({
330 | "margin-top": this._css.border * (_bottom ? -1 : 1),
331 | });
332 | } else {
333 | var shared = {
334 | left: "auto",
335 | top: "50%",
336 | "margin-top": -0.5 * md.inside.width,
337 | "border-top": borderSideCSS,
338 | "border-bottom": borderSideCSS,
339 | };
340 |
341 | // ==
342 | $.extend(borderStyle, shared);
343 | borderStyle[_right ? "right" : "left"] = 0;
344 | borderStyle[_right ? "border-left" : "border-right"] =
345 | md.inside.height + "px solid " + this._css.borderColor;
346 |
347 | // /\
348 | $.extend(triangleStyle, shared);
349 | triangleStyle[_right ? "border-left" : "border-right"] =
350 | md.inside.height + "px solid " + this._css.backgroundColor;
351 | triangleStyle[!_right ? "left" : "right"] = math.top;
352 | triangleStyle[_right ? "left" : "right"] = "auto";
353 |
354 | // add offset
355 | this.element
356 | .find(".tpd-stem-border-center-offset")
357 | .css({
358 | "margin-left": -1 * this._css.border * (_right ? -1 : 1),
359 | })
360 | .find(".tpd-stem-border-center-offset-inverse")
361 | .css({
362 | "margin-left": this._css.border * (_right ? -1 : 1),
363 | });
364 | }
365 |
366 | this.element.find(".tpd-stem-border-center").css(borderStyle);
367 | this.element
368 | .find(".tpd-stem-border-corner")
369 | .css({ "background-color": this._css.borderColor });
370 | this.element.find(".tpd-stem-triangle").css(triangleStyle);
371 |
372 | if (!this._css.border) {
373 | this.element.find(".tpd-stem-border").hide();
374 | }
375 | },
376 |
377 | setPosition: function (position) {
378 | this._position = position;
379 | this.transform.attr(
380 | "class",
381 | "tpd-stem-transform tpd-stem-transform-" + position
382 | );
383 | },
384 |
385 | getMath: function () {
386 | var height = this._css.height,
387 | width = this._css.width,
388 | border = this._css.border;
389 |
390 | // width should be divisible by 2
391 | // this fixes pixel bugs in the transform methods, so only do it there
392 | if (this._useTransform && !!(Math.floor(width) % 2)) {
393 | width = Math.max(Math.floor(width) - 1, 0);
394 | }
395 |
396 | // first increase the original dimensions so the triangle is that of the given css dimensions
397 | var corner_top = degrees(Math.atan((width * 0.5) / height)),
398 | corner_side = 90 - corner_top,
399 | side = border / Math.cos(((90 - corner_side) * Math.PI) / 180),
400 | top = border / Math.cos(((90 - corner_top) * Math.PI) / 180);
401 | var dimensions = {
402 | width: width + side * 2,
403 | height: height + top,
404 | };
405 |
406 | var cut = Math.max(border, this._css.radius);
407 |
408 | // adjust height and width
409 | height = dimensions.height;
410 | width = dimensions.width * 0.5;
411 |
412 | // calculate the rest
413 | var cA = degrees(Math.atan(height / width)),
414 | cB = 90 - cA,
415 | overstaand = border / Math.cos((cB * Math.PI) / 180);
416 |
417 | var angle = (Math.atan(height / width) * 180) / Math.PI,
418 | skew = -1 * (90 - angle),
419 | angleTop = 90 - angle,
420 | cornerWidth = border * Math.tan((angleTop * Math.PI) / 180);
421 |
422 | var top = border / Math.cos(((90 - angleTop) * Math.PI) / 180);
423 |
424 | // add spacing
425 | //dimensions.height += this._css.spacing;
426 | var inside = $.extend({}, dimensions),
427 | outside = $.extend({}, dimensions);
428 | outside.height += this._css.spacing;
429 |
430 | // IE11 and below have issues with rendering stems that
431 | // end up with floating point dimensions
432 | // ceil the outside height to fix this
433 | outside.height = Math.ceil(outside.height);
434 |
435 | // if the border * 2 is bigger than the width, we should disable the stem
436 | var enabled = true;
437 | if (border * 2 >= dimensions.width) {
438 | enabled = false;
439 | }
440 |
441 | return {
442 | enabled: enabled,
443 | outside: outside,
444 | dimensions: {
445 | inside: inside,
446 | outside: outside,
447 | },
448 | top: top,
449 | border: overstaand,
450 | skew: skew,
451 | corner: cornerWidth,
452 | };
453 | },
454 | });
455 |
--------------------------------------------------------------------------------
/src/js/tooltip.js:
--------------------------------------------------------------------------------
1 | function Tooltip() {
2 | this.initialize.apply(this, _slice.call(arguments));
3 | }
4 |
5 | $.extend(Tooltip.prototype, {
6 | supportsLoading: Support.css.transform && Support.css.animation,
7 |
8 | initialize: function (element, content) {
9 | this.element = element;
10 | if (!this.element) return;
11 |
12 | var options;
13 | if (
14 | typeof content === "object" &&
15 | !(
16 | _.isElement(content) ||
17 | _.isText(content) ||
18 | _.isDocumentFragment(content) ||
19 | content instanceof $
20 | )
21 | ) {
22 | options = content;
23 | content = null;
24 | } else {
25 | options = arguments[2] || {};
26 | }
27 |
28 | // append element options if data-tpd-options
29 | var dataOptions = $(element).data("tipped-options");
30 | if (dataOptions) {
31 | options = deepExtend(
32 | $.extend({}, options),
33 | eval("({" + dataOptions + "})")
34 | );
35 | }
36 |
37 | this.options = Options.create(options);
38 |
39 | // all the garbage goes in here
40 | this._cache = {
41 | dimensions: {
42 | width: 0,
43 | height: 0,
44 | },
45 | events: [],
46 | timers: {},
47 | layouts: {},
48 | is: {},
49 | fnCallFn: "",
50 | updatedTo: {},
51 | };
52 |
53 | // queues for effects
54 | this.queues = {
55 | showhide: $({}),
56 | };
57 |
58 | // title
59 | var title =
60 | $(element).attr("title") || $(element).data("tipped-restore-title");
61 |
62 | if (!content) {
63 | // grab the content off the attribute
64 | var dt = $(element).attr("data-tipped");
65 |
66 | if (dt) {
67 | content = dt;
68 | } else if (title) {
69 | content = title;
70 | }
71 |
72 | if (content) {
73 | // avoid scripts in title/data-tipped
74 | var SCRIPT_REGEX =
75 | /