diff options
| author | kujiu <kujiu@users.noreply.github.com> | 2018-06-22 21:22:21 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-06-22 21:22:21 +0200 |
| commit | 9de1bc0eef6f5bfaa2a8d745431caa361ae91548 (patch) | |
| tree | 342ddbf7fb2b7303606f864ff9f68cbf1bd8814e /addons/web/static | |
| parent | 864357203fc6222cc989b99a5e9f428cd53f413f (diff) | |
[IMP] Improve compatibility with screen readers (accessibility) (#24574)
Today, Odoo is really tricky to use without seeing the screen, it must be improved to be usable.
This PR forbid to use labels without a "for" attribute, add some title, rule and aria attributes in HTML. With that, Odoo will be fully usable with a screen reader.
* [IMP] Labels must have a for attribute. Improve accessibility.
* [IMP] Better error message when trying to read a missing cached value
* [FIX] Add some aria-label and title attributes for screen readers.
* [FIX] Template name is not included in the error message in case of SyntaxError in QWeb
* [FIX] Improve the Tour failed at step error message to be more explicit.
* [IMP] Add aria-labels
* [FIX] Add missing aria-label on failing test
* [IMP] aria-hidden means hidden. Fix all bad aria-hidden and hide aria-hidden for all.
* [IMP] Color names on kanban views and many2many tags
* [IMP] Add some checks on views for accessibility.
* [IMP] Add `alt` attribute on `img` tags.
* [IMP] Add aria-label and title on non-described icons
* [IMP] Add button role to widgets with btn class
* [IMP] Translate aria and formatted attributes.
* [IMP] Remove wrong aria-labelledby
* [IMP] Add menu role on dropdowns
* [IMP] Buttons must be focusable
* [IMP] Add aria attributes on progress bars
* [IMP] Improve accessibility of basic widgets
* [IMP] Change main layout to more semantic tags
* [IMP] Add menuitem role when missing
* [IMP] Remove wrong role='presentation'
* [IMP] Improve accessibility of tab panels
* [IMP] Add aria-invalid on invalid fields
* [IMP] Add aria-sort on ordered columns
* [IMP] Add role on alerts
* [IMP] Use dialog role, header, main and footer tags for modals
* [IMP] Add labels on o_status
* [IMP] Improve accessibility of kanban view with feeds and articles
* [IMP] Add alerts in case of new messages
* [IMP] Add widget, navigation or img role to aria-labelled items
Diffstat (limited to 'addons/web/static')
36 files changed, 2992 insertions, 735 deletions
diff --git a/addons/web/static/lib/fontawesome/css/font-awesome-suffix.css b/addons/web/static/lib/fontawesome/css/font-awesome-suffix.css new file mode 100644 index 00000000000..f5651cf8e02 --- /dev/null +++ b/addons/web/static/lib/fontawesome/css/font-awesome-suffix.css @@ -0,0 +1,2145 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * Suffix version by Odoo S.A. + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +/* FONT PATH + * -------------------------- */ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-suffix-glass:after { + content: "\f000"; +} +.fa-suffix-music:after { + content: "\f001"; +} +.fa-suffix-search:after { + content: "\f002"; +} +.fa-suffix-envelope-o:after { + content: "\f003"; +} +.fa-suffix-heart:after { + content: "\f004"; +} +.fa-suffix-star:after { + content: "\f005"; +} +.fa-suffix-star-o:after { + content: "\f006"; +} +.fa-suffix-user:after { + content: "\f007"; +} +.fa-suffix-film:after { + content: "\f008"; +} +.fa-suffix-th-large:after { + content: "\f009"; +} +.fa-suffix-th:after { + content: "\f00a"; +} +.fa-suffix-th-list:after { + content: "\f00b"; +} +.fa-suffix-check:after { + content: "\f00c"; +} +.fa-suffix-remove:after, +.fa-suffix-close:after, +.fa-suffix-times:after { + content: "\f00d"; +} +.fa-suffix-search-plus:after { + content: "\f00e"; +} +.fa-suffix-search-minus:after { + content: "\f010"; +} +.fa-suffix-power-off:after { + content: "\f011"; +} +.fa-suffix-signal:after { + content: "\f012"; +} +.fa-suffix-gear:after, +.fa-suffix-cog:after { + content: "\f013"; +} +.fa-suffix-trash-o:after { + content: "\f014"; +} +.fa-suffix-home:after { + content: "\f015"; +} +.fa-suffix-file-o:after { + content: "\f016"; +} +.fa-suffix-clock-o:after { + content: "\f017"; +} +.fa-suffix-road:after { + content: "\f018"; +} +.fa-suffix-download:after { + content: "\f019"; +} +.fa-suffix-arrow-circle-o-down:after { + content: "\f01a"; +} +.fa-suffix-arrow-circle-o-up:after { + content: "\f01b"; +} +.fa-suffix-inbox:after { + content: "\f01c"; +} +.fa-suffix-play-circle-o:after { + content: "\f01d"; +} +.fa-suffix-rotate-right:after, +.fa-suffix-repeat:after { + content: "\f01e"; +} +.fa-suffix-refresh:after { + content: "\f021"; +} +.fa-suffix-list-alt:after { + content: "\f022"; +} +.fa-suffix-lock:after { + content: "\f023"; +} +.fa-suffix-flag:after { + content: "\f024"; +} +.fa-suffix-headphones:after { + content: "\f025"; +} +.fa-suffix-volume-off:after { + content: "\f026"; +} +.fa-suffix-volume-down:after { + content: "\f027"; +} +.fa-suffix-volume-up:after { + content: "\f028"; +} +.fa-suffix-qrcode:after { + content: "\f029"; +} +.fa-suffix-barcode:after { + content: "\f02a"; +} +.fa-suffix-tag:after { + content: "\f02b"; +} +.fa-suffix-tags:after { + content: "\f02c"; +} +.fa-suffix-book:after { + content: "\f02d"; +} +.fa-suffix-bookmark:after { + content: "\f02e"; +} +.fa-suffix-print:after { + content: "\f02f"; +} +.fa-suffix-camera:after { + content: "\f030"; +} +.fa-suffix-font:after { + content: "\f031"; +} +.fa-suffix-bold:after { + content: "\f032"; +} +.fa-suffix-italic:after { + content: "\f033"; +} +.fa-suffix-text-height:after { + content: "\f034"; +} +.fa-suffix-text-width:after { + content: "\f035"; +} +.fa-suffix-align-left:after { + content: "\f036"; +} +.fa-suffix-align-center:after { + content: "\f037"; +} +.fa-suffix-align-right:after { + content: "\f038"; +} +.fa-suffix-align-justify:after { + content: "\f039"; +} +.fa-suffix-list:after { + content: "\f03a"; +} +.fa-suffix-dedent:after, +.fa-suffix-outdent:after { + content: "\f03b"; +} +.fa-suffix-indent:after { + content: "\f03c"; +} +.fa-suffix-video-camera:after { + content: "\f03d"; +} +.fa-suffix-photo:after, +.fa-suffix-image:after, +.fa-suffix-picture-o:after { + content: "\f03e"; +} +.fa-suffix-pencil:after { + content: "\f040"; +} +.fa-suffix-map-marker:after { + content: "\f041"; +} +.fa-suffix-adjust:after { + content: "\f042"; +} +.fa-suffix-tint:after { + content: "\f043"; +} +.fa-suffix-edit:after, +.fa-suffix-pencil-square-o:after { + content: "\f044"; +} +.fa-suffix-share-square-o:after { + content: "\f045"; +} +.fa-suffix-check-square-o:after { + content: "\f046"; +} +.fa-suffix-arrows:after { + content: "\f047"; +} +.fa-suffix-step-backward:after { + content: "\f048"; +} +.fa-suffix-fast-backward:after { + content: "\f049"; +} +.fa-suffix-backward:after { + content: "\f04a"; +} +.fa-suffix-play:after { + content: "\f04b"; +} +.fa-suffix-pause:after { + content: "\f04c"; +} +.fa-suffix-stop:after { + content: "\f04d"; +} +.fa-suffix-forward:after { + content: "\f04e"; +} +.fa-suffix-fast-forward:after { + content: "\f050"; +} +.fa-suffix-step-forward:after { + content: "\f051"; +} +.fa-suffix-eject:after { + content: "\f052"; +} +.fa-suffix-chevron-left:after { + content: "\f053"; +} +.fa-suffix-chevron-right:after { + content: "\f054"; +} +.fa-suffix-plus-circle:after { + content: "\f055"; +} +.fa-suffix-minus-circle:after { + content: "\f056"; +} +.fa-suffix-times-circle:after { + content: "\f057"; +} +.fa-suffix-check-circle:after { + content: "\f058"; +} +.fa-suffix-question-circle:after { + content: "\f059"; +} +.fa-suffix-info-circle:after { + content: "\f05a"; +} +.fa-suffix-crosshairs:after { + content: "\f05b"; +} +.fa-suffix-times-circle-o:after { + content: "\f05c"; +} +.fa-suffix-check-circle-o:after { + content: "\f05d"; +} +.fa-suffix-ban:after { + content: "\f05e"; +} +.fa-suffix-arrow-left:after { + content: "\f060"; +} +.fa-suffix-arrow-right:after { + content: "\f061"; +} +.fa-suffix-arrow-up:after { + content: "\f062"; +} +.fa-suffix-arrow-down:after { + content: "\f063"; +} +.fa-suffix-mail-forward:after, +.fa-suffix-share:after { + content: "\f064"; +} +.fa-suffix-expand:after { + content: "\f065"; +} +.fa-suffix-compress:after { + content: "\f066"; +} +.fa-suffix-plus:after { + content: "\f067"; +} +.fa-suffix-minus:after { + content: "\f068"; +} +.fa-suffix-asterisk:after { + content: "\f069"; +} +.fa-suffix-exclamation-circle:after { + content: "\f06a"; +} +.fa-suffix-gift:after { + content: "\f06b"; +} +.fa-suffix-leaf:after { + content: "\f06c"; +} +.fa-suffix-fire:after { + content: "\f06d"; +} +.fa-suffix-eye:after { + content: "\f06e"; +} +.fa-suffix-eye-slash:after { + content: "\f070"; +} +.fa-suffix-warning:after, +.fa-suffix-exclamation-triangle:after { + content: "\f071"; +} +.fa-suffix-plane:after { + content: "\f072"; +} +.fa-suffix-calendar:after { + content: "\f073"; +} +.fa-suffix-random:after { + content: "\f074"; +} +.fa-suffix-comment:after { + content: "\f075"; +} +.fa-suffix-magnet:after { + content: "\f076"; +} +.fa-suffix-chevron-up:after { + content: "\f077"; +} +.fa-suffix-chevron-down:after { + content: "\f078"; +} +.fa-suffix-retweet:after { + content: "\f079"; +} +.fa-suffix-shopping-cart:after { + content: "\f07a"; +} +.fa-suffix-folder:after { + content: "\f07b"; +} +.fa-suffix-folder-open:after { + content: "\f07c"; +} +.fa-suffix-arrows-v:after { + content: "\f07d"; +} +.fa-suffix-arrows-h:after { + content: "\f07e"; +} +.fa-suffix-bar-chart-o:after, +.fa-suffix-bar-chart:after { + content: "\f080"; +} +.fa-suffix-twitter-square:after { + content: "\f081"; +} +.fa-suffix-facebook-square:after { + content: "\f082"; +} +.fa-suffix-camera-retro:after { + content: "\f083"; +} +.fa-suffix-key:after { + content: "\f084"; +} +.fa-suffix-gears:after, +.fa-suffix-cogs:after { + content: "\f085"; +} +.fa-suffix-comments:after { + content: "\f086"; +} +.fa-suffix-thumbs-o-up:after { + content: "\f087"; +} +.fa-suffix-thumbs-o-down:after { + content: "\f088"; +} +.fa-suffix-star-half:after { + content: "\f089"; +} +.fa-suffix-heart-o:after { + content: "\f08a"; +} +.fa-suffix-sign-out:after { + content: "\f08b"; +} +.fa-suffix-linkedin-square:after { + content: "\f08c"; +} +.fa-suffix-thumb-tack:after { + content: "\f08d"; +} +.fa-suffix-external-link:after { + content: "\f08e"; +} +.fa-suffix-sign-in:after { + content: "\f090"; +} +.fa-suffix-trophy:after { + content: "\f091"; +} +.fa-suffix-github-square:after { + content: "\f092"; +} +.fa-suffix-upload:after { + content: "\f093"; +} +.fa-suffix-lemon-o:after { + content: "\f094"; +} +.fa-suffix-phone:after { + content: "\f095"; +} +.fa-suffix-square-o:after { + content: "\f096"; +} +.fa-suffix-bookmark-o:after { + content: "\f097"; +} +.fa-suffix-phone-square:after { + content: "\f098"; +} +.fa-suffix-twitter:after { + content: "\f099"; +} +.fa-suffix-facebook-f:after, +.fa-suffix-facebook:after { + content: "\f09a"; +} +.fa-suffix-github:after { + content: "\f09b"; +} +.fa-suffix-unlock:after { + content: "\f09c"; +} +.fa-suffix-credit-card:after { + content: "\f09d"; +} +.fa-suffix-feed:after, +.fa-suffix-rss:after { + content: "\f09e"; +} +.fa-suffix-hdd-o:after { + content: "\f0a0"; +} +.fa-suffix-bullhorn:after { + content: "\f0a1"; +} +.fa-suffix-bell:after { + content: "\f0f3"; +} +.fa-suffix-certificate:after { + content: "\f0a3"; +} +.fa-suffix-hand-o-right:after { + content: "\f0a4"; +} +.fa-suffix-hand-o-left:after { + content: "\f0a5"; +} +.fa-suffix-hand-o-up:after { + content: "\f0a6"; +} +.fa-suffix-hand-o-down:after { + content: "\f0a7"; +} +.fa-suffix-arrow-circle-left:after { + content: "\f0a8"; +} +.fa-suffix-arrow-circle-right:after { + content: "\f0a9"; +} +.fa-suffix-arrow-circle-up:after { + content: "\f0aa"; +} +.fa-suffix-arrow-circle-down:after { + content: "\f0ab"; +} +.fa-suffix-globe:after { + content: "\f0ac"; +} +.fa-suffix-wrench:after { + content: "\f0ad"; +} +.fa-suffix-tasks:after { + content: "\f0ae"; +} +.fa-suffix-filter:after { + content: "\f0b0"; +} +.fa-suffix-briefcase:after { + content: "\f0b1"; +} +.fa-suffix-arrows-alt:after { + content: "\f0b2"; +} +.fa-suffix-group:after, +.fa-suffix-users:after { + content: "\f0c0"; +} +.fa-suffix-chain:after, +.fa-suffix-link:after { + content: "\f0c1"; +} +.fa-suffix-cloud:after { + content: "\f0c2"; +} +.fa-suffix-flask:after { + content: "\f0c3"; +} +.fa-suffix-cut:after, +.fa-suffix-scissors:after { + content: "\f0c4"; +} +.fa-suffix-copy:after, +.fa-suffix-files-o:after { + content: "\f0c5"; +} +.fa-suffix-paperclip:after { + content: "\f0c6"; +} +.fa-suffix-save:after, +.fa-suffix-floppy-o:after { + content: "\f0c7"; +} +.fa-suffix-square:after { + content: "\f0c8"; +} +.fa-suffix-navicon:after, +.fa-suffix-reorder:after, +.fa-suffix-bars:after { + content: "\f0c9"; +} +.fa-suffix-list-ul:after { + content: "\f0ca"; +} +.fa-suffix-list-ol:after { + content: "\f0cb"; +} +.fa-suffix-strikethrough:after { + content: "\f0cc"; +} +.fa-suffix-underline:after { + content: "\f0cd"; +} +.fa-suffix-table:after { + content: "\f0ce"; +} +.fa-suffix-magic:after { + content: "\f0d0"; +} +.fa-suffix-truck:after { + content: "\f0d1"; +} +.fa-suffix-pinterest:after { + content: "\f0d2"; +} +.fa-suffix-pinterest-square:after { + content: "\f0d3"; +} +.fa-suffix-google-plus-square:after { + content: "\f0d4"; +} +.fa-suffix-google-plus:after { + content: "\f0d5"; +} +.fa-suffix-money:after { + content: "\f0d6"; +} +.fa-suffix-caret-down:after { + content: "\f0d7"; +} +.fa-suffix-caret-up:after { + content: "\f0d8"; +} +.fa-suffix-caret-left:after { + content: "\f0d9"; +} +.fa-suffix-caret-right:after { + content: "\f0da"; +} +.fa-suffix-columns:after { + content: "\f0db"; +} +.fa-suffix-unsorted:after, +.fa-suffix-sort:after { + content: "\f0dc"; +} +.fa-suffix-sort-down:after, +.fa-suffix-sort-desc:after { + content: "\f0dd"; +} +.fa-suffix-sort-up:after, +.fa-suffix-sort-asc:after { + content: "\f0de"; +} +.fa-suffix-envelope:after { + content: "\f0e0"; +} +.fa-suffix-linkedin:after { + content: "\f0e1"; +} +.fa-suffix-rotate-left:after, +.fa-suffix-undo:after { + content: "\f0e2"; +} +.fa-suffix-legal:after, +.fa-suffix-gavel:after { + content: "\f0e3"; +} +.fa-suffix-dashboard:after, +.fa-suffix-tachometer:after { + content: "\f0e4"; +} +.fa-suffix-comment-o:after { + content: "\f0e5"; +} +.fa-suffix-comments-o:after { + content: "\f0e6"; +} +.fa-suffix-flash:after, +.fa-suffix-bolt:after { + content: "\f0e7"; +} +.fa-suffix-sitemap:after { + content: "\f0e8"; +} +.fa-suffix-umbrella:after { + content: "\f0e9"; +} +.fa-suffix-paste:after, +.fa-suffix-clipboard:after { + content: "\f0ea"; +} +.fa-suffix-lightbulb-o:after { + content: "\f0eb"; +} +.fa-suffix-exchange:after { + content: "\f0ec"; +} +.fa-suffix-cloud-download:after { + content: "\f0ed"; +} +.fa-suffix-cloud-upload:after { + content: "\f0ee"; +} +.fa-suffix-user-md:after { + content: "\f0f0"; +} +.fa-suffix-stethoscope:after { + content: "\f0f1"; +} +.fa-suffix-suitcase:after { + content: "\f0f2"; +} +.fa-suffix-bell-o:after { + content: "\f0a2"; +} +.fa-suffix-coffee:after { + content: "\f0f4"; +} +.fa-suffix-cutlery:after { + content: "\f0f5"; +} +.fa-suffix-file-text-o:after { + content: "\f0f6"; +} +.fa-suffix-building-o:after { + content: "\f0f7"; +} +.fa-suffix-hospital-o:after { + content: "\f0f8"; +} +.fa-suffix-ambulance:after { + content: "\f0f9"; +} +.fa-suffix-medkit:after { + content: "\f0fa"; +} +.fa-suffix-fighter-jet:after { + content: "\f0fb"; +} +.fa-suffix-beer:after { + content: "\f0fc"; +} +.fa-suffix-h-square:after { + content: "\f0fd"; +} +.fa-suffix-plus-square:after { + content: "\f0fe"; +} +.fa-suffix-angle-double-left:after { + content: "\f100"; +} +.fa-suffix-angle-double-right:after { + content: "\f101"; +} +.fa-suffix-angle-double-up:after { + content: "\f102"; +} +.fa-suffix-angle-double-down:after { + content: "\f103"; +} +.fa-suffix-angle-left:after { + content: "\f104"; +} +.fa-suffix-angle-right:after { + content: "\f105"; +} +.fa-suffix-angle-up:after { + content: "\f106"; +} +.fa-suffix-angle-down:after { + content: "\f107"; +} +.fa-suffix-desktop:after { + content: "\f108"; +} +.fa-suffix-laptop:after { + content: "\f109"; +} +.fa-suffix-tablet:after { + content: "\f10a"; +} +.fa-suffix-mobile-phone:after, +.fa-suffix-mobile:after { + content: "\f10b"; +} +.fa-suffix-circle-o:after { + content: "\f10c"; +} +.fa-suffix-quote-left:after { + content: "\f10d"; +} +.fa-suffix-quote-right:after { + content: "\f10e"; +} +.fa-suffix-spinner:after { + content: "\f110"; +} +.fa-suffix-circle:after { + content: "\f111"; +} +.fa-suffix-mail-reply:after, +.fa-suffix-reply:after { + content: "\f112"; +} +.fa-suffix-github-alt:after { + content: "\f113"; +} +.fa-suffix-folder-o:after { + content: "\f114"; +} +.fa-suffix-folder-open-o:after { + content: "\f115"; +} +.fa-suffix-smile-o:after { + content: "\f118"; +} +.fa-suffix-frown-o:after { + content: "\f119"; +} +.fa-suffix-meh-o:after { + content: "\f11a"; +} +.fa-suffix-gamepad:after { + content: "\f11b"; +} +.fa-suffix-keyboard-o:after { + content: "\f11c"; +} +.fa-suffix-flag-o:after { + content: "\f11d"; +} +.fa-suffix-flag-checkered:after { + content: "\f11e"; +} +.fa-suffix-terminal:after { + content: "\f120"; +} +.fa-suffix-code:after { + content: "\f121"; +} +.fa-suffix-mail-reply-all:after, +.fa-suffix-reply-all:after { + content: "\f122"; +} +.fa-suffix-star-half-empty:after, +.fa-suffix-star-half-full:after, +.fa-suffix-star-half-o:after { + content: "\f123"; +} +.fa-suffix-location-arrow:after { + content: "\f124"; +} +.fa-suffix-crop:after { + content: "\f125"; +} +.fa-suffix-code-fork:after { + content: "\f126"; +} +.fa-suffix-unlink:after, +.fa-suffix-chain-broken:after { + content: "\f127"; +} +.fa-suffix-question:after { + content: "\f128"; +} +.fa-suffix-info:after { + content: "\f129"; +} +.fa-suffix-exclamation:after { + content: "\f12a"; +} +.fa-suffix-superscript:after { + content: "\f12b"; +} +.fa-suffix-subscript:after { + content: "\f12c"; +} +.fa-suffix-eraser:after { + content: "\f12d"; +} +.fa-suffix-puzzle-piece:after { + content: "\f12e"; +} +.fa-suffix-microphone:after { + content: "\f130"; +} +.fa-suffix-microphone-slash:after { + content: "\f131"; +} +.fa-suffix-shield:after { + content: "\f132"; +} +.fa-suffix-calendar-o:after { + content: "\f133"; +} +.fa-suffix-fire-extinguisher:after { + content: "\f134"; +} +.fa-suffix-rocket:after { + content: "\f135"; +} +.fa-suffix-maxcdn:after { + content: "\f136"; +} +.fa-suffix-chevron-circle-left:after { + content: "\f137"; +} +.fa-suffix-chevron-circle-right:after { + content: "\f138"; +} +.fa-suffix-chevron-circle-up:after { + content: "\f139"; +} +.fa-suffix-chevron-circle-down:after { + content: "\f13a"; +} +.fa-suffix-html5:after { + content: "\f13b"; +} +.fa-suffix-css3:after { + content: "\f13c"; +} +.fa-suffix-anchor:after { + content: "\f13d"; +} +.fa-suffix-unlock-alt:after { + content: "\f13e"; +} +.fa-suffix-bullseye:after { + content: "\f140"; +} +.fa-suffix-ellipsis-h:after { + content: "\f141"; +} +.fa-suffix-ellipsis-v:after { + content: "\f142"; +} +.fa-suffix-rss-square:after { + content: "\f143"; +} +.fa-suffix-play-circle:after { + content: "\f144"; +} +.fa-suffix-ticket:after { + content: "\f145"; +} +.fa-suffix-minus-square:after { + content: "\f146"; +} +.fa-suffix-minus-square-o:after { + content: "\f147"; +} +.fa-suffix-level-up:after { + content: "\f148"; +} +.fa-suffix-level-down:after { + content: "\f149"; +} +.fa-suffix-check-square:after { + content: "\f14a"; +} +.fa-suffix-pencil-square:after { + content: "\f14b"; +} +.fa-suffix-external-link-square:after { + content: "\f14c"; +} +.fa-suffix-share-square:after { + content: "\f14d"; +} +.fa-suffix-compass:after { + content: "\f14e"; +} +.fa-suffix-toggle-down:after, +.fa-suffix-caret-square-o-down:after { + content: "\f150"; +} +.fa-suffix-toggle-up:after, +.fa-suffix-caret-square-o-up:after { + content: "\f151"; +} +.fa-suffix-toggle-right:after, +.fa-suffix-caret-square-o-right:after { + content: "\f152"; +} +.fa-suffix-euro:after, +.fa-suffix-eur:after { + content: "\f153"; +} +.fa-suffix-gbp:after { + content: "\f154"; +} +.fa-suffix-dollar:after, +.fa-suffix-usd:after { + content: "\f155"; +} +.fa-suffix-rupee:after, +.fa-suffix-inr:after { + content: "\f156"; +} +.fa-suffix-cny:after, +.fa-suffix-rmb:after, +.fa-suffix-yen:after, +.fa-suffix-jpy:after { + content: "\f157"; +} +.fa-suffix-ruble:after, +.fa-suffix-rouble:after, +.fa-suffix-rub:after { + content: "\f158"; +} +.fa-suffix-won:after, +.fa-suffix-krw:after { + content: "\f159"; +} +.fa-suffix-bitcoin:after, +.fa-suffix-btc:after { + content: "\f15a"; +} +.fa-suffix-file:after { + content: "\f15b"; +} +.fa-suffix-file-text:after { + content: "\f15c"; +} +.fa-suffix-sort-alpha-asc:after { + content: "\f15d"; +} +.fa-suffix-sort-alpha-desc:after { + content: "\f15e"; +} +.fa-suffix-sort-amount-asc:after { + content: "\f160"; +} +.fa-suffix-sort-amount-desc:after { + content: "\f161"; +} +.fa-suffix-sort-numeric-asc:after { + content: "\f162"; +} +.fa-suffix-sort-numeric-desc:after { + content: "\f163"; +} +.fa-suffix-thumbs-up:after { + content: "\f164"; +} +.fa-suffix-thumbs-down:after { + content: "\f165"; +} +.fa-suffix-youtube-square:after { + content: "\f166"; +} +.fa-suffix-youtube:after { + content: "\f167"; +} +.fa-suffix-xing:after { + content: "\f168"; +} +.fa-suffix-xing-square:after { + content: "\f169"; +} +.fa-suffix-youtube-play:after { + content: "\f16a"; +} +.fa-suffix-dropbox:after { + content: "\f16b"; +} +.fa-suffix-stack-overflow:after { + content: "\f16c"; +} +.fa-suffix-instagram:after { + content: "\f16d"; +} +.fa-suffix-flickr:after { + content: "\f16e"; +} +.fa-suffix-adn:after { + content: "\f170"; +} +.fa-suffix-bitbucket:after { + content: "\f171"; +} +.fa-suffix-bitbucket-square:after { + content: "\f172"; +} +.fa-suffix-tumblr:after { + content: "\f173"; +} +.fa-suffix-tumblr-square:after { + content: "\f174"; +} +.fa-suffix-long-arrow-down:after { + content: "\f175"; +} +.fa-suffix-long-arrow-up:after { + content: "\f176"; +} +.fa-suffix-long-arrow-left:after { + content: "\f177"; +} +.fa-suffix-long-arrow-right:after { + content: "\f178"; +} +.fa-suffix-apple:after { + content: "\f179"; +} +.fa-suffix-windows:after { + content: "\f17a"; +} +.fa-suffix-android:after { + content: "\f17b"; +} +.fa-suffix-linux:after { + content: "\f17c"; +} +.fa-suffix-dribbble:after { + content: "\f17d"; +} +.fa-suffix-skype:after { + content: "\f17e"; +} +.fa-suffix-foursquare:after { + content: "\f180"; +} +.fa-suffix-trello:after { + content: "\f181"; +} +.fa-suffix-female:after { + content: "\f182"; +} +.fa-suffix-male:after { + content: "\f183"; +} +.fa-suffix-gittip:after, +.fa-suffix-gratipay:after { + content: "\f184"; +} +.fa-suffix-sun-o:after { + content: "\f185"; +} +.fa-suffix-moon-o:after { + content: "\f186"; +} +.fa-suffix-archive:after { + content: "\f187"; +} +.fa-suffix-bug:after { + content: "\f188"; +} +.fa-suffix-vk:after { + content: "\f189"; +} +.fa-suffix-weibo:after { + content: "\f18a"; +} +.fa-suffix-renren:after { + content: "\f18b"; +} +.fa-suffix-pagelines:after { + content: "\f18c"; +} +.fa-suffix-stack-exchange:after { + content: "\f18d"; +} +.fa-suffix-arrow-circle-o-right:after { + content: "\f18e"; +} +.fa-suffix-arrow-circle-o-left:after { + content: "\f190"; +} +.fa-suffix-toggle-left:after, +.fa-suffix-caret-square-o-left:after { + content: "\f191"; +} +.fa-suffix-dot-circle-o:after { + content: "\f192"; +} +.fa-suffix-wheelchair:after { + content: "\f193"; +} +.fa-suffix-vimeo-square:after { + content: "\f194"; +} +.fa-suffix-turkish-lira:after, +.fa-suffix-try:after { + content: "\f195"; +} +.fa-suffix-plus-square-o:after { + content: "\f196"; +} +.fa-suffix-space-shuttle:after { + content: "\f197"; +} +.fa-suffix-slack:after { + content: "\f198"; +} +.fa-suffix-envelope-square:after { + content: "\f199"; +} +.fa-suffix-wordpress:after { + content: "\f19a"; +} +.fa-suffix-openid:after { + content: "\f19b"; +} +.fa-suffix-institution:after, +.fa-suffix-bank:after, +.fa-suffix-university:after { + content: "\f19c"; +} +.fa-suffix-mortar-board:after, +.fa-suffix-graduation-cap:after { + content: "\f19d"; +} +.fa-suffix-yahoo:after { + content: "\f19e"; +} +.fa-suffix-google:after { + content: "\f1a0"; +} +.fa-suffix-reddit:after { + content: "\f1a1"; +} +.fa-suffix-reddit-square:after { + content: "\f1a2"; +} +.fa-suffix-stumbleupon-circle:after { + content: "\f1a3"; +} +.fa-suffix-stumbleupon:after { + content: "\f1a4"; +} +.fa-suffix-delicious:after { + content: "\f1a5"; +} +.fa-suffix-digg:after { + content: "\f1a6"; +} +.fa-suffix-pied-piper-pp:after { + content: "\f1a7"; +} +.fa-suffix-pied-piper-alt:after { + content: "\f1a8"; +} +.fa-suffix-drupal:after { + content: "\f1a9"; +} +.fa-suffix-joomla:after { + content: "\f1aa"; +} +.fa-suffix-language:after { + content: "\f1ab"; +} +.fa-suffix-fax:after { + content: "\f1ac"; +} +.fa-suffix-building:after { + content: "\f1ad"; +} +.fa-suffix-child:after { + content: "\f1ae"; +} +.fa-suffix-paw:after { + content: "\f1b0"; +} +.fa-suffix-spoon:after { + content: "\f1b1"; +} +.fa-suffix-cube:after { + content: "\f1b2"; +} +.fa-suffix-cubes:after { + content: "\f1b3"; +} +.fa-suffix-behance:after { + content: "\f1b4"; +} +.fa-suffix-behance-square:after { + content: "\f1b5"; +} +.fa-suffix-steam:after { + content: "\f1b6"; +} +.fa-suffix-steam-square:after { + content: "\f1b7"; +} +.fa-suffix-recycle:after { + content: "\f1b8"; +} +.fa-suffix-automobile:after, +.fa-suffix-car:after { + content: "\f1b9"; +} +.fa-suffix-cab:after, +.fa-suffix-taxi:after { + content: "\f1ba"; +} +.fa-suffix-tree:after { + content: "\f1bb"; +} +.fa-suffix-spotify:after { + content: "\f1bc"; +} +.fa-suffix-deviantart:after { + content: "\f1bd"; +} +.fa-suffix-soundcloud:after { + content: "\f1be"; +} +.fa-suffix-database:after { + content: "\f1c0"; +} +.fa-suffix-file-pdf-o:after { + content: "\f1c1"; +} +.fa-suffix-file-word-o:after { + content: "\f1c2"; +} +.fa-suffix-file-excel-o:after { + content: "\f1c3"; +} +.fa-suffix-file-powerpoint-o:after { + content: "\f1c4"; +} +.fa-suffix-file-photo-o:after, +.fa-suffix-file-picture-o:after, +.fa-suffix-file-image-o:after { + content: "\f1c5"; +} +.fa-suffix-file-zip-o:after, +.fa-suffix-file-archive-o:after { + content: "\f1c6"; +} +.fa-suffix-file-sound-o:after, +.fa-suffix-file-audio-o:after { + content: "\f1c7"; +} +.fa-suffix-file-movie-o:after, +.fa-suffix-file-video-o:after { + content: "\f1c8"; +} +.fa-suffix-file-code-o:after { + content: "\f1c9"; +} +.fa-suffix-vine:after { + content: "\f1ca"; +} +.fa-suffix-codepen:after { + content: "\f1cb"; +} +.fa-suffix-jsfiddle:after { + content: "\f1cc"; +} +.fa-suffix-life-bouy:after, +.fa-suffix-life-buoy:after, +.fa-suffix-life-saver:after, +.fa-suffix-support:after, +.fa-suffix-life-ring:after { + content: "\f1cd"; +} +.fa-suffix-circle-o-notch:after { + content: "\f1ce"; +} +.fa-suffix-ra:after, +.fa-suffix-resistance:after, +.fa-suffix-rebel:after { + content: "\f1d0"; +} +.fa-suffix-ge:after, +.fa-suffix-empire:after { + content: "\f1d1"; +} +.fa-suffix-git-square:after { + content: "\f1d2"; +} +.fa-suffix-git:after { + content: "\f1d3"; +} +.fa-suffix-y-combinator-square:after, +.fa-suffix-yc-square:after, +.fa-suffix-hacker-news:after { + content: "\f1d4"; +} +.fa-suffix-tencent-weibo:after { + content: "\f1d5"; +} +.fa-suffix-qq:after { + content: "\f1d6"; +} +.fa-suffix-wechat:after, +.fa-suffix-weixin:after { + content: "\f1d7"; +} +.fa-suffix-send:after, +.fa-suffix-paper-plane:after { + content: "\f1d8"; +} +.fa-suffix-send-o:after, +.fa-suffix-paper-plane-o:after { + content: "\f1d9"; +} +.fa-suffix-history:after { + content: "\f1da"; +} +.fa-suffix-circle-thin:after { + content: "\f1db"; +} +.fa-suffix-header:after { + content: "\f1dc"; +} +.fa-suffix-paragraph:after { + content: "\f1dd"; +} +.fa-suffix-sliders:after { + content: "\f1de"; +} +.fa-suffix-share-alt:after { + content: "\f1e0"; +} +.fa-suffix-share-alt-square:after { + content: "\f1e1"; +} +.fa-suffix-bomb:after { + content: "\f1e2"; +} +.fa-suffix-soccer-ball-o:after, +.fa-suffix-futbol-o:after { + content: "\f1e3"; +} +.fa-suffix-tty:after { + content: "\f1e4"; +} +.fa-suffix-binoculars:after { + content: "\f1e5"; +} +.fa-suffix-plug:after { + content: "\f1e6"; +} +.fa-suffix-slideshare:after { + content: "\f1e7"; +} +.fa-suffix-twitch:after { + content: "\f1e8"; +} +.fa-suffix-yelp:after { + content: "\f1e9"; +} +.fa-suffix-newspaper-o:after { + content: "\f1ea"; +} +.fa-suffix-wifi:after { + content: "\f1eb"; +} +.fa-suffix-calculator:after { + content: "\f1ec"; +} +.fa-suffix-paypal:after { + content: "\f1ed"; +} +.fa-suffix-google-wallet:after { + content: "\f1ee"; +} +.fa-suffix-cc-visa:after { + content: "\f1f0"; +} +.fa-suffix-cc-mastercard:after { + content: "\f1f1"; +} +.fa-suffix-cc-discover:after { + content: "\f1f2"; +} +.fa-suffix-cc-amex:after { + content: "\f1f3"; +} +.fa-suffix-cc-paypal:after { + content: "\f1f4"; +} +.fa-suffix-cc-stripe:after { + content: "\f1f5"; +} +.fa-suffix-bell-slash:after { + content: "\f1f6"; +} +.fa-suffix-bell-slash-o:after { + content: "\f1f7"; +} +.fa-suffix-trash:after { + content: "\f1f8"; +} +.fa-suffix-copyright:after { + content: "\f1f9"; +} +.fa-suffix-at:after { + content: "\f1fa"; +} +.fa-suffix-eyedropper:after { + content: "\f1fb"; +} +.fa-suffix-paint-brush:after { + content: "\f1fc"; +} +.fa-suffix-birthday-cake:after { + content: "\f1fd"; +} +.fa-suffix-area-chart:after { + content: "\f1fe"; +} +.fa-suffix-pie-chart:after { + content: "\f200"; +} +.fa-suffix-line-chart:after { + content: "\f201"; +} +.fa-suffix-lastfm:after { + content: "\f202"; +} +.fa-suffix-lastfm-square:after { + content: "\f203"; +} +.fa-suffix-toggle-off:after { + content: "\f204"; +} +.fa-suffix-toggle-on:after { + content: "\f205"; +} +.fa-suffix-bicycle:after { + content: "\f206"; +} +.fa-suffix-bus:after { + content: "\f207"; +} +.fa-suffix-ioxhost:after { + content: "\f208"; +} +.fa-suffix-angellist:after { + content: "\f209"; +} +.fa-suffix-cc:after { + content: "\f20a"; +} +.fa-suffix-shekel:after, +.fa-suffix-sheqel:after, +.fa-suffix-ils:after { + content: "\f20b"; +} +.fa-suffix-meanpath:after { + content: "\f20c"; +} +.fa-suffix-buysellads:after { + content: "\f20d"; +} +.fa-suffix-connectdevelop:after { + content: "\f20e"; +} +.fa-suffix-dashcube:after { + content: "\f210"; +} +.fa-suffix-forumbee:after { + content: "\f211"; +} +.fa-suffix-leanpub:after { + content: "\f212"; +} +.fa-suffix-sellsy:after { + content: "\f213"; +} +.fa-suffix-shirtsinbulk:after { + content: "\f214"; +} +.fa-suffix-simplybuilt:after { + content: "\f215"; +} +.fa-suffix-skyatlas:after { + content: "\f216"; +} +.fa-suffix-cart-plus:after { + content: "\f217"; +} +.fa-suffix-cart-arrow-down:after { + content: "\f218"; +} +.fa-suffix-diamond:after { + content: "\f219"; +} +.fa-suffix-ship:after { + content: "\f21a"; +} +.fa-suffix-user-secret:after { + content: "\f21b"; +} +.fa-suffix-motorcycle:after { + content: "\f21c"; +} +.fa-suffix-street-view:after { + content: "\f21d"; +} +.fa-suffix-heartbeat:after { + content: "\f21e"; +} +.fa-suffix-venus:after { + content: "\f221"; +} +.fa-suffix-mars:after { + content: "\f222"; +} +.fa-suffix-mercury:after { + content: "\f223"; +} +.fa-suffix-intersex:after, +.fa-suffix-transgender:after { + content: "\f224"; +} +.fa-suffix-transgender-alt:after { + content: "\f225"; +} +.fa-suffix-venus-double:after { + content: "\f226"; +} +.fa-suffix-mars-double:after { + content: "\f227"; +} +.fa-suffix-venus-mars:after { + content: "\f228"; +} +.fa-suffix-mars-stroke:after { + content: "\f229"; +} +.fa-suffix-mars-stroke-v:after { + content: "\f22a"; +} +.fa-suffix-mars-stroke-h:after { + content: "\f22b"; +} +.fa-suffix-neuter:after { + content: "\f22c"; +} +.fa-suffix-genderless:after { + content: "\f22d"; +} +.fa-suffix-facebook-official:after { + content: "\f230"; +} +.fa-suffix-pinterest-p:after { + content: "\f231"; +} +.fa-suffix-whatsapp:after { + content: "\f232"; +} +.fa-suffix-server:after { + content: "\f233"; +} +.fa-suffix-user-plus:after { + content: "\f234"; +} +.fa-suffix-user-times:after { + content: "\f235"; +} +.fa-suffix-hotel:after, +.fa-suffix-bed:after { + content: "\f236"; +} +.fa-suffix-viacoin:after { + content: "\f237"; +} +.fa-suffix-train:after { + content: "\f238"; +} +.fa-suffix-subway:after { + content: "\f239"; +} +.fa-suffix-medium:after { + content: "\f23a"; +} +.fa-suffix-yc:after, +.fa-suffix-y-combinator:after { + content: "\f23b"; +} +.fa-suffix-optin-monster:after { + content: "\f23c"; +} +.fa-suffix-opencart:after { + content: "\f23d"; +} +.fa-suffix-expeditedssl:after { + content: "\f23e"; +} +.fa-suffix-battery-4:after, +.fa-suffix-battery:after, +.fa-suffix-battery-full:after { + content: "\f240"; +} +.fa-suffix-battery-3:after, +.fa-suffix-battery-three-quarters:after { + content: "\f241"; +} +.fa-suffix-battery-2:after, +.fa-suffix-battery-half:after { + content: "\f242"; +} +.fa-suffix-battery-1:after, +.fa-suffix-battery-quarter:after { + content: "\f243"; +} +.fa-suffix-battery-0:after, +.fa-suffix-battery-empty:after { + content: "\f244"; +} +.fa-suffix-mouse-pointer:after { + content: "\f245"; +} +.fa-suffix-i-cursor:after { + content: "\f246"; +} +.fa-suffix-object-group:after { + content: "\f247"; +} +.fa-suffix-object-ungroup:after { + content: "\f248"; +} +.fa-suffix-sticky-note:after { + content: "\f249"; +} +.fa-suffix-sticky-note-o:after { + content: "\f24a"; +} +.fa-suffix-cc-jcb:after { + content: "\f24b"; +} +.fa-suffix-cc-diners-club:after { + content: "\f24c"; +} +.fa-suffix-clone:after { + content: "\f24d"; +} +.fa-suffix-balance-scale:after { + content: "\f24e"; +} +.fa-suffix-hourglass-o:after { + content: "\f250"; +} +.fa-suffix-hourglass-1:after, +.fa-suffix-hourglass-start:after { + content: "\f251"; +} +.fa-suffix-hourglass-2:after, +.fa-suffix-hourglass-half:after { + content: "\f252"; +} +.fa-suffix-hourglass-3:after, +.fa-suffix-hourglass-end:after { + content: "\f253"; +} +.fa-suffix-hourglass:after { + content: "\f254"; +} +.fa-suffix-hand-grab-o:after, +.fa-suffix-hand-rock-o:after { + content: "\f255"; +} +.fa-suffix-hand-stop-o:after, +.fa-suffix-hand-paper-o:after { + content: "\f256"; +} +.fa-suffix-hand-scissors-o:after { + content: "\f257"; +} +.fa-suffix-hand-lizard-o:after { + content: "\f258"; +} +.fa-suffix-hand-spock-o:after { + content: "\f259"; +} +.fa-suffix-hand-pointer-o:after { + content: "\f25a"; +} +.fa-suffix-hand-peace-o:after { + content: "\f25b"; +} +.fa-suffix-trademark:after { + content: "\f25c"; +} +.fa-suffix-registered:after { + content: "\f25d"; +} +.fa-suffix-creative-commons:after { + content: "\f25e"; +} +.fa-suffix-gg:after { + content: "\f260"; +} +.fa-suffix-gg-circle:after { + content: "\f261"; +} +.fa-suffix-tripadvisor:after { + content: "\f262"; +} +.fa-suffix-odnoklassniki:after { + content: "\f263"; +} +.fa-suffix-odnoklassniki-square:after { + content: "\f264"; +} +.fa-suffix-get-pocket:after { + content: "\f265"; +} +.fa-suffix-wikipedia-w:after { + content: "\f266"; +} +.fa-suffix-safari:after { + content: "\f267"; +} +.fa-suffix-chrome:after { + content: "\f268"; +} +.fa-suffix-firefox:after { + content: "\f269"; +} +.fa-suffix-opera:after { + content: "\f26a"; +} +.fa-suffix-internet-explorer:after { + content: "\f26b"; +} +.fa-suffix-tv:after, +.fa-suffix-television:after { + content: "\f26c"; +} +.fa-suffix-contao:after { + content: "\f26d"; +} +.fa-suffix-500px:after { + content: "\f26e"; +} +.fa-suffix-amazon:after { + content: "\f270"; +} +.fa-suffix-calendar-plus-o:after { + content: "\f271"; +} +.fa-suffix-calendar-minus-o:after { + content: "\f272"; +} +.fa-suffix-calendar-times-o:after { + content: "\f273"; +} +.fa-suffix-calendar-check-o:after { + content: "\f274"; +} +.fa-suffix-industry:after { + content: "\f275"; +} +.fa-suffix-map-pin:after { + content: "\f276"; +} +.fa-suffix-map-signs:after { + content: "\f277"; +} +.fa-suffix-map-o:after { + content: "\f278"; +} +.fa-suffix-map:after { + content: "\f279"; +} +.fa-suffix-commenting:after { + content: "\f27a"; +} +.fa-suffix-commenting-o:after { + content: "\f27b"; +} +.fa-suffix-houzz:after { + content: "\f27c"; +} +.fa-suffix-vimeo:after { + content: "\f27d"; +} +.fa-suffix-black-tie:after { + content: "\f27e"; +} +.fa-suffix-fonticons:after { + content: "\f280"; +} +.fa-suffix-reddit-alien:after { + content: "\f281"; +} +.fa-suffix-edge:after { + content: "\f282"; +} +.fa-suffix-credit-card-alt:after { + content: "\f283"; +} +.fa-suffix-codiepie:after { + content: "\f284"; +} +.fa-suffix-modx:after { + content: "\f285"; +} +.fa-suffix-fort-awesome:after { + content: "\f286"; +} +.fa-suffix-usb:after { + content: "\f287"; +} +.fa-suffix-product-hunt:after { + content: "\f288"; +} +.fa-suffix-mixcloud:after { + content: "\f289"; +} +.fa-suffix-scribd:after { + content: "\f28a"; +} +.fa-suffix-pause-circle:after { + content: "\f28b"; +} +.fa-suffix-pause-circle-o:after { + content: "\f28c"; +} +.fa-suffix-stop-circle:after { + content: "\f28d"; +} +.fa-suffix-stop-circle-o:after { + content: "\f28e"; +} +.fa-suffix-shopping-bag:after { + content: "\f290"; +} +.fa-suffix-shopping-basket:after { + content: "\f291"; +} +.fa-suffix-hashtag:after { + content: "\f292"; +} +.fa-suffix-bluetooth:after { + content: "\f293"; +} +.fa-suffix-bluetooth-b:after { + content: "\f294"; +} +.fa-suffix-percent:after { + content: "\f295"; +} +.fa-suffix-gitlab:after { + content: "\f296"; +} +.fa-suffix-wpbeginner:after { + content: "\f297"; +} +.fa-suffix-wpforms:after { + content: "\f298"; +} +.fa-suffix-envira:after { + content: "\f299"; +} +.fa-suffix-universal-access:after { + content: "\f29a"; +} +.fa-suffix-wheelchair-alt:after { + content: "\f29b"; +} +.fa-suffix-question-circle-o:after { + content: "\f29c"; +} +.fa-suffix-blind:after { + content: "\f29d"; +} +.fa-suffix-audio-description:after { + content: "\f29e"; +} +.fa-suffix-volume-control-phone:after { + content: "\f2a0"; +} +.fa-suffix-braille:after { + content: "\f2a1"; +} +.fa-suffix-assistive-listening-systems:after { + content: "\f2a2"; +} +.fa-suffix-asl-interpreting:after, +.fa-suffix-american-sign-language-interpreting:after { + content: "\f2a3"; +} +.fa-suffix-deafness:after, +.fa-suffix-hard-of-hearing:after, +.fa-suffix-deaf:after { + content: "\f2a4"; +} +.fa-suffix-glide:after { + content: "\f2a5"; +} +.fa-suffix-glide-g:after { + content: "\f2a6"; +} +.fa-suffix-signing:after, +.fa-suffix-sign-language:after { + content: "\f2a7"; +} +.fa-suffix-low-vision:after { + content: "\f2a8"; +} +.fa-suffix-viadeo:after { + content: "\f2a9"; +} +.fa-suffix-viadeo-square:after { + content: "\f2aa"; +} +.fa-suffix-snapchat:after { + content: "\f2ab"; +} +.fa-suffix-snapchat-ghost:after { + content: "\f2ac"; +} +.fa-suffix-snapchat-square:after { + content: "\f2ad"; +} +.fa-suffix-pied-piper:after { + content: "\f2ae"; +} +.fa-suffix-first-order:after { + content: "\f2b0"; +} +.fa-suffix-yoast:after { + content: "\f2b1"; +} +.fa-suffix-themeisle:after { + content: "\f2b2"; +} +.fa-suffix-google-plus-circle:after, +.fa-suffix-google-plus-official:after { + content: "\f2b3"; +} +.fa-suffix-fa:after, +.fa-suffix-font-awesome:after { + content: "\f2b4"; +} +.fa-suffix-handshake-o:after { + content: "\f2b5"; +} +.fa-suffix-envelope-open:after { + content: "\f2b6"; +} +.fa-suffix-envelope-open-o:after { + content: "\f2b7"; +} +.fa-suffix-linode:after { + content: "\f2b8"; +} +.fa-suffix-address-book:after { + content: "\f2b9"; +} +.fa-suffix-address-book-o:after { + content: "\f2ba"; +} +.fa-suffix-vcard:after, +.fa-suffix-address-card:after { + content: "\f2bb"; +} +.fa-suffix-vcard-o:after, +.fa-suffix-address-card-o:after { + content: "\f2bc"; +} +.fa-suffix-user-circle:after { + content: "\f2bd"; +} +.fa-suffix-user-circle-o:after { + content: "\f2be"; +} +.fa-suffix-user-o:after { + content: "\f2c0"; +} +.fa-suffix-id-badge:after { + content: "\f2c1"; +} +.fa-suffix-drivers-license:after, +.fa-suffix-id-card:after { + content: "\f2c2"; +} +.fa-suffix-drivers-license-o:after, +.fa-suffix-id-card-o:after { + content: "\f2c3"; +} +.fa-suffix-quora:after { + content: "\f2c4"; +} +.fa-suffix-free-code-camp:after { + content: "\f2c5"; +} +.fa-suffix-telegram:after { + content: "\f2c6"; +} +.fa-suffix-thermometer-4:after, +.fa-suffix-thermometer:after, +.fa-suffix-thermometer-full:after { + content: "\f2c7"; +} +.fa-suffix-thermometer-3:after, +.fa-suffix-thermometer-three-quarters:after { + content: "\f2c8"; +} +.fa-suffix-thermometer-2:after, +.fa-suffix-thermometer-half:after { + content: "\f2c9"; +} +.fa-suffix-thermometer-1:after, +.fa-suffix-thermometer-quarter:after { + content: "\f2ca"; +} +.fa-suffix-thermometer-0:after, +.fa-suffix-thermometer-empty:after { + content: "\f2cb"; +} +.fa-suffix-shower:after { + content: "\f2cc"; +} +.fa-suffix-bathtub:after, +.fa-suffix-s15:after, +.fa-suffix-bath:after { + content: "\f2cd"; +} +.fa-suffix-podcast:after { + content: "\f2ce"; +} +.fa-suffix-window-maximize:after { + content: "\f2d0"; +} +.fa-suffix-window-minimize:after { + content: "\f2d1"; +} +.fa-suffix-window-restore:after { + content: "\f2d2"; +} +.fa-suffix-times-rectangle:after, +.fa-suffix-window-close:after { + content: "\f2d3"; +} +.fa-suffix-times-rectangle-o:after, +.fa-suffix-window-close-o:after { + content: "\f2d4"; +} +.fa-suffix-bandcamp:after { + content: "\f2d5"; +} +.fa-suffix-grav:after { + content: "\f2d6"; +} +.fa-suffix-etsy:after { + content: "\f2d7"; +} +.fa-suffix-imdb:after { + content: "\f2d8"; +} +.fa-suffix-ravelry:after { + content: "\f2d9"; +} +.fa-suffix-eercast:after { + content: "\f2da"; +} +.fa-suffix-microchip:after { + content: "\f2db"; +} +.fa-suffix-snowflake-o:after { + content: "\f2dc"; +} +.fa-suffix-superpowers:after { + content: "\f2dd"; +} +.fa-suffix-wpexplorer:after { + content: "\f2de"; +} +.fa-suffix-meetup:after { + content: "\f2e0"; +} diff --git a/addons/web/static/lib/pdfjs/web/ui_utils.js b/addons/web/static/lib/pdfjs/web/ui_utils.js index 7e798e34270..5480224846b 100644 --- a/addons/web/static/lib/pdfjs/web/ui_utils.js +++ b/addons/web/static/lib/pdfjs/web/ui_utils.js @@ -348,6 +348,10 @@ var ProgressBar = (function ProgressBarClosure() { this.div.classList.remove('indeterminate'); var progressSize = this.width * this._percent / 100; this.div.style.width = progressSize + this.units; + // Add attributes for screen readers and analysis tools + this.bar.setAttribute('aria-valuemin', 0); + this.bar.setAttribute('aria-valuemax', 100); + this.bar.setAttribute('aria-valuenow', this._percent); }, get percent() { @@ -377,6 +381,7 @@ var ProgressBar = (function ProgressBarClosure() { } this.visible = false; this.bar.classList.add('hidden'); + this.bar.setAttribute('aria-hidden', "true") document.body.classList.remove('loadingInProgress'); }, @@ -387,6 +392,7 @@ var ProgressBar = (function ProgressBarClosure() { this.visible = true; document.body.classList.add('loadingInProgress'); this.bar.classList.remove('hidden'); + this.bar.setAttribute('aria-hidden', "false") } }; diff --git a/addons/web/static/lib/qweb/qweb-test-attributes.xml b/addons/web/static/lib/qweb/qweb-test-attributes.xml index e16ef8a3f0e..b599b76b629 100644 --- a/addons/web/static/lib/qweb/qweb-test-attributes.xml +++ b/addons/web/static/lib/qweb/qweb-test-attributes.xml @@ -5,9 +5,9 @@ <result id="static"><![CDATA[<div foo="a" bar="b" baz="c"></div>]]></result> <t t-name="static-void"> - <img src="/test.jpg"/> + <img src="/test.jpg" alt="Test"/> </t> - <result id="static-void"><![CDATA[<img src="/test.jpg"/>]]></result> + <result id="static-void"><![CDATA[<img src="/test.jpg" alt="Test"/>]]></result> <t t-name="fixed-literal"> <div t-att-foo="'bar'"/> diff --git a/addons/web/static/lib/qweb/qweb2.js b/addons/web/static/lib/qweb/qweb2.js index 94a0afaa32a..6ce74539926 100644 --- a/addons/web/static/lib/qweb/qweb2.js +++ b/addons/web/static/lib/qweb/qweb2.js @@ -471,10 +471,10 @@ QWeb2.Engine = (function() { if (this.debug && window.console) { console.log(code); } - this.tools.exception("Error evaluating template: " + error, { template: name }); + this.tools.exception("Error evaluating template: " + error, { template: template }); } if (!tcompiled) { - this.tools.exception("Error evaluating template: (IE?)" + error, { template: name }); + this.tools.exception("Error evaluating template: (IE?)" + error, { template: template }); } this.compiled_templates[template] = tcompiled; return this.render(template, dict); diff --git a/addons/web/static/src/js/core/dialog.js b/addons/web/static/src/js/core/dialog.js index 7d4796886b7..6ebd94ef13e 100644 --- a/addons/web/static/src/js/core/dialog.js +++ b/addons/web/static/src/js/core/dialog.js @@ -17,12 +17,13 @@ var _t = core._t; * always exists during the lifecycle of the dialog. **/ var Dialog = Widget.extend({ + tagName: 'main', xmlDependencies: ['/web/static/src/xml/dialog.xml'], custom_events: _.extend({}, Widget.prototype.custom_events, { focus_control_button: '_onFocusControlButton', }), events: _.extend({} , Widget.prototype.events, { - 'keydown .modal-footer button':'_onFooterButtonKeyDown', + 'keydown footer.modal-footer button':'_onFooterButtonKeyDown', }), /** * @param {Widget} parent @@ -92,7 +93,7 @@ var Dialog = Widget.extend({ self.$modal.find('.modal-dialog').addClass('modal-sm'); break; } - self.$footer = self.$modal.find(".modal-footer"); + self.$footer = self.$modal.find("footer"); self.set_buttons(self.buttons); self.$modal.on('hidden.bs.modal', _.bind(self.destroy, self)); }); @@ -168,7 +169,17 @@ var Dialog = Widget.extend({ var self = this; this.appendTo($('<div/>')).then(function () { - self.$modal.find(".modal-body").replaceWith(self.$el); + var $main = self.$modal.find("main:first"); + if ($main.length === 0) { + $main = self.$modal.find(".modal-body:first"); + } + if (self.$el.tagName !== 'MAIN') { + self.$el.removeClass(".modal-body"); + self.$el = $('<main class="modal-body"/>').append(self.$el); + } + $main.replaceWith(self.$el); + self.$modal.attr('open', true); + self.$modal.removeAttr("aria-hidden"); self.$modal.modal('show'); self._opened.resolve(); }); @@ -201,11 +212,13 @@ var Dialog = Widget.extend({ $('.tooltip').remove(); //remove open tooltip if any to prevent them staying when modal has disappeared if (this.$modal) { this.$modal.modal('hide'); + this.$modal.removeAttr('open'); + this.$modal.attr('aria-hidden', true); this.$modal.remove(); } if (!isFocusSet) { - var modals = $('body > .modal').filter(':visible'); + var modals = $('body > [role="dialog"]').filter(':visible'); if (modals.length) { modals.last().focus(); // Keep class modal-open (deleted by bootstrap hide fnct) on body to allow scrolling inside the modal @@ -287,9 +300,9 @@ Dialog.alert = function (owner, message, options) { return new Dialog(owner, _.extend({ size: 'medium', buttons: buttons, - $content: $('<div>', { + $content: $('<main role="alert"/>').append($('<p>', { text: message, - }), + })), title: _t("Alert"), }, options)).open({shouldFocusButtons:true}); }; @@ -312,9 +325,9 @@ Dialog.confirm = function (owner, message, options) { return new Dialog(owner, _.extend({ size: 'medium', buttons: buttons, - $content: $('<div>', { + $content: $('<main role="alert">').append($('<p>', { text: message, - }), + })), title: _t("Confirmation"), }, options)).open({shouldFocusButtons:true}); }; @@ -345,7 +358,7 @@ Dialog.safeConfirm = function (owner, message, options) { text: message, }); } - $content = $('<div/>').append($content, $securityCheck); + $content = $('<main role="alert"/>').append($content, $securityCheck); var buttons = [ { diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js index 9bb61475b83..eab0093ed50 100644 --- a/addons/web/static/src/js/fields/abstract_field.js +++ b/addons/web/static/src/js/fields/abstract_field.js @@ -310,6 +310,7 @@ var AbstractField = Widget.extend({ */ removeInvalidClass: function () { this.$el.removeClass('o_field_invalid'); + this.$el.removeAttr('aria-invalid'); }, /** @@ -317,6 +318,7 @@ var AbstractField = Widget.extend({ */ setInvalidClass: function () { this.$el.addClass('o_field_invalid'); + this.$el.attr('aria-invalid', 'true'); }, /** diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index 43b4e349a66..0cf9271de9d 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -397,9 +397,10 @@ var LinkButton = AbstractField.extend({ if (this.value) { var className = this.attrs.icon || 'fa-globe'; - this.$el.html("<span />"); + this.$el.html("<span role='img'/>"); this.$el.addClass("fa "+ className); this.$el.attr('title', this.value); + this.$el.attr('aria-label', this.value); } }, @@ -1460,6 +1461,7 @@ var PriorityWidget = AbstractField.extend({ _renderStar: function (tag, isFull, index, tip) { return $(tag) .attr('title', tip) + .attr('aria-label', tip) .attr('data-index', index) .addClass('o_priority_star fa') .toggleClass('fa-star', isFull) @@ -1529,7 +1531,8 @@ var AttachmentImage = AbstractField.extend({ if (this.value) { this.$el.empty().append($('<img>/', { src: "/web/image/" + this.value.data.id + "?unique=1", - title: this.value.data.display_name + title: this.value.data.display_name, + alt: _("Image") })); } } @@ -1598,7 +1601,9 @@ var StateSelectionWidget = AbstractField.extend({ this.$('.o_status') .removeClass('o_status_red o_status_green') .addClass(currentState.state_class) - .prop('special_click', true); + .prop('special_click', true) + .parent().attr('title', currentState.state_name) + .attr('aria-label', currentState.state_name); // Render "FormSelection.Items" and move it into "FormSelection" var $items = $(qweb.render('FormSelection.items', { @@ -1662,8 +1667,9 @@ var FavoriteWidget = AbstractField.extend({ * @private */ _render: function () { - var template = this.attrs.nolabel ? '<a href="#"><i class="fa %s" title="%s"></i></a>' : '<a href="#"><i class="fa %s"></i> %s</a>'; - this.$el.empty().append(_.str.sprintf(template, this.value ? 'fa-star' : 'fa-star-o', this.value ? _t('Remove from Favorites') : _t('Add to Favorites'))); + var tip = this.value ? _t('Remove from Favorites') : _t('Add to Favorites'); + var template = this.attrs.nolabel ? '<a href="#"><i class="fa %s" title="%s" aria-label="%s" role="img"></i></a>' : '<a href="#"><i class="fa %s" role="img" aria-label="%s"> %s</i></a>'; + this.$el.empty().append(_.str.sprintf(template, this.value ? 'fa-star' : 'fa-star-o', tip, tip)); }, //-------------------------------------------------------------------------- @@ -2043,7 +2049,10 @@ var FieldProgressBar = AbstractField.extend({ widthComplete = 100; } - this.$('.o_progress').toggleClass('o_progress_overflow', value > max_value); + this.$('.o_progress').toggleClass('o_progress_overflow', value > max_value) + .attr('aria-valuemin', '0') + .attr('aria-valuemax', max_value) + .attr('aria-valuenow', value); this.$('.o_progressbar_complete').css('width', widthComplete + '%'); if (!this.write_mode) { @@ -2100,6 +2109,7 @@ var FieldToggleBoolean = AbstractField.extend({ .toggleClass('text-muted', !this.value); var title = this.value ? this.attrs.options.active : this.attrs.options.inactive; this.$el.attr('title', title); + this.$el.attr('aria-pressed', this.value); }, //-------------------------------------------------------------------------- diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index c86411b6cd9..83ce59f1eb6 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -1867,7 +1867,7 @@ var FormFieldMany2ManyTags = FieldMany2ManyTags.extend({ var $target = $(ev.currentTarget); var color = $target.data('color'); var id = $target.data('id'); - var tag = this.$("span.badge[data-id='" + id + "']"); + var tag = this.$("button.badge[data-id='" + id + "']"); var currentColor = tag.data('color'); var changes = {}; diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js index 9834c9c18de..13a00dda046 100644 --- a/addons/web/static/src/js/views/basic/basic_renderer.js +++ b/addons/web/static/src/js/views/basic/basic_renderer.js @@ -50,6 +50,7 @@ var BasicRenderer = AbstractRenderer.extend({ invalidFields.push(widget.name); } widget.$el.toggleClass('o_field_invalid', !canBeSaved); + widget.$el.attr('aria-invalid', !canBeSaved); }); return invalidFields; }, diff --git a/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js b/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js index fad822efdb9..7af6b677dcf 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js +++ b/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js @@ -166,6 +166,9 @@ var KanbanColumnProgressBar = Widget.extend({ if (count > 0) { $bar.addClass('o_bar_has_records'); $bar.css('width', (count * 100 / self.groupCount) + '%'); + $bar.attr('aria-valuemin', 0); + $bar.attr('aria-valuemax', self.groupCount); + $bar.attr('aria-valuenow', count); } else { $bar.css('width', ''); } diff --git a/addons/web/static/src/js/views/kanban/kanban_column_quick_create.js b/addons/web/static/src/js/views/kanban/kanban_column_quick_create.js index 170b950a49d..f554d333bc9 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column_quick_create.js +++ b/addons/web/static/src/js/views/kanban/kanban_column_quick_create.js @@ -216,7 +216,7 @@ var ColumnQuickCreate = Widget.extend({ } // ignore clicks in modals - if ($(event.target).closest('.modal').length) { + if ($(event.target).closest('[role="dialog"]').length) { return; } diff --git a/addons/web/static/src/js/views/kanban/kanban_record.js b/addons/web/static/src/js/views/kanban/kanban_record.js index 30bafaab117..66171d2693c 100644 --- a/addons/web/static/src/js/views/kanban/kanban_record.js +++ b/addons/web/static/src/js/views/kanban/kanban_record.js @@ -17,7 +17,21 @@ var widgetRegistry = require('web.widget_registry'); var _t = core._t; var QWeb = core.qweb; -var NB_KANBAN_RECORD_COLORS = 12; +var KANBAN_RECORD_COLORS = [ + _t('No color'), + _t('Red'), + _t('Orange'), + _t('Yellow'), + _t('Light blue'), + _t('Dark purple'), + _t('Salmon pink'), + _t('Medium blue'), + _t('Dark blue'), + _t('Fushia'), + _t('Green'), + _t('Purple'), +]; +var NB_KANBAN_RECORD_COLORS = KANBAN_RECORD_COLORS.length; var KanbanRecord = Widget.extend({ events: { @@ -127,6 +141,17 @@ var KanbanRecord = Widget.extend({ return 0; }, /** + * Computes a color name from value + * + * @private + * @param {number | string} variable + * @returns {integer} the color name + */ + _getColorname: function (variable) { + var colorID = this._getColorID(variable); + return KANBAN_RECORD_COLORS[colorID]; + }, + /** * @private * @param {string} model the name of the model * @param {string} field the name of the field @@ -284,6 +309,7 @@ var KanbanRecord = Widget.extend({ _render: function () { this._replaceElement(this.qweb.render('kanban-box', this.qweb_context)); this.$el.addClass('o_kanban_record').attr("tabindex",0); + this.$el.attr('role', 'article'); this.$el.data('record', this); if (this.$el.hasClass('oe_kanban_global_click') || this.$el.hasClass('oe_kanban_global_click_edit')) { @@ -338,6 +364,7 @@ var KanbanRecord = Widget.extend({ kanban_image: this._getImageURL.bind(this), kanban_color: this._getColorClassname.bind(this), kanban_getcolor: this._getColorID.bind(this), + kanban_getcolorname: this._getColorname.bind(this), kanban_compute_domain: this._computeDomain.bind(this), read_only_mode: this.read_only_mode, record: this.record, @@ -354,8 +381,10 @@ var KanbanRecord = Widget.extend({ _setupColor: function () { var color_field = this.$el.attr('color'); if (color_field && color_field in this.fields) { + var colorHelp = _.str.sprintf(_t("Card color: %s"), this._getColorname(this.recordData[color_field])); var colorClass = this._getColorClassname(this.recordData[color_field]); this.$el.addClass(colorClass); + this.$el.prepend('<span title="' + colorHelp + '" aria-label="' + colorHelp +'" role="img" class="oe_kanban_color_help"/>'); } }, /** diff --git a/addons/web/static/src/js/views/kanban/kanban_record_quick_create.js b/addons/web/static/src/js/views/kanban/kanban_record_quick_create.js index bf7e60b68c3..749938e8b9e 100644 --- a/addons/web/static/src/js/views/kanban/kanban_record_quick_create.js +++ b/addons/web/static/src/js/views/kanban/kanban_record_quick_create.js @@ -232,7 +232,7 @@ var RecordQuickCreate = Widget.extend({ } // ignore clicks in modals - if ($(ev.target).closest('.modal').length) { + if ($(ev.target).closest('[role="dialog"]').length) { return; } diff --git a/addons/web/static/src/js/views/list/list_editable_renderer.js b/addons/web/static/src/js/views/list/list_editable_renderer.js index 07aa8eacb4e..9ec82878e70 100644 --- a/addons/web/static/src/js/views/list/list_editable_renderer.js +++ b/addons/web/static/src/js/views/list/list_editable_renderer.js @@ -527,7 +527,7 @@ ListRenderer.include({ _renderRows: function () { var $rows = this._super(); if (this.addCreateLine) { - var $a = $('<a href="#">').text(_t("Add a line")); + var $a = $('<a href="#" role="button">').text(_t("Add a line")); var $td = $('<td>') .attr('colspan', this._getNumberOfCols()) .addClass('o_field_x2many_list_row_add') @@ -923,9 +923,9 @@ ListRenderer.include({ // ignore clicks in modals, except if the list is in a modal, and the // click is performed in that modal - var $clickModal = $(event.target).closest('.modal'); + var $clickModal = $(event.target).closest('[role="dialog"]'); if ($clickModal.length) { - var $listModal = this.$el.closest('.modal'); + var $listModal = this.$el.closest('[role="dialog"]'); if ($clickModal.prop('id') !== $listModal.prop('id')) { return; } diff --git a/addons/web/static/src/js/views/list/list_renderer.js b/addons/web/static/src/js/views/list/list_renderer.js index bf206eae32c..e84d6687cc9 100644 --- a/addons/web/static/src/js/views/list/list_renderer.js +++ b/addons/web/static/src/js/views/list/list_renderer.js @@ -549,6 +549,10 @@ var ListRenderer = BasicRenderer.extend({ .toggleClass('o-sort-up', isNodeSorted ? order[0].asc : false) .addClass(field.sortable && 'o_column_sortable'); + if (isNodeSorted) { + $th.attr('aria-sort', order[0].asc ? 'ascending': 'descending'); + } + if (field.type === 'float' || field.type === 'integer' || field.type === 'monetary') { $th.css({textAlign: 'right'}); } diff --git a/addons/web/static/src/js/views/pivot/pivot_renderer.js b/addons/web/static/src/js/views/pivot/pivot_renderer.js index b5648d358a9..b3953076161 100644 --- a/addons/web/static/src/js/views/pivot/pivot_renderer.js +++ b/addons/web/static/src/js/views/pivot/pivot_renderer.js @@ -96,6 +96,11 @@ var PivotRenderer = AbstractRenderer.extend({ $cell.data('id', cell.id).data('measure', cell.measure); if (cell.id === this.state.sortedColumn.id && cell.measure === this.state.sortedColumn.measure) { $cell.addClass('o_pivot_measure_row_sorted_' + this.state.sortedColumn.order); + if (this.state.sortedColumn.order == 'asc') { + $cell.attr('aria-sorted', 'ascending'); + } else { + $cell.attr('aria-sorted', 'descending'); + } } } $row.append($cell); diff --git a/addons/web/static/src/js/widgets/change_password.js b/addons/web/static/src/js/widgets/change_password.js index c05fa30408b..b2e4e013335 100644 --- a/addons/web/static/src/js/widgets/change_password.js +++ b/addons/web/static/src/js/widgets/change_password.js @@ -28,7 +28,7 @@ var ChangePassword = AbstractAction.extend({ var $button = self.$('.oe_form_button'); $button.appendTo(this.getParent().$footer); $button.eq(1).click(function () { - self.$el.parents('.modal').modal('hide'); + self.$el.parents('[role="dialog"]').modal('hide'); }); $button.eq(0).click(function () { self._rpc({ diff --git a/addons/web/static/src/js/widgets/debug_manager.js b/addons/web/static/src/js/widgets/debug_manager.js index 4b86b76c36d..4bdc27448a0 100644 --- a/addons/web/static/src/js/widgets/debug_manager.js +++ b/addons/web/static/src/js/widgets/debug_manager.js @@ -848,7 +848,7 @@ if (config.debug) { if (action) { var controller = parent.getCurrentControllerInDialog(); self.debugManager = new DebugManager(self); - var $header = self.$modal.find('.modal-header:first'); + var $header = self.$modal.find('header.modal-header:first'); return self.debugManager.prependTo($header).then(function () { self.debugManager.update('action', action, controller.widget); }); diff --git a/addons/web/static/src/js/widgets/domain_selector_dialog.js b/addons/web/static/src/js/widgets/domain_selector_dialog.js index 46b54089c5f..d0c0030b100 100644 --- a/addons/web/static/src/js/widgets/domain_selector_dialog.js +++ b/addons/web/static/src/js/widgets/domain_selector_dialog.js @@ -43,7 +43,7 @@ return Dialog.extend({ var self = this; this.opened().then(function () { // this restores default modal height (bootstrap) and allows field selector to overflow - self.$el.css('overflow', 'visible').closest('.modal-dialog').css('height', 'auto'); + self.$el.css('overflow', 'visible').closest('[role="dialog"]').css('height', 'auto'); }); return $.when( this._super.apply(this, arguments), diff --git a/addons/web/static/src/scss/ui.scss b/addons/web/static/src/scss/ui.scss index 8911b4f10ab..d88f21f83a1 100644 --- a/addons/web/static/src/scss/ui.scss +++ b/addons/web/static/src/scss/ui.scss @@ -9,3 +9,7 @@ .ui-autocomplete { z-index: $zindex-modal + 1; } + +[aria-hidden="true"], [aria-hidden="1"] { + display: none!important; +} diff --git a/addons/web/static/src/scss/utils.scss b/addons/web/static/src/scss/utils.scss index efb8dce7598..cf04a8d32f8 100644 --- a/addons/web/static/src/scss/utils.scss +++ b/addons/web/static/src/scss/utils.scss @@ -337,6 +337,14 @@ } } } +.oe_kanban_color_help { + bottom: 0px; + left: -1px; + top: 0px; + width: 6px; + position: absolute; + right: auto; +} @mixin o-kanban-slim-col { position: relative; @include o-flex(0, 0, auto); diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 328f1ab93b5..45bd3555d69 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -6,13 +6,13 @@ <div t-name="Loading" class="o_loading"/> <t t-name="WidgetLabel.tooltip"> - <div class="oe_tooltip_string" t-if="widget.string"> + <div class="oe_tooltip_string" t-if="widget.string" role="tooltip"> <t t-esc="widget.string"/> <t t-if="debug and widget.nolabel">(nolabel)</t> </div> - <p t-if="widget.attrs.help || widget.field.help" class="oe_tooltip_help"> + <p t-if="widget.attrs.help || widget.field.help" class="oe_tooltip_help" role="tooltip"> <t t-esc="widget.attrs.help || widget.field.help"/> </p> - <ul t-if="debug" class="oe_tooltip_technical"> + <ul t-if="debug" class="oe_tooltip_technical" role="tooltip"> <li data-item="field" t-if="widget.name"> <span class="oe_tooltip_technical_title">Field:</span> <t t-esc="widget.name"/> @@ -70,7 +70,7 @@ </ul> </t> <t t-name="WidgetButton.tooltip"> - <div class="oe_tooltip_string" t-if="debug || node.attrs.string"> + <div class="oe_tooltip_string" t-if="debug || node.attrs.string" role="tooltip"> <t t-if="debug"> Button <t t-if="node.attrs.string">: </t> @@ -78,10 +78,10 @@ </t> <t t-esc="node.attrs.string"/> </div> - <p t-if="node.attrs.help" class="oe_tooltip_help"> + <p t-if="node.attrs.help" class="oe_tooltip_help" role="tooltip"> <t t-esc="node.attrs.help"/> </p> - <ul t-if="debug" class="oe_tooltip_technical"> + <ul t-if="debug" class="oe_tooltip_technical" role="tooltip"> <li data-item="object"> <span class="oe_tooltip_technical_title">Object:</span> <t t-esc="state.model"/> @@ -115,18 +115,18 @@ </t> <t t-name="Notification"> - <div t-attf-class="o_notification #{widget.className}" t-translation="off"> - <a t-if="widget.sticky" class="fa fa-times o_close" href="#"/> + <div t-attf-class="o_notification #{widget.className}" t-translation="off" role="alertdialog"> + <a t-if="widget.sticky" class="fa fa-times o_close" href="#" title="Close" aria-label="Close"/> <div class="o_notification_title"> - <span t-attf-class="o_icon fa fa-3x #{widget.icon}"/> + <span t-attf-class="o_icon fa fa-3x #{widget.icon}" role="img" t-attf-aria-label="Notification #{widget.name}" t-attf-title="Notification #{widget.name}"/> <t t-raw="widget.title"/> </div> <div class="o_notification_content" t-if="widget.message"><t t-raw="widget.message"/></div> <div t-if="widget.buttons.length" class="o_buttons"> <button t-foreach="widget.buttons" t-as="button" t-attf-class="btn btn-sm #{button.primary ? 'btn-primary' : 'btn-default'}" type="button"> <t t-if="button.icon"> - <i t-if="button.icon.indexOf('fa-') === 0" t-attf-class="fa fa-fw o_button_icon #{button.icon}"/> - <img t-else="" t-att-src="button.icon"/> + <i t-if="button.icon.indexOf('fa-') === 0" t-attf-class="fa fa-fw o_button_icon #{button.icon}" role="img" t-att-aria-label="button.name" t-att-title="button.name"/> + <img t-else="" t-att-src="button.icon" t-att-alt="button.name"/> </t> <span><t t-esc="button.text"/></span> </button> @@ -134,7 +134,7 @@ </div> </t> -<div t-name="CrashManager.warning" class="o_dialog_warning"> +<div t-name="CrashManager.warning" class="o_dialog_warning" role="alert"> <t t-js="d"> var message = (d.message !== undefined) ? d.message : d.error.data.message; d.html_error = context.engine.tools.html_escape(message).replace(/\n/g, '<br/>'); @@ -144,7 +144,7 @@ <div t-name="CrashManager.error" class="o_dialog_error"> <div class="alert alert-warning clearfix" role="alert"> <button class="btn btn-sm btn-primary pull-right ml8 o_clipboard_button"> - <i class="fa fa-clipboard mr8"/>Copy the full error to clipboard + <span class="fa fa-clipboard mr8">Copy the full error to clipboard</span> </button> <p><b>An error occurred</b></p> <p>Please use the copy button to report the error to your support service.</p> @@ -152,13 +152,13 @@ <t t-set="errUID" t-value="_.uniqueId()"/> <button class="btn btn-sm btn-link" t-att-data-target="'#o_error_detail' + errUID" data-toggle="collapse">See details</button> - <div t-att-id="'o_error_detail' + errUID" class="collapse alert alert-danger o_error_detail"> + <div t-att-id="'o_error_detail' + errUID" class="collapse alert alert-danger o_error_detail" role="alert"> <pre><t t-esc="error.message"/></pre> <pre><t t-esc="error.data.debug"/></pre> </div> </div> -<form t-name="ChangePassword" name="change_password_form" method="POST"> +<form t-name="ChangePassword" name="change_password_form" method="POST" aria-atomic="true"> <div class="o_form_view"> <table class="o_group o_inner_group o_label_nowrap"> <tr> @@ -182,23 +182,23 @@ <t t-name="ControlPanel"> <div class="o_control_panel"> - <ol class="breadcrumb"/> - <div class="o_cp_searchview"/> + <ol class="breadcrumb" role="navigation"/> + <div class="o_cp_searchview" role="search"/> <div class="o_cp_left"> - <div class="o_cp_buttons"/> - <div class="o_cp_sidebar"/> + <div class="o_cp_buttons" role="toolbar" aria-label="Control panel toolbar"/> + <aside class="o_cp_sidebar"/> </div> <div class="o_cp_right"> - <div class="btn-group o_search_options"/> - <div class="o_cp_pager"/> - <div class="btn-group btn-group-sm o_cp_switch_buttons"/> + <div class="btn-group o_search_options" role="search"/> + <nav class="o_cp_pager" role="search" aria-label="Pager"/> + <nav class="btn-group btn-group-sm o_cp_switch_buttons" role="toolbar" aria-label="View switcher"/> </div> </div> </t> <t t-name="X2ManyControlPanel"> <div class="o_x2m_control_panel"> - <div class="o_cp_buttons"/> - <div class="o_cp_pager"/> + <nav class="o_cp_buttons" aria-label="Control panel toolbar" role="toolbar"/> + <nav class="o_cp_pager" aria-label="Pager" role="toolbar"/> </div> </t> @@ -206,41 +206,41 @@ <t t-foreach="views" t-as="view"> <button type="button" t-att-accesskey="view.accessKey" t-attf-class="btn btn-icon fa fa-lg #{view.icon} o_cp_switch_#{view.type}" - t-att-aria-label="view.type" - t-att-data-view-type="view.type" t-att-title="view.label" tabindex="-1"/> + t-attf-aria-label="View #{view.type}" + t-att-data-view-type="view.type" t-attf-title="View #{view.type}" tabindex="-1"/> </t> </t> <t t-name="WebClient.DebugManager"> - <li class="o_debug_manager"> - <a href="#" title="Open Developer Tools" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" tabindex="-1"> + <li class="o_debug_manager" role="menuitem"> + <a href="#" title="Open Developer Tools" aria-label="Open Developer Tools" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" tabindex="-1"> <span class="fa fa-bug"/> </a> <ul class="dropdown-menu o_debug_dropdown" role="menu"/> </li> </t> <t t-name="WebClient.DebugManager.Global"> - <li><a href="#" data-action="perform_js_tests">Run JS Tests</a></li> - <li><a href="#" data-action="perform_js_mobile_tests">Run JS Mobile Tests</a></li> - <li><a href="#" data-action="select_view">Open View</a></li> + <li><a role="menuitem" href="#" data-action="perform_js_tests">Run JS Tests</a></li> + <li><a role="menuitem" href="#" data-action="perform_js_mobile_tests">Run JS Mobile Tests</a></li> + <li><a role="menuitem" href="#" data-action="select_view">Open View</a></li> <t t-if="manager._events"> - <li class="divider"/> - <li><a href="#" data-action="show_timelines">Toggle Timelines</a></li> - <li><a href="#" data-action="requests_clear">Clear Events</a></li> + <li class="divider" role="separator"/> + <li><a role="menuitem" href="#" data-action="show_timelines">Toggle Timelines</a></li> + <li><a role="menuitem" href="#" data-action="requests_clear">Clear Events</a></li> </t> - <li class="divider o_debug_leave_section"/> - <li><a href="#" data-action="split_assets">Activate Assets Debugging</a></li> - <li><a href="#" data-action="regenerateAssets">Regenerate Assets Bundles</a></li> - <li><a href="#" data-action="leave_debug_mode">Leave the Developer Tools</a></li> + <li class="divider o_debug_leave_section" role="separator"/> + <li><a role="menuitem" href="#" data-action="split_assets">Activate Assets Debugging</a></li> + <li><a role="menuitem" href="#" data-action="regenerateAssets">Regenerate Assets Bundles</a></li> + <li><a role="menuitem" href="#" data-action="leave_debug_mode">Leave the Developer Tools</a></li> </t> <t t-name="WebClient.DebugManager.Action"> <t t-if="action"> - <li class="divider"/> - <li><a href="#" data-action="edit" t-att-data-model="action.type" t-att-data-id="action.id">Edit Action</a></li> + <li class="divider" role="separator"/> + <li><a role="menuitem" href="#" data-action="edit" t-att-data-model="action.type" t-att-data-id="action.id">Edit Action</a></li> <t t-if="action.res_model"> - <li><a href="#" data-action="get_view_fields">View Fields</a></li> - <li><a href="#" data-action="manage_filters">Manage Filters</a></li> - <li><a href="#" data-action="translate">Technical Translation</a></li> + <li><a role="menuitem" href="#" data-action="get_view_fields">View Fields</a></li> + <li><a role="menuitem" href="#" data-action="manage_filters">Manage Filters</a></li> + <li><a role="menuitem" href="#" data-action="translate">Technical Translation</a></li> </t> </t> </t> @@ -248,7 +248,7 @@ <dl><t t-foreach="fields" t-as="field"> <dt><h4><t t-esc="field"/></h4></dt> <dd> - <dl><ul><li t-foreach="field_value" t-as="attribute"> + <dl><ul role="menu"><li role="menuitem" t-foreach="field_value" t-as="attribute"> <strong><t t-esc="attribute"/></strong>: <t t-esc="attribute_value"/> </li></ul></dl> @@ -257,21 +257,21 @@ </t> <t t-name="WebClient.DebugManager.View"> <t t-if="view"> - <li class="divider"/> + <li role="separator" class="divider"/> <t t-if="view.type === 'form'"> - <li><a href="#" data-action="set_defaults">Set Defaults</a></li> + <li><a role="menuitem" href="#" data-action="set_defaults">Set Defaults</a></li> <t t-if="controller.getSelectedIds().length === 1"> - <li><a href="#" data-action="get_metadata">View Metadata</a></li> + <li><a role="menuitem" href="#" data-action="get_metadata">View Metadata</a></li> </t> </t> - <li><a href="#" data-action="fvg">Fields View Get</a></li> + <li><a role="menuitem" href="#" data-action="fvg">Fields View Get</a></li> <t t-if="can_edit"> <li> - <a href="#" data-action="edit" data-model="ir.ui.view" t-att-data-id="view.fieldsView.view_id"> + <a role="menuitem" href="#" data-action="edit" data-model="ir.ui.view" t-att-data-id="view.fieldsView.view_id"> Edit View: <t t-esc="_.str.capitalize(view.type)"/> </a> </li> - <li t-if="searchview and searchview.$el.is(':visible')"><a href="#" data-action="edit" data-model="ir.ui.view" t-att-data-id="action.searchFieldsView.view_id">Edit SearchView</a></li> + <li t-if="searchview and searchview.$el.is(':visible')"><a role="menuitem" href="#" data-action="edit" data-model="ir.ui.view" t-att-data-id="action.searchFieldsView.view_id">Edit SearchView</a></li> </t> </t> </t> @@ -332,7 +332,7 @@ </a> </t> <ul class="dropdown-menu" role="menu"> - <li t-foreach="widget.items[section.name]" t-as="item" t-att-class="item.classname"> + <li role="menuitem" t-foreach="widget.items[section.name]" t-as="item" t-att-class="item.classname"> <t t-if="section.name == 'files'"> <t t-set="item.title"> <b>Attachment : </b><br/> @@ -351,10 +351,10 @@ </t> <a t-att-title="item.title or None" t-att-data-section="section.name" t-att-data-index="item_index" t-att-href="item.url or '#'"> <t t-raw="item.label"/> - <span t-if="section.name == 'files' and widget.options.editable and !item.callback" class="fa fa-trash-o o_sidebar_delete_attachment" t-att-data-id="item.id" title="Delete this attachment"/> + <span t-if="section.name == 'files' and widget.options.editable and !item.callback" class="fa fa-trash-o o_sidebar_delete_attachment" t-att-data-id="item.id" title="Delete this attachment" role="img" aria-label="Delete this attachment"/> </a> </li> - <li t-if="section.name == 'files' and widget.options.editable" class="o_sidebar_add_attachment"> + <li role="menuitem" t-if="section.name == 'files' and widget.options.editable" class="o_sidebar_add_attachment"> <t t-call="HiddenInputFile"> <t t-set="fileupload_id" t-value="widget.fileuploadId"/> <t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t> @@ -371,7 +371,7 @@ </t> <t t-name="ListView.buttons"> - <div class="o_list_buttons"> + <div class="o_list_buttons" role="toolbar" aria-label="Main actions"> <t t-if="widget.is_action_enabled('create')"> <button type="button" class="btn btn-primary btn-sm o_list_button_add" accesskey="c"> Create @@ -387,7 +387,7 @@ </t> <t t-name="FormView.buttons"> - <div class="o_form_buttons_view"> + <div class="o_form_buttons_view" role="toolbar" aria-label="Main actions"> <button t-if="widget.is_action_enabled('edit')" type="button" class="btn btn-primary btn-sm o_form_button_edit" accesskey="a"> Edit @@ -397,7 +397,7 @@ Create </button> </div> - <div class="o_form_buttons_edit"> + <div class="o_form_buttons_edit" role="toolbar" aria-label="Main actions"> <button type="button" class="btn btn-primary btn-sm o_form_button_save" accesskey="s"> Save @@ -409,7 +409,7 @@ </div> </t> <t t-name="SaveCancelButton.tooltip"> - <div class="oe_tooltip_string"> + <div class="oe_tooltip_string" role="alert"> <div class="tooltip-inner"> Hit ENTER to SAVE<br/> Hit ESCAPE to DISCARD @@ -417,7 +417,7 @@ </div> </t> <t t-name="CreateButton.tooltip"> - <div class="oe_tooltip_string"> + <div class="oe_tooltip_string" role="tooltip"> <div class="tooltip-inner"> Hit ENTER to CREATE<br/> Hit DOWN to navigate to the list bellow @@ -425,14 +425,14 @@ </div> </t> <t t-name="FormButton.tooltip"> - <div class="oe_tooltip_string"> + <div class="oe_tooltip_string" role="tooltip"> <div class="tooltip-inner"> Hit ENTER to <t t-esc="title"></t> </div> </div> </t> -<form t-name="FormView.set_default"> +<form t-name="FormView.set_default" aria-atomic="true"> <t t-set="args" t-value="widget.args"/> <table style="width: 100%"> <tr> @@ -489,25 +489,25 @@ </table> </form> <t t-name="GraphView.buttons"> - <div class="btn-group btn-group-sm" role="group"> + <div class="btn-group btn-group-sm" role="toolbar" aria-label="Main actions"> <button class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> Measures <span class="caret"/> </button> - <ul class="dropdown-menu o_graph_measures_list"> + <ul class="dropdown-menu o_graph_measures_list" role="menu"> <li t-foreach="measures" t-as="measure" t-att-data-field="measure[0]"> - <a href="#"><t t-esc="measure[1].string"/><t t-if="measure[1].type === 'many2one'"> (count)</t></a> + <a role="menuitem" href="#"><t t-esc="measure[1].string"/><t t-if="measure[1].type === 'many2one'"> (count)</t></a> </li> - <li class="divider"></li> - <li data-field="__count__"><a href="#">Count</a></li> + <li role="separator" class="divider"></li> + <li data-field="__count__"><a role="menuitem" href="#">Count</a></li> </ul> </div> - <div class="btn-group btn-group-sm"> - <button class="btn btn-default fa fa-bar-chart-o o_graph_button" title="Bar Chart" data-mode="bar"/> - <button class="btn btn-default fa fa-line-chart o_graph_button" title="Line Chart" data-mode="line"/> - <button class="btn btn-default fa fa-pie-chart o_graph_button" title="Pie Chart" data-mode="pie"/> + <div class="btn-group btn-group-sm" role="toolbar" aria-label="Change graph"> + <button class="btn btn-default fa fa-bar-chart-o o_graph_button" title="Bar Chart" aria-label="Bar Chart" data-mode="bar"/> + <button class="btn btn-default fa fa-line-chart o_graph_button" title="Line Chart" aria-label="Line Chart" data-mode="line"/> + <button class="btn btn-default fa fa-pie-chart o_graph_button" title="Pie Chart" aria-label="Pie Chart" data-mode="pie"/> </div> </t> -<div t-name="GraphView.error" class="o_view_nocontent" > +<div t-name="GraphView.error" class="o_view_nocontent" role="alert"> <div class="o_nocontent_help"> <p class="o_view_nocontent_empty_folder"><t t-esc="title"/></p> <p><t t-esc="description"/></p> @@ -518,51 +518,51 @@ <div class="o_field_selection"/> </div> <t t-name="PivotView.buttons"> - <div class="btn-group btn-group-sm" role="group"> + <div class="btn-group btn-group-sm" role="toolbar" aria-label="Main actions"> <button class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> Measures <span class="caret"/> </button> - <ul class="dropdown-menu o_pivot_measures_list"> + <ul class="dropdown-menu o_pivot_measures_list" role="menu"> <li t-foreach="measures" t-as="measure" t-att-data-field="measure[0]"> - <a href="#"><t t-esc="measure[1].string"/><t t-if="measure[1].type === 'many2one'"> (count)</t></a> + <a role="menuitem" href="#"><t t-esc="measure[1].string"/><t t-if="measure[1].type === 'many2one'"> (count)</t></a> </li> - <li class="divider"></li> - <li data-field="__count"><a href="#">Count</a></li> + <li role="separator" class="divider"></li> + <li data-field="__count"><a role="menuitem" href="#">Count</a></li> </ul> </div> - <div class="btn-group btn-group-sm"> - <button class="btn btn-default fa fa-expand o_pivot_flip_button" title="Flip axis"/> - <button class="btn btn-default fa fa-arrows-alt o_pivot_expand_button" title="Expand all"/> - <button class="btn btn-default fa fa-download o_pivot_download" title="Download xls"/> + <div class="btn-group btn-group-sm" role="toolbar" aria-label="Pivot settings"> + <button class="btn btn-default fa fa-expand o_pivot_flip_button" title="Flip axis" aria-label="Flip axis"/> + <button class="btn btn-default fa fa-arrows-alt o_pivot_expand_button" title="Expand all" aria-label="Expand all"/> + <button class="btn btn-default fa fa-download o_pivot_download" title="Download xls" aria-label="Download xls"/> </div> </t> <t t-name="PivotView.FieldSelection"> <ul class="dropdown-menu o_pivot_field_menu" role="menu"> <t t-foreach="fields" t-as="field"> <t t-if="(field[1].type === 'date') || (field[1].type === 'datetime')"> - <li t-att-data-field="field[0]" t-attf-class="o_inline_dropdown#{field[2] ? ' disabled' : ''}"> + <li role="menuitem" aria-haspopup="true" t-att-data-field="field[0]" t-attf-class="o_inline_dropdown#{field[2] ? ' disabled' : ''}"> <a href="#" class="o_pivot_field_selection"> <t t-esc="field[1].string"/> </a> - <ul class="dropdown-menu"> - <li t-att-data-field="field[0]"><a href="#" t-att-data-interval="'day'">Day</a></li> - <li t-att-data-field="field[0]"><a href="#" t-att-data-interval="'week'">Week</a></li> - <li t-att-data-field="field[0]"><a href="#" t-att-data-interval="'month'">Month</a></li> - <li t-att-data-field="field[0]"><a href="#" t-att-data-interval="'quarter'">Quarter</a></li> - <li t-att-data-field="field[0]"><a href="#" t-att-data-interval="'year'">Year</a></li> + <ul class="dropdown-menu" role="menu"> + <li t-att-data-field="field[0]"><a role="menuitem" href="#" t-att-data-interval="'day'">Day</a></li> + <li t-att-data-field="field[0]"><a role="menuitem" href="#" t-att-data-interval="'week'">Week</a></li> + <li t-att-data-field="field[0]"><a role="menuitem" href="#" t-att-data-interval="'month'">Month</a></li> + <li t-att-data-field="field[0]"><a role="menuitem" href="#" t-att-data-interval="'quarter'">Quarter</a></li> + <li t-att-data-field="field[0]"><a role="menuitem" href="#" t-att-data-interval="'year'">Year</a></li> </ul> </li> </t> <t t-else=""> <li t-att-data-field="field[0]" t-att-class="(field[2] ? 'disabled' : '')"> - <a href="#"><t t-esc="field[1].string"/></a> + <a role="menuitem" href="#"><t t-esc="field[1].string"/></a> </li> </t> </t> </ul> </t> <div t-name="PivotView.nodata"> - <div class="o_view_nocontent"> + <div class="o_view_nocontent" role="alert"> <div class="o_nocontent_help"> <p class="o_view_nocontent_empty_folder"> No data to display @@ -575,15 +575,15 @@ </div> <t t-name="FormSelection"> - <div class="btn-group o_selection"> - <a href="#" data-toggle="dropdown"><span class="o_status"/></a> + <div class="btn-group o_selection" aria-atomic="true"> + <a href="#" data-toggle="dropdown" aria-label="Dropdown menu" title="Dropdown menu"><span class="o_status"/></a> <ul class="dropdown-menu state" role="menu"> </ul> </div> </t> <t t-name="FormSelection.items"> <li t-foreach="states" t-as="rec" t-att-data-value="rec.name"> - <a href="#"> + <a role="menuitem" href="#"> <span t-att-class="'o_status ' + (rec.state_class && rec.state_class || '')"/> <t t-raw="rec.state_name"/> </a> @@ -591,34 +591,34 @@ </t> <t t-name="FieldDomain.content"> <div t-if="hasModel" class="o_field_domain_panel"> - <i class="fa fa-arrow-right"/> + <i class="fa fa-arrow-right" role="img" aria-label="Domain" title="Domain"/> <button t-if="isValid" class="btn btn-xs btn-default o_domain_show_selection_button" type="button"> <t t-esc="nbRecords"/> record(s) </button> - <span t-else="" class="text-warning"><i class="fa fa-exclamation-triangle"/> Invalid domain</span> + <span t-else="" class="text-warning" role="alert"><i class="fa fa-exclamation-triangle" role="img" aria-label="Warning" title="Warning"/> Invalid domain</span> <button t-if="inDialogEdit" class="btn btn-xs btn-primary o_field_domain_dialog_button">Edit Domain</button> </div> <div t-else="">Select a model to add a filter.</div> </t> <t t-name="DomainNode.ControlPanel"> - <div t-if="!widget.readonly && !widget.noControlPanel" class="o_domain_node_control_panel"> - <button class="btn o_domain_delete_node_button"><i class="fa fa-times"/></button> - <button class="btn o_domain_add_node_button"><i class="fa fa-plus-circle"/></button> - <button class="btn o_domain_add_node_button" data-branch="1"><i class="fa fa-ellipsis-h"/></button> + <div t-if="!widget.readonly && !widget.noControlPanel" class="o_domain_node_control_panel" role="toolbar" aria-label="Domain node"> + <button class="btn o_domain_delete_node_button" title="Delete node" aria-label="Delete node"><i class="fa fa-times"/></button> + <button class="btn o_domain_add_node_button" title="Add node" aria-label="Add node"><i class="fa fa-plus-circle"/></button> + <button class="btn o_domain_add_node_button" title="Add branch" aria-label="Add branch" data-branch="1"><i class="fa fa-ellipsis-h"/></button> </div> </t> <t t-name="DomainTree.OperatorSelector"> - <div t-if="!widget.readonly" class="btn-group o_domain_tree_operator_selector"> + <div t-if="!widget.readonly" class="btn-group o_domain_tree_operator_selector" aria-atomic="true"> <button class="btn btn-xs btn-primary o_domain_tree_operator_caret" data-toggle="dropdown"> <t t-if="widget.operator === '&'">All</t> <t t-if="widget.operator === '|'">Any</t> <t t-if="widget.operator === '!'">None</t> </button> - <ul class="dropdown-menu"> - <li><a href="#" data-operator="&">All</a></li> - <li><a href="#" data-operator="|">Any</a></li> + <ul class="dropdown-menu" role="menu"> + <li><a role="menuitem" href="#" data-operator="&">All</a></li> + <li><a role="menuitem" href="#" data-operator="|">Any</a></li> </ul> </div> <strong t-else=""> @@ -627,10 +627,10 @@ <t t-if="widget.operator === '!'">NONE</t> </strong> </t> -<div t-name="DomainSelector" t-attf-class="o_domain_node o_domain_tree o_domain_selector #{widget.readonly ? 'o_read_mode' : 'o_edit_mode'}"> +<div aria-atomic="true" t-name="DomainSelector" t-attf-class="o_domain_node o_domain_tree o_domain_selector #{widget.readonly ? 'o_read_mode' : 'o_edit_mode'}"> <t t-if="widget.children.length === 0"> <span>Match <strong>all records</strong></span> - <button t-if="!widget.readonly" class="btn btn-xs btn-primary o_domain_add_first_node_button"><i class="fa fa-plus"/> Add filter</button> + <button t-if="!widget.readonly" class="btn btn-xs btn-primary o_domain_add_first_node_button"><span class="fa fa-plus"> Add filter</span></button> </t> <t t-else=""> <div class="o_domain_tree_header"> @@ -686,12 +686,12 @@ <t t-if="_.contains(['in', 'not in'], widget.operator)"> <div class="o_domain_leaf_value_input"> <span class="badge" t-foreach="widget.displayValue" t-as="val"> - <t t-esc="val"/> <i class="o_domain_leaf_value_remove_tag_button fa fa-times" t-att-data-value="val"/> + <t t-esc="val"/> <i class="o_domain_leaf_value_remove_tag_button fa fa-times" t-att-data-value="val" role="img" aria-label="Remove tag" title="Remove tag"/> </span> </div> <div class="o_domain_leaf_value_tags"> <input placeholder="Add new value" type="text" class="o_input"/> - <button class="btn btn-xs btn-primary fa fa-plus o_domain_leaf_value_add_tag_button"/> + <button class="btn btn-xs btn-primary fa fa-plus o_domain_leaf_value_add_tag_button" aria-label="Add tag" title="Add tag"/> </div> </t> <t t-else=""> @@ -724,16 +724,16 @@ </t> </div> </div> -<div t-name="ModelFieldSelector" t-attf-class="o_field_selector#{!widget.options.readonly ? ' o_edit_mode o_input' : ''}"> +<div aria-atomic="true" t-name="ModelFieldSelector" t-attf-class="o_field_selector#{!widget.options.readonly ? ' o_edit_mode o_input' : ''}"> <div class="o_field_selector_value" tabindex="0"/> <div class="o_field_selector_controls" tabindex="0"> - <i class="fa fa-exclamation-triangle o_field_selector_warning hidden" title="Invalid field chain"/> + <i role="alert" class="fa fa-exclamation-triangle o_field_selector_warning hidden" title="Invalid field chain" aria-label="Invalid field chain"/> </div> <div t-if="!widget.options.readonly" class="o_field_selector_popover hidden" tabindex="0"> <div class="o_field_selector_popover_header text-center"> - <i class="fa fa-arrow-left o_field_selector_popover_option o_field_selector_prev_page"/> + <i class="fa fa-arrow-left o_field_selector_popover_option o_field_selector_prev_page" title="Previous" role="img" aria-label="Previous"/> <div class="o_field_selector_title"/> - <i class="fa fa-times o_field_selector_popover_option o_field_selector_close"/> + <i class="fa fa-times o_field_selector_popover_option o_field_selector_close" title="Close" role="img" aria-label="Close"/> </div> <div class="o_field_selector_popover_body"> <ul class="o_field_selector_page"/> @@ -746,7 +746,7 @@ <t t-name="ModelFieldSelector.value"> <t t-foreach="chain" t-as="fieldName"> <t t-if="fieldName_index > 0"> - <i class="fa fa-chevron-right"/> + <i class="fa fa-chevron-right" role="img" aria-label="Followed by" title="Followed by"/> </t> <span class="o_field_selector_chain_part"> <t t-set="fieldInfo" t-value="_.findWhere(pages[fieldName_index], {'name': fieldName})"/> @@ -761,13 +761,13 @@ t-att-data-name="line.name"> <t t-esc="line.string"/> <div t-if="debug" class="text-muted o_field_selector_item_title"><t t-esc="line.name"/> (<t t-esc="line.type"/>)</div> - <i t-if="relationToFollow" class="fa fa-chevron-right o_field_selector_relation_icon"/> + <i t-if="relationToFollow" class="fa fa-chevron-right o_field_selector_relation_icon" role="img" aria-label="Relation to follow" title="Relation to follow"/> </li> </t> </ul> <t t-name="web.datepicker"> <t t-set="placeholder" t-value="widget.getParent().node and widget.getParent().node.attrs.placeholder"/> - <div class="o_datepicker"> + <div class="o_datepicker" aria-atomic="true"> <input type="text" class="o_datepicker_input o_input" t-att-name="widget.name" @@ -786,7 +786,7 @@ t-att-id="widget.idForLabel"/> </t> <t t-name="FieldRadio.button"> - <div class="o_radio_item"> + <div class="o_radio_item" aria-atomic="true"> <input type="radio" class="o_radio_input" t-att-checked="checked ? true : undefined" t-att-data-value="value[0]" t-att-data-index="index" t-att-id="id"/> <label class="o_form_label" t-att-for="id"><t t-esc="value[1]"/></label> @@ -804,7 +804,7 @@ <a t-if="!widget.nodeOptions.no_open" class="o_form_uri" href="#"/> <span t-if="widget.nodeOptions.no_open"/> </t> - <div t-if="widget.mode === 'edit'" class="o_field_widget o_field_many2one"> + <div t-if="widget.mode === 'edit'" class="o_field_widget o_field_many2one" aria-atomic="true"> <div class="o_input_dropdown"> <input type="text" class="o_input" t-att-barcode_events="widget.nodeOptions.barcode_events" @@ -812,9 +812,9 @@ t-att-autofocus="widget.attrs.autofocus" t-att-placeholder="widget.attrs.placeholder" t-att-id="widget.idForLabel"/> - <span class="o_dropdown_button" draggable="false"/> + <a role="button" class="o_dropdown_button" draggable="false"/> </div> - <button type="button" t-if="!widget.nodeOptions.no_open" class="fa fa-external-link btn btn-default o_external_button" tabindex="-1" draggable="false"/> + <button type="button" t-if="!widget.nodeOptions.no_open" class="fa fa-external-link btn btn-default o_external_button" tabindex="-1" draggable="false" aria-label="External link" title="External link"/> </div> </t> <t t-name="FieldReference" t-extend="FieldMany2One"> @@ -828,23 +828,29 @@ <t t-name="FieldMany2ManyTag"> <t t-foreach="elements" t-as="el"> <t t-set="color" t-value="el[colorField] || 0"/> - <span t-attf-class="badge dropdown o_tag_color_#{color}" t-att-data-color="color" t-att-data-index="el_index" t-att-data-id="el.id"> - <span class="o_badge_text"><t t-esc="el.display_name"/></span> - <span t-if="!readonly" class="fa fa-times o_delete"/> - </span> + <t t-set="colornames" t-value="['No color', 'Red', 'Orange', 'Yellow', 'Light blue', 'Dark purple', 'Salmon pink', 'Medium blue', 'Dark blue', 'Fushia', 'Green', 'Purple']"/> + <button t-attf-class="badge dropdown o_tag_color_#{color}" t-att-data-color="color" t-att-data-index="el_index" t-att-data-id="el.id" t-attf-title="Tag color: #{colornames[color]}"> + <span class="o_badge_text"><span role="img" t-attf-aria-label="Tag color: #{colornames[color]}"/><t t-esc="el.display_name"/></span> + <a t-if="!readonly" class="fa fa-times o_delete" title="Delete" aria-label="Delete"/> + </button> </t> </t> <t t-name="FieldMany2ManyTag.colorpicker"> <div class="o_colorpicker dropdown-menu tagcolor_dropdown_menu" role="menu"> <ul> - <li t-foreach="11" t-as="color"> - <a href="#" - t-att-data-id="tag_id" - t-att-data-color="color+1" - t-attf-class="o_tag_color_#{color+1}"/> - </li> + <li><a role="menuitem" href="#" t-att-data-id="tag_id" class="o_tag_color_1" data-color="1" title="Red" aria-label="Red"/></li> + <li><a role="menuitem" href="#" t-att-data-id="tag_id" class="o_tag_color_2" data-color="2" title="Orange" aria-label="Orange"/></li> + <li><a role="menuitem" href="#" t-att-data-id="tag_id" class="o_tag_color_3" data-color="3" title="Yellow" aria-label="Yellow"/></li> + <li><a role="menuitem" href="#" t-att-data-id="tag_id" class="o_tag_color_4" data-color="4" title="Light blue" aria-label="Light blue"/></li> + <li><a role="menuitem" href="#" t-att-data-id="tag_id" class="o_tag_color_5" data-color="5" title="Dark purple" aria-label="Dark purple"/></li> + <li><a role="menuitem" href="#" t-att-data-id="tag_id" class="o_tag_color_6" data-color="6" title="Salmon pink" aria-label="Salmon pink"/></li> + <li><a role="menuitem" href="#" t-att-data-id="tag_id" class="o_tag_color_7" data-color="7" title="Medium blue" aria-label="Medium blue"/></li> + <li><a role="menuitem" href="#" t-att-data-id="tag_id" class="o_tag_color_8" data-color="8" title="Dark blue" aria-label="Dark blue"/></li> + <li><a role="menuitem" href="#" t-att-data-id="tag_id" class="o_tag_color_9" data-color="9" title="Fushia" aria-label="Fushia"/></li> + <li><a role="menuitem" href="#" t-att-data-id="tag_id" class="o_tag_color_10" data-color="10" title="Green" aria-label="Green"/></li> + <li><a role="menuitem" href="#" t-att-data-id="tag_id" class="o_tag_color_11" data-color="11" title="Purple" aria-label="Purple"/></li> <li> <!-- checkbox for tag color 0 --> - <div class="o_hide_in_kanban" + <div role="menuitem" class="o_hide_in_kanban" t-att-data-id="tag_id" t-att-data-color="0"> <div class="o_checkbox"> @@ -857,7 +863,7 @@ </div> </t> <t t-name="ProgressBar"> - <div class="o_progressbar"> + <div class="o_progressbar" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"> <div t-if="widget.title" class="o_progressbar_title"><t t-esc="widget.title"/></div><div class="o_progress"> <div class="o_progressbar_complete"/> </div><div class="o_progressbar_value"/> @@ -887,18 +893,26 @@ </t> </t> <t t-name="FieldStatus.content.button"> - <t t-set="disabled" t-value="!clickable || i.selected"/> - <button type="button" t-att-data-value="i.id" t-att-disabled="disabled ? 'disabled' : undefined" - t-attf-class="btn btn-sm o_arrow_button btn-#{i.selected ? 'primary' : 'default'}#{disabled ? ' disabled' : ''}"> - <t t-esc="i.display_name"/> + <t t-set="disabled" t-value="!clickable"/> + <button type="button" t-att-data-value="i.id" disabled="disabled" title="Current state" aria-pressed="true" + class="btn btn-sm o_arrow_button btn-primary disabled" t-if="i.selected" aria-current="step"> + <t t-esc="i.display_name" role="img" t-attf-aria-label="#{i.display_name} is current state"/> + </button> + <button type="button" t-att-data-value="i.id" disabled="disabled" title="Not active state" aria-pressed="false" + class="btn btn-sm o_arrow_button btn-default disabled" t-if="!i.selected and disabled"> + <t t-esc="i.display_name" role="img" t-attf-aria-label="#{i.display_name} is not current state"/> + </button> + <button type="button" t-att-data-value="i.id" title="Not active state, click to change it" aria-pressed="false" + class="btn btn-sm o_arrow_button btn-default" t-if="!i.selected and !disabled"> + <t t-esc="i.display_name" role="img" t-attf-aria-label="Click to change current state to #{i.display_name}"/> </button> </t> <t t-name="FieldBinaryImage"> - <div class="o_field_image"> + <div class="o_field_image" aria-atomic="true"> <t t-if="widget.mode !== 'readonly'"> <div class="o_form_image_controls"> - <span class="fa fa-pencil fa-lg pull-left o_select_file_button" title="Edit"/> - <span class="fa fa-trash-o fa-lg pull-right o_clear_file_button" title="Clear"/> + <button class="fa fa-pencil fa-lg pull-left o_select_file_button" title="Edit" aria-label="Edit"/> + <button class="fa fa-trash-o fa-lg pull-right o_clear_file_button" title="Clear" aria-label="Clear"/> <span class="o_form_binary_progress">Uploading...</span> <t t-call="HiddenInputFile"> @@ -911,6 +925,7 @@ </t> <t t-name="FieldBinaryImage-img"> <img class="img img-responsive" + alt="Binary file" t-att-src='url' t-att-border="widget.readonly ? 0 : 1" t-att-name="widget.name"/> @@ -918,7 +933,7 @@ <t t-name="FieldBinaryFile"> <a t-if="widget.mode === 'readonly'" href="javascript:void(0)" class="o_form_uri"/> - <div t-if="widget.mode !== 'readonly'" class="o_field_binary_file"> + <div t-if="widget.mode !== 'readonly'" class="o_field_binary_file" aria-atomic="true"> <input type="text" class="o_input" readonly="readonly" t-att-name="widget.name" @@ -926,8 +941,8 @@ t-att-autofocus="widget.attrs.autofocus"/> <button type="button" class="btn btn-sm btn-primary o_select_file_button" title="Select">Upload your file</button> - <button type="button" class="btn btn-sm btn-default fa fa-pencil o_select_file_button" title="Select"/> - <button type="button" class="btn btn-sm btn-default fa fa-trash-o o_clear_file_button" title="Clear"/> + <button type="button" class="btn btn-sm btn-default fa fa-pencil o_select_file_button" title="Select" aria-label="Select"/> + <button type="button" class="btn btn-sm btn-default fa fa-trash-o o_clear_file_button" title="Clear" aria-label="Clear"/> <span class="o_form_binary_progress">Uploading...</span> <t t-call="HiddenInputFile"> @@ -938,7 +953,7 @@ </t> <t t-name="HiddenInputFile"> - <div t-attf-class="o_hidden_input_file #{fileupload_class or ''}" t-att-style="fileupload_style"> + <div t-attf-class="o_hidden_input_file #{fileupload_class or ''}" t-att-style="fileupload_style" aria-atomic="true"> <form class="o_form_binary_form" t-att-target="fileupload_id" method="post" enctype="multipart/form-data" t-att-action="fileupload_action || '/web/binary/upload'"> <input type="hidden" name="csrf_token" t-att-value="csrf_token"/> @@ -953,12 +968,12 @@ </t> <t t-name="FieldPdfViewer"> - <div class="o_field_pdfviewer"> - <div t-if="widget.mode !== 'readonly'" class="o_form_pdf_controls mt8"> + <div class="o_field_pdfviewer" aria-atomic="true"> + <div t-if="widget.mode !== 'readonly'" class="o_form_pdf_controls mt8" role="toolbar" aria-label="PDF controls"> <span class="o_form_binary_progress">Uploading...</span> <button type="button" class="btn btn-sm btn-primary o_select_file_button" title="Select">Upload your file</button> - <button class="btn btn-sm btn-default fa fa-pencil o_select_file_button" title="Select" type="button"></button> - <button class="btn btn-sm btn-default fa fa-trash-o o_clear_file_button" title="Clear" type="button"></button> + <button class="btn btn-sm btn-default fa fa-pencil o_select_file_button" title="Select" aria-label="Select" type="button"></button> + <button class="btn btn-sm btn-default fa fa-trash-o o_clear_file_button" title="Clear" aria-label="Clear" type="button"></button> </div> <iframe class="o_pdfview_iframe o_field_pdfviewer"/> <t t-call="HiddenInputPDFFile"> @@ -976,10 +991,10 @@ </t> </t> -<div t-name="FieldBinaryFileUploader" t-attf-class="oe_fileupload #{widget.attrs.class ? widget.attrs.class :''}"> +<div t-name="FieldBinaryFileUploader" t-attf-class="oe_fileupload #{widget.attrs.class ? widget.attrs.class :''}" aria-atomic="true"> <div class="oe_placeholder_files"/> <div t-if="widget.mode !== 'readonly'" class="oe_add"> - <button class="btn btn-default o_attach"><span class="fa fa-paperclip"/> <t t-esc="widget.string"/></button> + <button class="btn btn-default o_attach" title="Attach"><span class="fa fa-paperclip" aria-label="Attach"/> <t t-esc="widget.string"/></button> <t t-call="HiddenInputFile"> <t t-set="fileupload_id" t-value="widget.fileupload_id"/> <t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t> @@ -990,7 +1005,7 @@ </t> </div> </div> -<div t-name="FieldBinaryFileUploader.files" class="oe_attachments"> +<div t-name="FieldBinaryFileUploader.files" class="oe_attachments" aria-atomic="true"> <t t-if="widget.mode === 'readonly'"> <div t-foreach="widget.value.data" t-as="file"> <a target="_blank" t-att-href="widget.metadata[file.id].url" t-attf-title="#{(file.data.name || file.data.filename) + (file.data.date?' \n('+file.data.date+')':'' )}"><t t-raw="file.data.name || file.data.filename"/></a> @@ -1000,19 +1015,20 @@ <div t-foreach="widget.value.data" t-as="file" class="oe_attachment"> <t t-if="!file.data.upload"> <div> - <a href="#" class="fa fa-times pull-right oe_delete" title="Delete this file" t-att-data-id="file.data.id"/> + <a href="#" class="fa fa-times pull-right oe_delete" title="Delete this file" aria-label="Delete this file" t-att-data-id="file.data.id"/> <t t-raw="file.data.name || file.data.filename"/> </div> <a class="o_image" target="_blank" t-att-href="widget.metadata[file.id] ? widget.metadata[file.id].url : false" t-att-title="file.data.name" + t-att-aria-label="file.data.name" t-att-data-mimetype="file.data.mimetype" t-attf-data-src="/web/image/#{file.data.id}/100x80"/> </t> </div> <div t-foreach="widget.uploadingFiles" t-as="file" class="oe_attachment"> <div>Uploading...</div> - <a t-att-title="file.name" t-att-name="file.name" class="o_image"> - <i class="fa fa-spinner fa-spin fa-5x fa-fw"></i> + <a t-att-title="file.name" t-att-aria-label="file.name" t-att-name="file.name" class="o_image"> + <i class="fa fa-spinner fa-spin fa-5x fa-fw" role="img" aria-label="Loading, please wait..." title="Loading, please wait..."></i> </a> <div><t t-esc="file.name"/></div> </div> @@ -1087,12 +1103,12 @@ -<div t-name="SearchView" class="o_searchview"> - <span class="o_searchview_more fa" title="Advanced Search..."/> +<div t-name="SearchView" class="o_searchview" role="search" aria-autocomplete="list"> + <span class="o_searchview_more fa" title="Advanced Search..." role="img" aria-label="Advanced Search..."/> <div class="o_searchview_input_container"/> </div> <t t-name="SearchViewMobile"> - <div class="o_searchview"> + <div class="o_searchview" role="search" aria-autocomplete="list"> <button class="o_enable_searchview btn btn-sm fa fa-search"/> <div class="o_mobile_search o_hidden"> <div class="o_mobile_search_header"> @@ -1109,14 +1125,14 @@ </div> </t> -<input t-name="SearchView.InputView" type="text" class="o_searchview_input" accesskey="Q" placeholder="Search..."/> -<div t-name="SearchView.FacetView" tabindex="0" class="o_searchview_facet"> +<input t-name="SearchView.InputView" type="text" class="o_searchview_input" accesskey="Q" placeholder="Search..." role="searchbox" aria-haspopup="true"/> +<div t-name="SearchView.FacetView" tabindex="0" class="o_searchview_facet" role="img" aria-label="search"> <span t-if="widget.model.has('icon')" t-att-class="'fa ' + widget.model.get('icon') + ' o_searchview_facet_label'"/> <span t-if="!widget.model.has('icon')" class="o_searchview_facet_label"> <t t-esc="widget.model.get('category')"/> </span> <div class="o_facet_values"/> - <div class="fa fa-sm fa-remove o_facet_remove"/> + <div class="fa fa-sm fa-remove o_facet_remove" role="img" aria-label="Remove" title="Remove"/> </div> <span t-name="SearchView.FacetView.Value"> <t t-esc="widget.model.get('label') + (widget.intervalLabel ? (': ' + widget.intervalLabel) : '')"/> @@ -1129,7 +1145,7 @@ <li t-foreach="widget.filters" t-as="filter" t-if="!filter.visible || filter.visible()" t-att-title="filter.attrs.string ? filter.attrs.help : undefined" t-att-data-index="filter_index"> - <a href="#"><t t-esc="filter.attrs.string or filter.attrs.help or filter.attrs.name or 'Ω'"/></a> + <a role="menuitem" href="#"><t t-esc="filter.attrs.string or filter.attrs.help or filter.attrs.name or 'Ω'"/></a> </li> </t> <t t-name="SearchView.field"> @@ -1192,7 +1208,7 @@ </div> </t> <t t-name="SearchView.extended_search.proposition"> - <li class="o_filter_condition"> + <li role="menuitem" class="o_filter_condition"> <span class="o_or_filter">or</span> <span> <select class="o_input o_searchview_extended_prop_field"> @@ -1203,7 +1219,7 @@ </option> </t> </select> - <span class="o_searchview_extended_delete_prop fa fa-trash-o"/> + <span class="o_searchview_extended_delete_prop fa fa-trash-o" role="img" aria-label="Delete" title="Delete"/> </span> <select class="o_input o_searchview_extended_prop_op"/> <span class="o_searchview_extended_prop_value"/> @@ -1225,32 +1241,32 @@ </t> <div t-name="SearchView.FavoriteMenu" class="btn-group o_dropdown"> - <button class="o_dropdown_toggler_btn btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false" tabindex="-1"> + <button class="o_dropdown_toggler_btn btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false" tabindex="-1" aria-label="Favorites" title="Favorites"> <span class="fa fa-star"/> Favorites <span t-attf-class="#{widget.isMobile ? 'fa fa-chevron-right pull-right mt4' : 'caret'}"/> </button> <ul class="dropdown-menu o_favorites_menu" role="menu"> <li class="divider user_filter"/> <li class="divider shared_filter"/> <li class="o_save_search o_closed_menu"> - <a href="#">Save current search</a> + <a role="menuitem" href="#">Save current search</a> </li> - <li class="o_save_name"> + <li role="menuitem" class="o_save_name"> <input type="text"></input> </li> - <li class="o_save_name"> + <li role="menuitem" class="o_save_name"> <span><div class="o_checkbox"><input type="checkbox"/><span/></div> Use by default</span> </li> - <li class="o_save_name"> - <span><div class="o_checkbox"><input type="checkbox"/><span/></div> Share with all users </span><span class="fa fa-users"/> + <li role="menuitem" class="o_save_name"> + <span><div class="o_checkbox"><input type="checkbox"/><span/></div> Share with all users </span><span class="fa fa-users" role="img" aria-label="Users" title="Users"/> </li> <li class="o_save_name"> - <button type="button" class="btn btn-primary btn-sm">Save</button> + <button role="menuitem" type="button" class="btn btn-primary btn-sm">Save</button> </li> </ul> </div> <div t-name="ExportDialog" class="o_export"> - <p> + <p role="status"> This wizard will export all data that matches the current search criteria to a CSV file. You can export all data or only the fields that can be reimported after modification. </p> @@ -1293,16 +1309,16 @@ </div> </div> <p t-name="Export.DomainMessage"> - <strong t-if="!record.ids_to_export">Please pay attention that all records matching your search filter will be exported. Not only the selected ids.</strong> - <strong t-if="record.ids_to_export">Please note that only the selected ids will be exported.</strong> + <strong t-if="!record.ids_to_export" role="alert">Please pay attention that all records matching your search filter will be exported. Not only the selected ids.</strong> + <strong t-if="record.ids_to_export" role="alert">Please note that only the selected ids will be exported.</strong> </p> <div t-name="Export.TreeItems" t-foreach="fields" t-as="field" t-att-data-id="field.id" class="o_export_tree_item" - tabindex="-1"> <!-- tabindex make the div focusable --> + tabindex="-1" role="treeitem"> <!-- tabindex make the div focusable --> <span t-if="field.children && (field.id).split('/').length != 3" - class="o_expand_parent fa fa-plus"/> + class="o_expand_parent fa fa-plus" role="img" aria-label="Expand parents" title="Expand parents"/> <span class="o_tree_column" t-att-title="debug and field.id or None"><t t-esc="field.string"/></span> </div> <t t-name="Export.SaveList"> @@ -1322,14 +1338,14 @@ <t t-name="Throbber"> <div> <div class="oe_blockui_spin" style="height: 50px"> - <img src="/web/static/src/img/spin.png" style="animation: fa-spin 1s infinite steps(12);"/> + <img src="/web/static/src/img/spin.png" style="animation: fa-spin 1s infinite steps(12);" alt="Loading..."/> </div> <br /> <div class="oe_throbber_message" style="color:white"></div> </div> </t> <t t-name="Spinner"> - <div class="o_spinner"><i class="fa fa-spinner fa-spin"/></div> + <div class="o_spinner"><i class="fa fa-spinner fa-spin" role="img" aria-label="Loading, please wait..." title="Loading, please wait..."/></div> </t> <t t-name="M2ODialog"> <div> @@ -1338,7 +1354,7 @@ </div> </t> <t t-name="FieldMany2ManyCheckBoxes"> - <div> + <div aria-atomic="true"> <div t-foreach="widget.m2mValues" t-as="m2m_value"> <t t-set="id_for_label" t-value="'o_many2many_checkbox_' + _.uniqueId()"/> <div class="o_checkbox"> @@ -1354,7 +1370,7 @@ <span class="o_stat_text"><t t-esc="text"/></span> </t> <t t-name="toggle_button"> - <button type="button" class="o_icon_button" t-att-title="widget.string" t-att-aria-label="widget.string"> + <button type="button" class="o_icon_button" t-att-title="widget.string" t-att-aria-label="widget.string" aria-pressed="false"> <i class="fa fa-circle" t-att-title="widget.string"/> </button> </t> @@ -1363,14 +1379,14 @@ <span class="o_pager_counter"> <span class="o_pager_value"></span> / <span class="o_pager_limit"></span> </span> - <span class="btn-group btn-group-sm"> + <span class="btn-group btn-group-sm" aria-atomic="true"> <!-- accesskeys not wanted in X2Many widgets --> <t t-if="widget.options.withAccessKey"> <t t-set="att_prev" t-value="{'accesskey': 'p'}" /> <t t-set="att_next" t-value="{'accesskey': 'n'}" /> </t> - <button type="button" class="fa fa-chevron-left btn btn-icon o_pager_previous" t-att="att_prev" aria-label="Previous" tabindex="-1"/> - <button type="button" class="fa fa-chevron-right btn btn-icon o_pager_next" t-att="att_next" aria-label="Next" tabindex="-1"/> + <button type="button" class="fa fa-chevron-left btn btn-icon o_pager_previous" t-att="att_prev" aria-label="Previous" title="Next" tabindex="-1"/> + <button type="button" class="fa fa-chevron-right btn btn-icon o_pager_next" t-att="att_next" aria-label="Next" title="Next" tabindex="-1"/> </span> </div> @@ -1381,15 +1397,15 @@ </t> <t t-name="notification-box"> - <div t-attf-class="o_notification_box mb0 alert alert-dismissible alert-{{type}}" role="alert"> + <div t-attf-class="o_notification_box mb0 alert alert-dismissible alert-{{type}}" role="alertdialog"> <button type="button" class="close" data-dismiss="alert" aria-label="Close"> - <span aria-hidden="true" class="fa fa-times"></span> + <span class="fa fa-times"></span> </button> </div> </t> <t t-name="translation-alert"> - <div> + <div role="alertdialog"> Please update translations of : <t t-foreach="fields" t-as="field"> <strong><a class="oe_field_translate" t-att-name="field.name" href="#"><t t-esc="field.string"/><t t-if="!field_last">, </t></a></strong> @@ -1400,7 +1416,7 @@ <t t-name="UserMenu"> <li class="o_user_menu"> <a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" href="#"> - <img class="img-circle oe_topbar_avatar" t-att-src="_s + '/web/static/src/img/user_menu_avatar.png'"/> + <img class="img-circle oe_topbar_avatar" t-att-src="_s + '/web/static/src/img/user_menu_avatar.png'" alt="Avatar"/> <span class="oe_topbar_name"/> </a> <ul class="dropdown-menu" role="menu"> @@ -1410,17 +1426,17 @@ </t> <t t-name="UserMenu.Actions"> - <li><a href="#" data-menu="documentation">Documentation</a></li> - <li><a href="#" data-menu="support">Support</a></li> - <li class="divider"/> - <li><a href="#" data-menu="settings">Preferences</a></li> - <li><a href="#" data-menu="account">My Odoo.com account</a></li> - <li><a href="#" data-menu="logout">Log out</a></li> + <li><a role="menuitem" href="#" data-menu="documentation">Documentation</a></li> + <li><a role="menuitem" href="#" data-menu="support">Support</a></li> + <li role="separator" class="divider"/> + <li><a role="menuitem" href="#" data-menu="settings">Preferences</a></li> + <li><a role="menuitem" href="#" data-menu="account">My Odoo.com account</a></li> + <li><a role="menuitem" href="#" data-menu="logout">Log out</a></li> </t> <t t-name="SwitchCompanyMenu"> <li class="o_switch_company_menu"> - <a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" href="#"> + <a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" href="#" aria-label="Dropdown menu" title="Dropdown menu"> <span t-attf-class="#{widget.isMobile ? 'fa fa-building-o' : 'oe_topbar_name'}"/> <span class="caret"/> </a> <ul class="dropdown-menu" role="menu"/> @@ -1428,35 +1444,35 @@ </t> <t t-name="EnterpriseUpgrade"> - <div class="row"> + <div class="row" role="status"> <div class="col-xs-6"> Get this feature and much more with Odoo Enterprise! <ul class="list-unstyled"> - <li><i class="fa fa-check"></i> Access to all Enterprise Apps</li> - <li><i class="fa fa-check"></i> New design</li> - <li><i class="fa fa-check"></i> Mobile support</li> - <li><i class="fa fa-check"></i> Upgrade to future versions</li> - <li><i class="fa fa-check"></i> Bugfixes guarantee</li> - <li><a href="http://www.odoo.com/editions" target="_blank"><i class="fa fa-plus"></i> And more</a></li> + <li><span class="fa fa-check"> Access to all Enterprise Apps</span></li> + <li><span class="fa fa-check"> New design</span></li> + <li><span class="fa fa-check"> Mobile support</span></li> + <li><span class="fa fa-check"> Upgrade to future versions</span></li> + <li><span class="fa fa-check"> Bugfixes guarantee</span></li> + <li><a href="http://www.odoo.com/editions" target="_blank"><span class="fa fa-plus"> And more</span></a></li> </ul> </div> <div class="col-xs-6"> - <img class="img-responsive" t-att-src='_s + "/web/static/src/img/enterprise_upgrade.jpg"' draggable="false"/> + <img class="img-responsive" t-att-src='_s + "/web/static/src/img/enterprise_upgrade.jpg"' draggable="false" alt="Upgrade to enterprise"/> </div> </div> </t> <t t-name="BaseSetting.Tabs"> <t t-foreach="tabItems" t-as="tab"> - <div class="tab" t-attf-data-key="#{tab.key}"> + <div class="tab" t-attf-data-key="#{tab.key}" role="tab"> <div class="icon hidden-xs" t-attf-style="background : url('#{imgurl}') no-repeat center;background-size:contain;"/> <span class="app_name"><t t-esc="tab.string"/></span> </div> </t> </t> <t t-name="BaseSetting.SearchHeader"> - <div class="settingSearchHeader o_hidden"> - <img class="icon" t-att-src="imgurl"></img> + <div class="settingSearchHeader o_hidden" role="search"> + <img class="icon" t-att-src="imgurl" alt="Search"></img> <span class="appName"><t t-esc="string"/></span> </div> </t> diff --git a/addons/web/static/src/xml/dialog.xml b/addons/web/static/src/xml/dialog.xml index 68c3ab3f2e3..eb1a67ee98d 100644 --- a/addons/web/static/src/xml/dialog.xml +++ b/addons/web/static/src/xml/dialog.xml @@ -3,15 +3,15 @@ <!-- These templates are accessible in backend and frontend --> -<div t-name="Dialog" t-attf-class="modal#{technical ? ' o_technical_modal' : ''}" tabindex="-1" data-backdrop="static" role="dialog" aria-hidden="true" t-att-id="_.uniqueId('modal_')"> +<div role="dialog" t-name="Dialog" t-attf-class="modal#{technical ? ' o_technical_modal' : ''}" tabindex="-1" data-backdrop="static" t-att-id="_.uniqueId('modal_')"> <div class="modal-dialog"> <div class="modal-content"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-hidden="true" tabindex="-1">×</button> + <header class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-label="Close" tabindex="-1">×</button> <h4 class="modal-title"><t t-raw="title"/><span class="o_subtitle text-muted small"><t t-esc="subtitle"/></span></h4> - </div> - <div class="modal-body"/> - <div class="modal-footer"/> + </header> + <main class="modal-body"/> + <footer class="modal-footer"/> </div> </div> </div> diff --git a/addons/web/static/src/xml/kanban.xml b/addons/web/static/src/xml/kanban.xml index 67514072c95..4b62f52cda8 100644 --- a/addons/web/static/src/xml/kanban.xml +++ b/addons/web/static/src/xml/kanban.xml @@ -9,18 +9,19 @@ </t> <t t-name="KanbanView.Group"> - <div t-attf-class="o_kanban_group#{widget.data_records.length == 0 ? ' o_kanban_no_records' : ''}" t-att-data-id="widget.id or widget.db_id"> + <div t-attf-class="o_kanban_group#{widget.data_records.length == 0 ? ' o_kanban_no_records' : ''}" t-att-data-id="widget.id or widget.db_id" + role="feed" t-attf-aria-labelledby="kanban_header_#{widget.id or widget.db_id}"> <div class="o_kanban_header"> <div class="o_kanban_header_title" t-att-title="widget.data_records.length + ' records'" data-delay="500"> - <span class="o_column_title"><t t-esc="widget.title"/></span> - <span class="o_column_unfold"><i class="fa fa-arrows-h"/></span> + <span t-attf-id="#kanban_header_#{widget.id or widget.db_id}" class="o_column_title"><t t-esc="widget.title"/></span> + <span class="o_column_unfold"><i class="fa fa-arrows-h" role="img" aria-label="Unfold" title="Unfold"/></span> <span class="o_kanban_config dropdown"> - <a class="dropdown-toggle" data-toggle="dropdown" href="#"><i class="fa fa-gear"/></a> + <a class="dropdown-toggle" data-toggle="dropdown" href="#"><i class="fa fa-gear" role="img" aria-label="Settings" title="Settings"/></a> <ul class="dropdown-menu" role="menu"> - <li><a class="o_kanban_toggle_fold" href="#">Fold</a></li> + <li><a role="menuitem" class="o_kanban_toggle_fold" href="#">Fold</a></li> <t t-if="widget.grouped_by_m2o"> - <li t-if="widget.editable and widget.id"><a class="o_column_edit" href="#">Edit Stage</a></li> - <li t-if="widget.deletable and widget.id"><a class="o_column_delete" href="#">Delete</a></li> + <li t-if="widget.editable and widget.id"><a role="menuitem" class="o_column_edit" href="#">Edit Stage</a></li> + <li t-if="widget.deletable and widget.id"><a role="menuitem" class="o_column_delete" href="#">Delete</a></li> </t> <t t-if="widget.has_active_field"> <li><a class="o_column_archive_records" href="#">Archive All</a></li> @@ -28,7 +29,7 @@ </t> </ul> </span> - <span t-if="widget.quick_create" class="o_kanban_quick_add"><i class="fa fa-plus"/></span> + <span t-if="widget.quick_create" class="o_kanban_quick_add"><i class="fa fa-plus" role="img" aria-label="Quick add" title="Quick add"/></span> </div> </div> <div t-if="widget.remaining > 0" class="o_kanban_load_more"> @@ -44,7 +45,7 @@ <t t-name="KanbanView.ColumnQuickCreate"> <div class="o_column_quick_create"> <div class="o_quick_create_folded"> - <span class="o_kanban_add_column"><i class="fa fa-plus"/></span> + <span class="o_kanban_add_column"><i class="fa fa-plus" role="img" aria-label="Add column" title="Add column"/></span> <span class="o_kanban_title">Add a Column</span> </div> <div class="o_quick_create_unfolded"> @@ -56,7 +57,7 @@ </span> </div> <t t-if="widget.examples"> - <span class="btn-link o_kanban_examples">Examples</span> + <a href="#" role="button" class="btn-link o_kanban_examples">Examples</a> </t> <span class="o_discard_msg text-muted pull-right">Esc to discard</span> </div> @@ -76,9 +77,18 @@ </t> <t t-name="KanbanColorPicker"> - <li t-foreach="12" t-as="color"> - <a href="#" t-att-data-color="color_index" t-attf-class="oe_kanban_color_#{color}"/> - </li> + <li><a role="menuitem" href="#" data-color="0" class="oe_kanban_color_0" title="No color" aria-label="No color"/></li> + <li><a role="menuitem" href="#" data-color="1" class="oe_kanban_color_1" title="Red" aria-label="Red"/></li> + <li><a role="menuitem" href="#" data-color="2" class="oe_kanban_color_2" title="Orange" aria-label="Orange"/></li> + <li><a role="menuitem" href="#" data-color="3" class="oe_kanban_color_3" title="Yellow" aria-label="Yellow"/></li> + <li><a role="menuitem" href="#" data-color="4" class="oe_kanban_color_4" title="Light blue" aria-label="Light blue"/></li> + <li><a role="menuitem" href="#" data-color="5" class="oe_kanban_color_5" title="Dark purple" aria-label="Dark purple"/></li> + <li><a role="menuitem" href="#" data-color="6" class="oe_kanban_color_6" title="Salmon pink" aria-label="Salmon pink"/></li> + <li><a role="menuitem" href="#" data-color="7" class="oe_kanban_color_7" title="Medium blue" aria-label="Medium blue"/></li> + <li><a role="menuitem" href="#" data-color="8" class="oe_kanban_color_8" title="Dark blue" aria-label="Dark blue"/></li> + <li><a role="menuitem" href="#" data-color="9" class="oe_kanban_color_9" title="Fushia" aria-label="Fushia"/></li> + <li><a role="menuitem" href="#" data-color="10" class="oe_kanban_color_10" title="Green" aria-label="Green"/></li> + <li><a role="menuitem" href="#" data-color="11" class="oe_kanban_color_11" title="Purple" aria-label="Purple"/></li> </t> <t t-name="GraphCustomTooltip"> @@ -103,6 +113,7 @@ <div t-attf-class="progress-bar transition-off bg-#{color_value}-full#{count ? ' o_bar_has_records' : ''}#{widget.activeFilter ? ' active progress-bar-striped' : ''}" t-att-data-filter="color" t-attf-data-original-title="#{count} #{color}" + aria-valuemin="0" aria-valuemax="100" t-att-aria-valuenow="count*100" role="progressbar" t-attf-style="width: #{count ? (count * 100 / widget.groupCount) : 0}%;"/> </t> </div> @@ -116,7 +127,7 @@ <ul class="nav nav-pills nav-stacked"> <t t-foreach="examples" t-as="example"> <li t-att-class="example_index == 0 and 'active' or None"> - <a data-toggle="tab" t-attf-href="#example_#{example_index}"> <t t-esc="example.name"/> </a> + <a t-attf-aria-controls="example_#{example_index}" data-toggle="tab" role="tab" t-attf-href="#example_#{example_index}"> <t t-esc="example.name"/> </a> </li> </t> </ul> @@ -124,7 +135,7 @@ <div class="o_kanban_examples_dialog_content"> <div class="tab-content"> <t t-foreach="examples" t-as="example"> - <div t-attf-id="example_#{example_index}" t-attf-class="tab-pane fade #{example_index == 0 and 'active in' or ''}"> + <div role="tabpanel" t-attf-id="example_#{example_index}" t-attf-class="tab-pane fade #{example_index == 0 and 'active in' or ''}"> <div t-if="example.description" class="o_kanban_examples_description"> <t t-raw="example.description"/> <!-- description is supposed to be properly escaped --> </div> @@ -147,7 +158,7 @@ <div class="o_kanban_examples_ghost"> <div class="o_ghost_content"/> <div class="o_ghost_content o_ghost_tag"/> - <img class="pull-right o_ghost_avatar" src="/base/static/img/avatar.png"/> + <img class="pull-right o_ghost_avatar" src="/base/static/img/avatar.png" alt="Avatar"/> </div> </t> diff --git a/addons/web/static/src/xml/web_calendar.xml b/addons/web/static/src/xml/web_calendar.xml index 7f65ed93a08..41f772cd52f 100644 --- a/addons/web/static/src/xml/web_calendar.xml +++ b/addons/web/static/src/xml/web_calendar.xml @@ -1,7 +1,7 @@ <template> <div t-name="CalendarView" class="o_calendar_container"> <div class="o_calendar_view"> - <div class="o_calendar_buttons"/> + <div class="o_calendar_buttons" role="toolbar" aria-label="Calendar toolbar"/> <div class="o_calendar_widget" /> </div> <div class="o_calendar_sidebar_container hidden-xs"> @@ -44,17 +44,17 @@ <input type="checkbox" name="selection" t-att-checked="(filter.active ? true : undefined)"/><span/> </div> <t t-if="filter.value == 'all'"> - <span><i class="fa fa-users fa-fw o_cal_avatar"/></span> + <span><i class="fa fa-users fa-fw o_cal_avatar" role="img" aria-label="Avatar" title="Avatar"/></span> </t> <t t-if="widget.avatar_field && (filter.value != 'all')"> - <img t-attf-src="/web/image/#{widget.avatar_model}/#{filter.value}/#{widget.avatar_field}" class="o_cal_avatar"/> + <img t-attf-src="/web/image/#{widget.avatar_model}/#{filter.value}/#{widget.avatar_field}" class="o_cal_avatar" alt="Avatar"/> </t> <t t-set="color" t-value="widget.getColor(filter.color_index)"/> <span t-if="typeof color === 'number'" t-attf-class="color_filter o_underline_color_#{widget.getColor(filter.color_index)}"><t t-esc="filter.label"/></span> <span t-elif="color" t-attf-style="border-bottom: 4px solid #{color};"><t t-esc="filter.label"/></span> <span t-else=""><t t-esc="filter.label"/></span> <t t-if="filter.id"> - <span class="o_remove fa fa-times" title="Remove this favorite from the list"/> + <span class="o_remove fa fa-times" title="Remove this favorite from the list" role="img" aria-label="Remove this favorite from the list"/> </t> </div> </div> @@ -64,9 +64,9 @@ <t t-name="CalendarView.buttons"> <div class="o_calendar_buttons"> <t t-if="!isMobile"> - <button class="o_calendar_button_prev btn btn-sm btn-primary"><span class="fa fa-arrow-left"/></button> + <button class="o_calendar_button_prev btn btn-sm btn-primary" aria-label="Previous" title="Previous"><span class="fa fa-arrow-left"/></button> <button class="o_calendar_button_today btn btn-sm btn-primary">Today</button> - <button class="o_calendar_button_next btn btn-sm btn-primary"><span class="fa fa-arrow-right"/></button> + <button class="o_calendar_button_next btn btn-sm btn-primary" aria-label="Next" title="Next"><span class="fa fa-arrow-right"/></button> </t> <div class="btn-group btn-group-sm"> <button type="button" class="o_calendar_button_day btn btn-sm btn-default">Day</button> @@ -78,15 +78,15 @@ <t t-name="CalendarView.TodayButtonMobile"> <span class="fa-stack o_calendar_button_today"> - <i class="fa fa-calendar-o fa-stack-2x"></i> + <i class="fa fa-calendar-o fa-stack-2x" role="img" aria-label="Today" title="Today"></i> <strong class="o_calendar_text fa-stack-1x"><t t-esc="moment().date()"/></strong> </span> </t> - <div t-name="CalendarView.quick_create" class="o_calendar_quick_create"> + <main t-name="CalendarView.quick_create" class="o_calendar_quick_create"> <div class="form-group"> <label for='name' class='control-label'>Summary:</label> <input type='text' name='name' class="o_input" t-att-value="widget.dataTemplate.name or None"/> </div> - </div> + </main> </template> diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js index b0a90173363..07febe83234 100644 --- a/addons/web/static/tests/chrome/action_manager_tests.js +++ b/addons/web/static/tests/chrome/action_manager_tests.js @@ -2624,12 +2624,12 @@ QUnit.module('ActionManager', { // go back to kanban view $('.o_control_panel .breadcrumb li:first a').click(); - assert.strictEqual($('.modal .modal-body').text(), + assert.strictEqual($('main.modal-body:first').text(), "The record has been modified, your changes will be discarded. Do you want to proceed?", "should display a modal dialog to confirm discard action"); // cancel - $('.modal .modal-footer button.btn-default').click(); + $('footer.modal-footer button.btn-default').click(); assert.strictEqual(actionManager.$('.o_form_view').length, 1, "should still be in form view"); @@ -2638,7 +2638,7 @@ QUnit.module('ActionManager', { $('.o_control_panel .breadcrumb li:first a').click(); // confirm discard - $('.modal .modal-footer button.btn-primary').click(); + $('footer.modal-footer button.btn-primary').click(); assert.strictEqual(actionManager.$('.o_form_view').length, 0, "should no longer be in form view"); @@ -3001,8 +3001,8 @@ QUnit.module('ActionManager', { assert.strictEqual($('.o_technical_modal .o_form_view').length, 1, "should have rendered a form view in a modal"); - assert.ok($('.o_technical_modal .modal-body').hasClass('o_act_window'), - "modal-body element should have classname 'o_act_window'"); + assert.ok($('.o_technical_modal main').hasClass('o_act_window'), + "dialog main element should have classname 'o_act_window'"); assert.ok($('.o_technical_modal .o_form_view').hasClass('o_form_editable'), "form view should be in edit mode"); @@ -3032,11 +3032,11 @@ QUnit.module('ActionManager', { }); actionManager.doAction(5); - assert.strictEqual($('.o_technical_modal .modal-body button.infooter').length, 0, + assert.strictEqual($('.o_technical_modal main button.infooter').length, 0, "the button should not be in the body"); - assert.strictEqual($('.o_technical_modal .modal-footer button.infooter').length, 1, + assert.strictEqual($('.o_technical_modal footer button.infooter').length, 1, "the button should be in the footer"); - assert.strictEqual($('.o_technical_modal .modal-footer button').length, 1, + assert.strictEqual($('.o_technical_modal footer button').length, 1, "the modal footer should only contain one button"); actionManager.destroy(); @@ -3066,7 +3066,7 @@ QUnit.module('ActionManager', { type: 'ir.actions.client', }); - assert.strictEqual($('.modal .o_test').length, 1, + assert.strictEqual($('[role="dialog"] .o_test').length, 1, "should have rendered the client action in a dialog"); assert.verifySteps(['on_attach_callback']); diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js index 9cda103eedd..e285626f763 100644 --- a/addons/web/static/tests/fields/basic_fields_tests.js +++ b/addons/web/static/tests/fields/basic_fields_tests.js @@ -1842,7 +1842,7 @@ QUnit.module('basic_fields', { // Actual flow: click on an element of the m2m to get its form view form.$('tbody td:contains(gold)').click(); - assert.strictEqual($('.modal-dialog').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, 'The modal should have opened'); assert.verifySteps([ "The view's image should have been fetched", @@ -2570,7 +2570,7 @@ QUnit.module('basic_fields', { // switch to form view form.$('.o_field_widget[name=p] .o_data_row').click(); - assert.strictEqual($('.modal .o_field_date[name=datetime]').text(), '02/07/2017', + assert.strictEqual($('[role="dialog"] .o_field_date[name=datetime]').text(), '02/07/2017', 'the datetime (date widget) should be correctly displayed in form view'); form.destroy(); @@ -2614,7 +2614,7 @@ QUnit.module('basic_fields', { // switch to form view form.$('.o_field_widget[name=p] .o_data_row').click(); - assert.strictEqual($('.modal .o_field_date[name=datetime]').text(), '02/08/2017', + assert.strictEqual($('[role="dialog"] .o_field_date[name=datetime]').text(), '02/08/2017', 'the datetime (date widget) should be correctly displayed in form view'); form.destroy(); @@ -4602,13 +4602,13 @@ QUnit.module('basic_fields', { // open the selection form.$(".o_domain_show_selection_button").click(); - assert.strictEqual($('.modal .o_list_view .o_data_row').length, 2, + assert.strictEqual($('[role="dialog"] .o_list_view .o_data_row').length, 2, "should have open a list view with 2 records in a dialog"); // click on a record -> should not open the record // we don't actually check that it doesn't open the record because even // if it tries to, it will crash as we don't define an arch in this test - $('.modal .o_list_view .o_data_row:first .o_data_cell').click(); + $('[role="dialog"] .o_list_view .o_data_row:first .o_data_cell').click(); form.destroy(); }); diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js index 9b42c518891..95b12e9137d 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -206,7 +206,7 @@ QUnit.module('relational_fields', { form.$('.o_external_button').click(); // click on the external button (should do an RPC) - assert.strictEqual($('.modal .modal-title').text().trim(), 'Open: custom label', + assert.strictEqual($('[role="dialog"] .modal-title').text().trim(), 'Open: custom label', "dialog title should display the custom string label"); // TODO: test that we can edit the record in the dialog, and that the value is correctly @@ -246,7 +246,7 @@ QUnit.module('relational_fields', { // click on the external button (should do an RPC) form.$('.o_external_button').click(); // save and close modal - $('.modal .modal-footer .btn-primary:first').click(); + $('footer.modal-footer .btn-primary:first').click(); // save form form.$buttons.find('.o_form_button_save').click(); // click next on pager @@ -315,10 +315,10 @@ QUnit.module('relational_fields', { // click on the external button (should do an RPC) form.$('.o_external_button').click(); - $('.modal input[name="foo"]').val('brandon').trigger('input'); + $('[role="dialog"] input[name="foo"]').val('brandon').trigger('input'); // save and close modal - $('.modal .modal-footer .btn-primary:first').click(); + $('footer.modal-footer .btn-primary:first').click(); // save form form.$buttons.find('.o_form_button_save').click(); // click next on pager @@ -372,7 +372,7 @@ QUnit.module('relational_fields', { assert.strictEqual(form.$('button.o_external_button:visible').length, 1, "should still have an open record button"); form.$('input.o_input').trigger('focusout'); - assert.strictEqual($('.modal button:contains(Create and edit)').length, 0, + assert.strictEqual($('[role="dialog"] button:contains(Create and edit)').length, 0, "there should not be a quick create modal"); form.destroy(); @@ -471,10 +471,10 @@ QUnit.module('relational_fields', { // open the many2one in form view and change something form.$buttons.find('.o_form_button_edit').click(); form.$('.o_external_button').click(); - $('.modal-body input[name="other_field"]').val('wood').trigger('input'); + $('main.modal-body input[name="other_field"]').val('wood').trigger('input'); // save the modal and make sure an onchange is triggered - $('.modal .modal-footer .btn-primary').first().click(); + $('footer.modal-footer .btn-primary').first().click(); assert.verifySteps(['read', 'get_formview_id', 'load_views', 'read', 'write', 'onchange', 'read']); // save the main record, and check that no extra rpcs are done (record @@ -572,20 +572,20 @@ QUnit.module('relational_fields', { form.$('.o_field_many2one input').click(); // click on 'Search More' (mouseenter required by ui-autocomplete) $dropdown.find('.o_m2o_dropdown_option:contains(Search)').mouseenter().click(); - assert.ok($('.modal .o_list_view').length, "should have opened a list view in a modal"); - assert.ok(!$('.modal .o_list_view .o_list_record_selector').length, + assert.ok($('[role="dialog"] .o_list_view').length, "should have opened a list view in a modal"); + assert.ok(!$('[role="dialog"] .o_list_view .o_list_record_selector').length, "there should be no record selector in the list view"); - assert.ok(!$('.modal .modal-footer .o_select_button').length, + assert.ok(!$('footer.modal-footer .o_select_button').length, "there should be no 'Select' button in the footer"); - assert.ok($('.modal tbody tr').length > 10, "list should contain more than 10 records"); + assert.ok($('[role="dialog"] tbody tr').length > 10, "list should contain more than 10 records"); // filter the list using the searchview - $('.modal .o_searchview_input').trigger({type: 'keypress', which: 80}); // P - $('.modal .o_searchview_input').trigger({type: 'keydown', which: 13}); // enter - assert.strictEqual($('.modal tbody tr').length, 10, + $('[role="dialog"] .o_searchview_input').trigger({type: 'keypress', which: 80}); // P + $('[role="dialog"] .o_searchview_input').trigger({type: 'keydown', which: 13}); // enter + assert.strictEqual($('[role="dialog"] tbody tr').length, 10, "list should be restricted to records containing a P (10 records)"); // choose a record - $('.modal tbody tr:contains(Partner 20)').click(); // choose record 'Partner 20' - assert.ok(!$('.modal').length, "should have closed the modal"); + $('[role="dialog"] tbody tr:contains(Partner 20)').click(); // choose record 'Partner 20' + assert.ok(!$('[role="dialog"]').length, "should have closed the modal"); assert.ok(!$dropdown.is(':visible'), 'should have closed the dropdown'); assert.strictEqual(form.$('.o_field_many2one input').val(), 'Partner 20', 'value of the m2o should have been correctly updated'); @@ -1690,7 +1690,7 @@ QUnit.module('relational_fields', { form.$('.o_data_cell').click(); form.$('.o_external_button').click(); - var $modal = $('.modal-dialog'); + var $modal = $('[role="dialog"]'); assert.equal($modal.length, 1, 'There should be 1 modal opened'); @@ -1702,7 +1702,7 @@ QUnit.module('relational_fields', { {position: 'top'}); // Saving the modal and then the original model - $modal.find('.modal-footer .btn-primary').click(); + $modal.find('footer.modal-footer .btn-primary').click(); form.$buttons.find('.o_form_button_save').click(); assert.verifySteps(['onchange sequence', 'partner_type write']); @@ -1900,7 +1900,7 @@ QUnit.module('relational_fields', { form.$('.o_field_many2one input').focus(); form.$('.o_field_many2one input').val('new partner').trigger('keyup').trigger('focusout'); - $('.modal .modal-footer .btn-primary').first().click(); + $('footer.modal-footer .btn-primary').first().click(); form.destroy(); }); @@ -1928,14 +1928,14 @@ QUnit.module('relational_fields', { // cancel the many2one creation with Cancel button form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur'); - assert.strictEqual($('.modal').length, 1, "there should be one opened modal"); - $('.modal .modal-footer .btn:contains(Cancel)').click(); + assert.strictEqual($('[role="dialog"]').length, 1, "there should be one opened modal"); + $('footer.modal-footer .btn:contains(Cancel)').click(); assert.strictEqual(form.$('.o_field_many2one input').val(), "", 'the many2one should not set a value as its creation has been cancelled (with Cancel button)'); // cancel the many2one creation with Close button form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur'); - $('.modal .modal-header button').click(); + $('header.modal-header button').click(); assert.strictEqual(form.$('.o_field_many2one input').val(), "", 'the many2one should not set a value as its creation has been cancelled (with Close button)'); @@ -1944,16 +1944,16 @@ QUnit.module('relational_fields', { form.$('.o_field_many2one input').autocomplete('widget').find('a').first().click(); assert.strictEqual(form.$('input').val(), "xphone", "should have selected xphone"); form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur'); - assert.strictEqual($('.modal').length, 1, "there should be one opened modal"); - $('.modal .modal-footer .btn:contains(Cancel)').click(); + assert.strictEqual($('[role="dialog"]').length, 1, "there should be one opened modal"); + $('footer.modal-footer .btn:contains(Cancel)').click(); assert.strictEqual(form.$('.o_field_many2one input').val(), "xphone", 'should have restored the many2one with its previous selected value (xphone)'); // confirm the many2one creation form.$('.o_field_many2one input').focus(); form.$('.o_field_many2one input').val('new partner').trigger('keyup').trigger('blur'); - $('.modal .modal-footer .btn-primary').click(); - assert.strictEqual($('.modal .o_form_view').length, 1, + $('footer.modal-footer .btn-primary').click(); + assert.strictEqual($('[role="dialog"] .o_form_view').length, 1, 'a new modal should be opened and contain a form view'); form.destroy(); @@ -1976,7 +1976,7 @@ QUnit.module('relational_fields', { form.$('.o_field_many2one input').focus(); form.$('.o_field_many2one input').val('new partner').trigger('keyup').trigger('focusout'); - assert.strictEqual($('.modal').length, 0, "should not display the create modal"); + assert.strictEqual($('[role="dialog"]').length, 0, "should not display the create modal"); form.destroy(); }); @@ -2019,14 +2019,14 @@ QUnit.module('relational_fields', { "there should be an external button displayed"); form.$('.o_field_many2one .o_external_button').click(); - assert.strictEqual($('.modal .o_form_view.o_form_readonly').length, 1, + assert.strictEqual($('[role="dialog"] .o_form_view.o_form_readonly').length, 1, "there should be a readonly form view opened"); - $('.modal .o_form_button_cancel').click(); + $('[role="dialog"] .o_form_button_cancel').click(); form.$('.o_field_many2one input').val('new product').trigger('keyup').trigger('focusout'); - assert.strictEqual($('.modal').length, 0, "should not display the create modal"); + assert.strictEqual($('[role="dialog"]').length, 0, "should not display the create modal"); form.destroy(); }); @@ -2143,10 +2143,10 @@ QUnit.module('relational_fields', { })); concurrency.delay(0).then(function() { $input.blur(); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "should have one modal in body"); // Check that discarding clears $input - $('.modal .o_form_button_cancel').click(); + $('[role="dialog"] .o_form_button_cancel').click(); assert.strictEqual($input.val(), '', "the field should be empty"); form.destroy(); @@ -2202,7 +2202,7 @@ QUnit.module('relational_fields', { which: $.ui.keyCode.ENTER, keyCode: $.ui.keyCode.ENTER, })); - assert.strictEqual($('div.modal').length, 0, "should not have any modal in DOM"); + assert.strictEqual($('[role="dialog"]').length, 0, "should not have any modal in DOM"); assert.verifySteps(['name_search', 'onchange', 'write', 'read']); list.destroy(); relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; @@ -2258,7 +2258,7 @@ QUnit.module('relational_fields', { keyCode: $.ui.keyCode.ENTER, })); def.resolve(); - assert.strictEqual($('div.modal').length, 0, "should not have any modal in DOM"); + assert.strictEqual($('[role="dialog"]').length, 0, "should not have any modal in DOM"); assert.verifySteps(['name_search', 'onchange', 'write', 'read']); list.destroy(); relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; @@ -2409,15 +2409,15 @@ QUnit.module('relational_fields', { form.$buttons.find('.o_form_button_edit').click(); form.$('.o_data_row td:contains(first record)').click(); form.$('.o_external_button').click(); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "should have one modal in body"); // Changing the 'trululu' value - $('.modal input[name="display_name"]').val('test').trigger('input'); - $('.modal button.btn-primary').click(); + $('[role="dialog"] input[name="display_name"]').val('test').trigger('input'); + $('[role="dialog"] button.btn-primary').click(); // Test whether the value has changed - assert.strictEqual($('.modal').length, 0, + assert.strictEqual($('[role="dialog"]').length, 0, "the modal should be closed"); assert.equal(form.$('.o_data_cell:contains(test)').text(), 'test', "the partner name should have been updated to 'test'"); @@ -2504,7 +2504,7 @@ QUnit.module('relational_fields', { form.$buttons.find('.btn.btn-primary.btn-sm.o_form_button_edit').click(); form.$('.o_field_x2many_list_row_add a').click(); - var $modal = $('.modal-dialog.modal-lg'); + var $modal = $('.modal-lg'); assert.equal($modal.length, 1, 'There should be one modal'); @@ -2532,7 +2532,7 @@ QUnit.module('relational_fields', { // Third round: re-add 1 records form.$('.o_field_x2many_list_row_add a').click(); - $modal = $('.modal-dialog.modal-lg'); + $modal = $('.modal-lg'); assert.equal($modal.length, 1, 'There should be one modal'); @@ -3370,7 +3370,7 @@ QUnit.module('relational_fields', { assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "blurp#21#22#23#24#25#26#27#28#29", "should display the records in order with the changes"); - $('.modal .modal-footer button:first').click(); + $('footer.modal-footer button:first').click(); assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#21#22#23#24#25#26#27#28#29", "should cancel changes and display the records in order"); @@ -3402,7 +3402,7 @@ QUnit.module('relational_fields', { assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#39#40#41#42#43#44#45#46#47", "should display the records in order after resequence"); - $('.modal .modal-footer button:first').click(); + $('footer.modal-footer button:first').click(); assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#21#22#23#24#25#26#27#28#29", "should cancel changes and display the records in order"); @@ -3750,62 +3750,62 @@ QUnit.module('relational_fields', { // in its relation form.$('.o_data_row').click(); - assert.strictEqual($('.modal').length, 1, "should have opened a dialog"); - assert.strictEqual($('.modal .o_data_row').length, 0, + assert.strictEqual($('[role="dialog"]').length, 1, "should have opened a dialog"); + assert.strictEqual($('[role="dialog"] .o_data_row').length, 0, "there should be no record in the one2many in the dialog"); // add a many2many subrecord - $('.modal .o_field_x2many_list_row_add a').click(); + $('[role="dialog"] .o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal').length, 2, + assert.strictEqual($('[role="dialog"]').length, 2, "should have opened a second dialog"); // select a many2many subrecord - $('.modal:nth(1) .o_list_view .o_data_cell:first').click(); + $('[role="dialog"]:nth(1) .o_list_view .o_data_cell:first').click(); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "second dialog should be closed"); - assert.strictEqual($('.modal .o_data_row').length, 1, + assert.strictEqual($('[role="dialog"] .o_data_row').length, 1, "there should be one record in the one2many in the dialog"); - assert.notOk($('.modal .o_x2m_control_panel .o_cp_pager div').is(':visible'), + assert.notOk($('[role="dialog"] .o_x2m_control_panel .o_cp_pager div').is(':visible'), 'm2m pager should be hidden'); // click on 'Save & Close' - $('.modal .modal-footer .btn-primary:first').click(); + $('footer.modal-footer .btn-primary:first').click(); - assert.strictEqual($('.modal').length, 0, "dialog should be closed"); + assert.strictEqual($('[role="dialog"]').length, 0, "dialog should be closed"); // reopen o2m record, and another m2m subrecord in its relation, but // discard the changes form.$('.o_data_row').click(); - assert.strictEqual($('.modal').length, 1, "should have opened a dialog"); - assert.strictEqual($('.modal .o_data_row').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "should have opened a dialog"); + assert.strictEqual($('[role="dialog"] .o_data_row').length, 1, "there should be one record in the one2many in the dialog"); // add another m2m subrecord - $('.modal .o_field_x2many_list_row_add a').click(); + $('[role="dialog"] .o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal').length, 2, + assert.strictEqual($('[role="dialog"]').length, 2, "should have opened a second dialog"); - $('.modal:nth(1) .o_list_view .o_data_cell:first').click(); + $('[role="dialog"]:nth(1) .o_list_view .o_data_cell:first').click(); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "second dialog should be closed"); - assert.strictEqual($('.modal .o_data_row').length, 2, + assert.strictEqual($('[role="dialog"] .o_data_row').length, 2, "there should be two records in the one2many in the dialog"); // click on 'Discard' - $('.modal .modal-footer .btn-default').click(); + $('footer.modal-footer .btn-default').click(); - assert.strictEqual($('.modal').length, 0, "dialog should be closed"); + assert.strictEqual($('[role="dialog"]').length, 0, "dialog should be closed"); // reopen o2m record to check that second changes have properly been discarded form.$('.o_data_row').click(); - assert.strictEqual($('.modal').length, 1, "should have opened a dialog"); - assert.strictEqual($('.modal .o_data_row').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "should have opened a dialog"); + assert.strictEqual($('[role="dialog"] .o_data_row').length, 1, "there should be one record in the one2many in the dialog"); form.destroy(); @@ -4158,8 +4158,8 @@ QUnit.module('relational_fields', { checkRead = true; form.$buttons.find('.o_form_button_edit').click(); form.$('.o-kanban-button-new').click(); - $('.modal input').val('new record').trigger('input'); - $('.modal .modal-footer .btn-primary:first').click(); // save and close + $('[role="dialog"] input').val('new record').trigger('input'); + $('footer.modal-footer .btn-primary:first').click(); // save and close // checks assert.strictEqual(readIDs, undefined, "should not have read any record"); assert.strictEqual(form.$('span:contains(new record)').length, 0, @@ -4195,8 +4195,8 @@ QUnit.module('relational_fields', { readIDs = undefined; // add and delete a record in page 1 form.$('.o-kanban-button-new').click(); - $('.modal input').val('new record page 1').trigger('input'); - $('.modal .modal-footer .btn-primary:first').click(); // save and close + $('[role="dialog"] input').val('new record page 1').trigger('input'); + $('footer.modal-footer .btn-primary:first').click(); // save and close assert.strictEqual(form.$('.o_kanban_record:first span:contains(relational record 11)').length, 1, 'first record should be the one with id 11 (next checks rely on that)'); form.$('.delete_icon:first').click(); @@ -4210,8 +4210,8 @@ QUnit.module('relational_fields', { readIDs = undefined; form.$('.delete_icon:first').click(); form.$('.o-kanban-button-new').click(); - $('.modal input').val('new record page 2').trigger('input'); - $('.modal .modal-footer .btn-primary:first').click(); // save and close + $('[role="dialog"] input').val('new record page 2').trigger('input'); + $('footer.modal-footer .btn-primary:first').click(); // save and close assert.strictEqual(readIDs, undefined, "should not have read any record"); // checks assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 5, @@ -4255,13 +4255,13 @@ QUnit.module('relational_fields', { form.$buttons.find('.o_form_button_edit').click(); form.$('.o_field_x2many_list_row_add a').click(); $('input[name="turtle_int"]').val('5').trigger('input'); - $('.modal-footer button.btn-primary').first().click(); + $('footer.modal-footer button.btn-primary').first().click(); assert.strictEqual(form.$('tbody tr:eq(1) td.o_data_cell').text(), '5', 'should display 5 in the foo field'); form.$('tbody tr:eq(1) td.o_data_cell').click(); $('input[name="turtle_int"]').val('3').trigger('input'); - $('.modal-footer button.btn-primary').first().click(); + $('footer.modal-footer button.btn-primary').first().click(); assert.strictEqual(form.$('tbody tr:eq(1) td.o_data_cell').text(), '3', 'should now display 3 in the foo field'); form.destroy(); @@ -4358,7 +4358,7 @@ QUnit.module('relational_fields', { form.$buttons.find('.o_form_button_cancel').click(); assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'new value', "changes shouldn't have been discarded yet, waiting for user confirmation"); - $('.modal .modal-footer .btn-primary').click(); + $('footer.modal-footer .btn-primary').click(); assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'relational record 1', "display name of first record in o2m list should be 'relational record 1'"); @@ -4557,15 +4557,15 @@ QUnit.module('relational_fields', { // edit existing subrecord form.$('.oe_kanban_global_click').click(); - $('.modal .o_form_view input').val('new name').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save + $('[role="dialog"] .o_form_view input').val('new name').trigger('input'); + $('footer.modal-footer .btn-primary').click(); // save assert.strictEqual(form.$('.o_kanban_record span:first').text(), 'new name', 'value of subrecord should have been updated'); // create a new subrecord form.$('.o-kanban-button-new').click(); - $('.modal .o_form_view input').val('new subrecord 1').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save and close + $('[role="dialog"] .o_form_view input').val('new subrecord 1').trigger('input'); + $('footer.modal-footer .btn-primary').click(); // save and close assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2, 'should contain 2 records'); assert.strictEqual(form.$('.o_kanban_record:nth(1) span').text(), 'new subrecord 1', @@ -4573,10 +4573,10 @@ QUnit.module('relational_fields', { // create two new subrecords form.$('.o-kanban-button-new').click(); - $('.modal .o_form_view input').val('new subrecord 2').trigger('input'); - $('.modal .modal-footer .btn-primary:nth(1)').click(); // save and new - $('.modal .o_form_view input').val('new subrecord 3').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save and close + $('[role="dialog"] .o_form_view input').val('new subrecord 2').trigger('input'); + $('footer.modal-footer .btn-primary:nth(1)').click(); // save and new + $('[role="dialog"] .o_form_view input').val('new subrecord 3').trigger('input'); + $('footer.modal-footer .btn-primary').click(); // save and close assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 4, 'should contain 4 records'); @@ -4742,8 +4742,8 @@ QUnit.module('relational_fields', { // edit existing subrecord form.$('.o_list_view tbody tr:first() td:eq(1)').click(); - $('.modal .o_form_view input').val('new name').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save + $('[role="dialog"] .o_form_view input').val('new name').trigger('input'); + $('footer.modal-footer .btn-primary').click(); // save assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'new name', 'value of subrecord should have been updated'); assert.strictEqual(nbWrite, 0, "should not have write anything in DB"); @@ -4789,9 +4789,9 @@ QUnit.module('relational_fields', { '"Add an item" link should not be available in readonly'); form.$('.o_list_view tbody td:first()').click(); - assert.ok($('.modal .o_form_readonly').length, + assert.ok($('[role="dialog"] .o_form_readonly').length, 'in readonly, clicking on a subrecord should open it in readonly in a dialog'); - $('.modal .o_form_button_cancel').click(); // close the dialog + $('[role="dialog"] .o_form_button_cancel').click(); // close the dialog form.$buttons.find('.o_form_button_edit').click(); @@ -4800,7 +4800,7 @@ QUnit.module('relational_fields', { // edit existing subrecord form.$('.o_list_view tbody td:first()').click(); - assert.strictEqual($('.modal').length, 0, + assert.strictEqual($('[role="dialog"]').length, 0, 'in edit, clicking on a subrecord should not open a dialog'); assert.ok(form.$('.o_list_view tbody tr:first()').hasClass('o_selected_row'), 'first row should be in edition'); @@ -4898,7 +4898,7 @@ QUnit.module('relational_fields', { // cancel the edition form.$buttons.find('.o_form_button_cancel').click(); - $('.modal-footer button.btn-primary').first().click(); + $('footer.modal-footer button.btn-primary').first().click(); assert.strictEqual(form.$('tr.o_data_row').length, 1, "should have 1 data rows"); @@ -5054,7 +5054,7 @@ QUnit.module('relational_fields', { form.$buttons.find('.o_form_button_cancel').click(); // confirm the discard operation - $('.modal .modal-footer .btn-primary').click(); // click on confirm + $('footer.modal-footer .btn-primary').click(); // click on confirm assert.strictEqual(form.$('.o_cp_pager').text().trim(), '1-3 / 4', "pager should still be visible"); @@ -5129,7 +5129,7 @@ QUnit.module('relational_fields', { "pager should still display the correct total"); // click on cancel - $('.modal .modal-footer .btn-default').click(); // click on cancel + $('footer.modal-footer .btn-default').click(); // click on cancel assert.strictEqual(form.$('.o_cp_pager').text().trim(), '1-3 / 4', "pager should again display the correct total"); @@ -5169,7 +5169,7 @@ QUnit.module('relational_fields', { // discard form.$buttons.find('.o_form_button_cancel').click(); - $('.modal .modal-footer .btn-primary').click(); + $('footer.modal-footer .btn-primary').click(); assert.strictEqual(form.$('tr.o_data_row').length, 1, "should have 1 data row"); @@ -5216,17 +5216,17 @@ QUnit.module('relational_fields', { // click elsewhere, form.$('label.o_form_label').click(); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, 'a confirmation model should be opened'); // click on cancel, the line should still be selected - $('.modal .modal-footer button.btn-default').click(); + $('footer.modal-footer button.btn-default').click(); assert.strictEqual(form.$('tr.o_data_row.o_selected_row').length, 1, "should still have 1 selected data row"); // click elsewhere, and click on ok (on the confirmation dialog) form.$('label.o_form_label').click(); - $('.modal .modal-footer button.btn-primary').click(); + $('footer.modal-footer button.btn-primary').click(); assert.strictEqual(form.$('tr.o_data_row').length, 0, "should have 0 data rows (invalid line has been discarded"); @@ -5427,17 +5427,17 @@ QUnit.module('relational_fields', { }); form.$('.o_field_x2many_list_row_add a').click(); - $('.modal .o_field_x2many_list_row_add a').click(); + $('[role="dialog"] .o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal .o_data_row.o_selected_row').length, 1, + assert.strictEqual($('[role="dialog"] .o_data_row.o_selected_row').length, 1, "there should be a row in edition in the dialog"); // trigger keydown ESCAPE in the edited row - $('.modal .o_data_cell input').trigger({type: 'keydown', which: $.ui.keyCode.ESCAPE}); + $('[role="dialog"] .o_data_cell input').trigger({type: 'keydown', which: $.ui.keyCode.ESCAPE}); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "dialog should still be open"); - assert.strictEqual($('.modal .o_data_row').length, 0, + assert.strictEqual($('[role="dialog"] .o_data_row').length, 0, "the row should have been removed"); form.destroy(); @@ -6042,8 +6042,8 @@ QUnit.module('relational_fields', { // click to create a subrecord form.$('tbody td.o_field_x2many_list_row_add a').click(); - $('.modal input').val('new record').trigger('input'); - $('.modal .modal-footer button:eq(0)').click(); // save and close + $('[role="dialog"] input').val('new record').trigger('input'); + $('footer.modal-footer button:eq(0)').click(); // save and close assert.ok(!form.$('.o_x2m_control_panel .o_cp_pager div').is(':visible'), 'o2m pager should be hidden'); @@ -6098,14 +6098,14 @@ QUnit.module('relational_fields', { form.$('tbody td.o_field_x2many_list_row_add a').click(); - $('.modal .o_field_many2one input').click(); + $('[role="dialog"] .o_field_many2one input').click(); - var $dropdown = $('.modal .o_field_many2one input').autocomplete('widget'); + var $dropdown = $('[role="dialog"] .o_field_many2one input').autocomplete('widget'); $dropdown.find('li:eq(1) a').mouseenter(); $dropdown.find('li:eq(1) a').click(); - $('.modal .modal-footer button:eq(0)').click(); // save and close + $('footer.modal-footer button:eq(0)').click(); // save and close assert.strictEqual(form.$('tbody td:contains(xpad)').length, 1, "should display 'xpad' on a td"); @@ -6157,16 +6157,16 @@ QUnit.module('relational_fields', { form.$('tbody td.o_field_x2many_list_row_add a').click(); // write in the many2one field, value = 37 (xphone) - $('.modal .o_field_many2one input').click(); - var $dropdown = $('.modal .o_field_many2one input').autocomplete('widget'); + $('[role="dialog"] .o_field_many2one input').click(); + var $dropdown = $('[role="dialog"] .o_field_many2one input').autocomplete('widget'); $dropdown.find('li:eq(0) a').mouseenter(); $dropdown.find('li:eq(0) a').click(); // write in the integer field - $('.modal .modal-body input.o_field_widget').val('123').trigger('input'); + $('main.modal-body input.o_field_widget').val('123').trigger('input'); // save and close - $('.modal .modal-footer button:eq(0)').click(); + $('footer.modal-footer button:eq(0)').click(); assert.strictEqual(form.$('tbody td:contains(xphone)').length, 1, "should display 'xphone' in a td"); @@ -6174,28 +6174,28 @@ QUnit.module('relational_fields', { // reopen the record in form view form.$('tbody td:contains(xphone)').click(); - assert.strictEqual($('.modal .modal-body input').val(), "xphone", + assert.strictEqual($('main.modal-body input').val(), "xphone", "should display 'xphone' in an input"); - $('.modal .modal-body input.o_field_widget').val('456').trigger('input'); + $('main.modal-body input.o_field_widget').val('456').trigger('input'); // discard - $('.modal .modal-footer span:contains(Discard)').click(); + $('footer.modal-footer span:contains(Discard)').click(); // reopen the record in form view form.$('tbody td:contains(xphone)').click(); - assert.strictEqual($('.modal .modal-body input.o_field_widget').val(), "123", + assert.strictEqual($('main.modal-body input.o_field_widget').val(), "123", "should display 123 (previous change has been discarded)"); // write in the many2one field, value = 41 (xpad) - $('.modal .o_field_many2one input').click(); - $dropdown = $('.modal .o_field_many2one input').autocomplete('widget'); + $('[role="dialog"] .o_field_many2one input').click(); + $dropdown = $('[role="dialog"] .o_field_many2one input').autocomplete('widget'); $dropdown.find('li:eq(1) a').mouseenter(); $dropdown.find('li:eq(1) a').click(); // save and close - $('.modal .modal-footer button:eq(0)').click(); + $('footer.modal-footer button:eq(0)').click(); assert.strictEqual(form.$('tbody td:contains(xpad)').length, 1, "should display 'xpad' in a td"); @@ -6245,7 +6245,7 @@ QUnit.module('relational_fields', { form.$('tr.o_data_row:eq(0) td:contains(xphone)').click(); // write in the many2one field - $('.modal .o_field_many2one input').click(); + $('[role="dialog"] .o_field_many2one input').click(); form.destroy(); }); @@ -6513,29 +6513,29 @@ QUnit.module('relational_fields', { form.$buttons.find('.o_form_button_edit').click(); form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal .o_data_row').length, 2, + assert.strictEqual($('[role="dialog"] .o_data_row').length, 2, "sould have 2 records in the select view (the last one is not displayed because it is already selected)"); - $('.modal .o_data_row:first .o_list_record_selector input').click(); - $('.modal .o_select_button').click(); + $('[role="dialog"] .o_data_row:first .o_list_record_selector input').click(); + $('[role="dialog"] .o_select_button').click(); $('.o_form_button_save').click(); form.$buttons.find('.o_form_button_edit').click(); form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal .o_data_row').length, 1, + assert.strictEqual($('[role="dialog"] .o_data_row').length, 1, "sould have 1 record in the select view"); - $('.modal-footer button:eq(1)').click(); - $('.modal input.o_field_widget[name="turtle_foo"]').val('tototo').trigger('input'); - $('.modal input.o_field_widget[name="turtle_int"]').val(50).trigger('input'); - var $many2one = $('.modal [name="product_id"] input').click(); + $('footer.modal-footer button:eq(1)').click(); + $('[role="dialog"] input.o_field_widget[name="turtle_foo"]').val('tototo').trigger('input'); + $('[role="dialog"] input.o_field_widget[name="turtle_int"]').val(50).trigger('input'); + var $many2one = $('[role="dialog"] [name="product_id"] input').click(); var $dropdown = $many2one.autocomplete('widget'); $dropdown.find('li:first a').mouseenter(); $dropdown.find('li:first a').click(); - $('.modal-footer button:contains(&):first').click(); + $('footer.modal-footer button:contains(&):first').click(); - assert.strictEqual($('.modal').length, 0, "sould close the modals"); + assert.strictEqual($('[role="dialog"]').length, 0, "sould close the modals"); assert.strictEqual(form.$('.o_data_row').length, 3, "sould have 3 records in one2many list"); @@ -6593,34 +6593,34 @@ QUnit.module('relational_fields', { }); form.$('.o_data_row:first').click(); - assert.strictEqual($('.modal .modal-title').first().text().trim(), 'Open: one2many turtle field', + assert.strictEqual($('[role="dialog"] .modal-title').first().text().trim(), 'Open: one2many turtle field', "modal should use the python field string as title"); - $('.modal .o_form_button_cancel').click(); + $('[role="dialog"] .o_form_button_cancel').click(); form.$buttons.find('.o_form_button_edit').click(); // edit the first one2many record form.$('.o_data_row:first').click(); - var $many2one = $('.modal [name="product_id"] input').click(); + var $many2one = $('[role="dialog"] [name="product_id"] input').click(); var $dropdown = $many2one.autocomplete('widget'); $dropdown.find('li:first a').mouseenter(); $dropdown.find('li:first a').click(); - $('.modal-footer button:first').click(); + $('footer.modal-footer button:first').click(); $('.o_form_button_save').click(); // don't save anything because the one2many does not change // add a one2many record form.$buttons.find('.o_form_button_edit').click(); form.$('.o_field_x2many_list_row_add a').click(); - $('.modal .o_data_row:first .o_list_record_selector input').click(); - $('.modal .o_select_button').click(); + $('[role="dialog"] .o_data_row:first .o_list_record_selector input').click(); + $('[role="dialog"] .o_select_button').click(); // edit the second one2many record form.$('.o_data_row:eq(1)').click(); - $many2one = $('.modal [name="product_id"] input').click(); + $many2one = $('[role="dialog"] [name="product_id"] input').click(); $dropdown = $many2one.autocomplete('widget'); $dropdown.find('li:first a').mouseenter(); $dropdown.find('li:first a').click(); - $('.modal-footer button:first').click(); + $('footer.modal-footer button:first').click(); $('.o_form_button_save').click(); @@ -6812,10 +6812,10 @@ QUnit.module('relational_fields', { form.$buttons.find('.o_form_button_edit').click(); form.$('tbody td.o_field_x2many_list_row_add a').click(); - $('.modal-footer button.btn-primary').first().click(); + $('footer.modal-footer button.btn-primary').first().click(); - assert.strictEqual($('.modal').length, 1, "should still have an open modal"); - assert.strictEqual($('.modal tbody label.o_field_invalid').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "should still have an open modal"); + assert.strictEqual($('[role="dialog"] tbody label.o_field_invalid').length, 1, "should have displayed invalid fields"); form.destroy(); }); @@ -7011,9 +7011,9 @@ QUnit.module('relational_fields', { }); form.$('.o_field_one2many .o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal').length, 1, "form view dialog should be opened"); - $('.modal-body input[name="model_name"]').val('partner').trigger('input'); - $('.modal-footer button:first').click(); + assert.strictEqual($('[role="dialog"]').length, 1, "form view dialog should be opened"); + $('main.modal-body input[name="model_name"]').val('partner').trigger('input'); + $('footer.modal-footer button:first').click(); assert.strictEqual(form.$('.o_field_one2many tbody tr:first').text(), "coucouhas changed[]", "the onchange should create one new record and remove the existing"); @@ -7112,9 +7112,9 @@ QUnit.module('relational_fields', { form.$('.o_data_row:first').click(); - assert.strictEqual($('.modal .o_field_widget').text(), "xphone", + assert.strictEqual($('[role="dialog"] .o_field_widget').text(), "xphone", 'should display the form view dialog with the many2one value'); - $('.modal-footer button').click(); // close the modal + $('footer.modal-footer button').click(); // close the modal form.$buttons.find('.o_form_button_edit').click(); @@ -7368,7 +7368,7 @@ QUnit.module('relational_fields', { form.$('.o_data_row:first').click(); - assert.strictEqual($('.modal .o_field_widget[name="partner_ids"] .o_list_view').length, 1, + assert.strictEqual($('[role="dialog"] .o_field_widget[name="partner_ids"] .o_list_view').length, 1, 'should display many2many list view in the modal'); form.destroy(); @@ -7400,7 +7400,7 @@ QUnit.module('relational_fields', { form.$('.o_data_row:first').click(); - assert.strictEqual($('.modal .o_field_widget[name="turtle_foo"]').text(), 'blip', + assert.strictEqual($('[role="dialog"] .o_field_widget[name="turtle_foo"]').text(), 'blip', 'should open the modal and display the form field'); form.destroy(); @@ -7449,14 +7449,14 @@ QUnit.module('relational_fields', { form.$('.o_data_row:first').click(); // edit first record - var $input = $('.modal .o_field_many2manytags input'); + var $input = $('[role="dialog"] .o_field_many2manytags input'); $input.click(); // opens the dropdown $input.autocomplete('widget').find('li').click(); // add 'first record' // add a many2many tag and save - $('.modal .o_field_x2many_list_row_add a').click(); - $('.modal .o_field_widget[name=name]').val('test').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save + $('[role="dialog"] .o_field_x2many_list_row_add a').click(); + $('[role="dialog"] .o_field_widget[name=name]').val('test').trigger('input'); + $('footer.modal-footer .btn-primary').click(); // save form.$buttons.find('.o_form_button_save').click(); @@ -7510,13 +7510,13 @@ QUnit.module('relational_fields', { form.$('.o_external_button').click(); // click on add, to add a new partner in the m2m - $('.modal .o_field_x2many_list_row_add a').click(); + $('[role="dialog"] .o_field_x2many_list_row_add a').click(); // select the partner_type 'gold' (this closes the 2nd modal) - $('.modal td:contains(gold)').click(); + $('[role="dialog"] td:contains(gold)').click(); // confirm the changes in the modal - $('.modal .modal-footer .btn-primary').click(); + $('footer.modal-footer .btn-primary').click(); form.$buttons.find('.o_form_button_save').click(); form.destroy(); @@ -7585,7 +7585,7 @@ QUnit.module('relational_fields', { form.$('.o_data_row:first').click(); - assert.strictEqual($('.modal .o_field_widget[name="turtle_foo"]').text(), 'blip', + assert.strictEqual($('[role="dialog"] .o_field_widget[name="turtle_foo"]').text(), 'blip', 'should open the modal and display the form field'); form.destroy(); @@ -8080,7 +8080,7 @@ QUnit.module('relational_fields', { // try to add a second line and check that it is correctly waiting // for the onchange to return form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal').length, 0, "no modal should be displayed"); + assert.strictEqual($('[role="dialog"]').length, 0, "no modal should be displayed"); assert.strictEqual($('.o_field_invalid').length, 0, "no field should be marked as invalid"); assert.strictEqual(form.$('.o_data_row').length, 1, @@ -8384,11 +8384,11 @@ QUnit.module('relational_fields', { form.$('.o_data_row td:first').click(); // open the record - assert.strictEqual($('.modal .o_field_many2manytags[name="timmy"]').length, 1, + assert.strictEqual($('[role="dialog"] .o_field_many2manytags[name="timmy"]').length, 1, "timmy should be displayed in the form view"); - assert.strictEqual($('.modal .o_field_many2manytags[name="timmy"] .badge').length, 1, + assert.strictEqual($('[role="dialog"] .o_field_many2manytags[name="timmy"] .badge').length, 1, "m2mtags should contain one tag"); - assert.strictEqual($('.modal .o_field_many2manytags[name="timmy"] .o_badge_text').text(), + assert.strictEqual($('[role="dialog"] .o_field_many2manytags[name="timmy"] .o_badge_text').text(), 'gold', "tag name should have been correctly loaded"); form.destroy(); @@ -8464,10 +8464,10 @@ QUnit.module('relational_fields', { }); form.$('.o_field_x2many_list_row_add a').click(); - $('.modal .o_field_x2many_list_row_add a').click(); - $('.modal .o_data_cell input').val('new record').trigger('input'); + $('[role="dialog"] .o_field_x2many_list_row_add a').click(); + $('[role="dialog"] .o_data_cell input').val('new record').trigger('input'); checkOnchange = true; - $('.modal .modal-footer .btn-primary').click(); // save (should trigger the onchange) + $('footer.modal-footer .btn-primary').click(); // save (should trigger the onchange) form.destroy(); }); @@ -8788,7 +8788,7 @@ QUnit.module('relational_fields', { assert.strictEqual(form.$('.o_data_row.o_selected_row').length, 1, "line should not have been removed and should still be in edition"); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "a confirmation dialog should be opened"); assert.ok(form.$('.o_field_widget[name=int_field]').hasClass('o_field_invalid'), "should indicate that int_field is invalid"); @@ -8986,9 +8986,9 @@ QUnit.module('relational_fields', { // open the new subrecord to check the value of the nested o2m, and to // ensure that it will be saved form.$('.o_data_cell:first').click(); - assert.strictEqual($('.modal .o_data_cell').text(), 'test nested', + assert.strictEqual($('[role="dialog"] .o_data_cell').text(), 'test nested', "should have added the new row to the nested one2many"); - $('.modal .modal-footer .btn-primary').click(); + $('footer.modal-footer .btn-primary').click(); form.$buttons.find('.o_form_button_save').click(); @@ -9276,26 +9276,26 @@ QUnit.module('relational_fields', { // add a new record form.$('.o_field_x2many_list_row_add a').click(); - $('.modal .o_field_widget').val('new record').trigger('input'); - $('.modal .modal-footer .btn-primary:first').click(); // Save & Close + $('[role="dialog"] .o_field_widget').val('new record').trigger('input'); + $('footer.modal-footer .btn-primary:first').click(); // Save & Close assert.strictEqual(form.$('.o_data_row .o_data_cell').text(), 'new record', "should display the new record"); // reopen freshly added record and edit it form.$('.o_data_row .o_data_cell').click(); - $('.modal .o_field_widget').val('new record edited').trigger('input'); + $('[role="dialog"] .o_field_widget').val('new record edited').trigger('input'); // save it, and choose to directly create another record - $('.modal .modal-footer .btn-primary:nth(1)').click(); // Save & New + $('footer.modal-footer .btn-primary:nth(1)').click(); // Save & New - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "the model should still be open"); - assert.strictEqual($('.modal .o_field_widget').text(), '', + assert.strictEqual($('[role="dialog"] .o_field_widget').text(), '', "should have cleared the input"); - $('.modal .o_field_widget').val('another new record').trigger('input'); - $('.modal .modal-footer .btn-primary:first').click(); // Save & Close + $('[role="dialog"] .o_field_widget').val('another new record').trigger('input'); + $('footer.modal-footer .btn-primary:first').click(); // Save & Close assert.strictEqual(form.$('.o_data_row .o_data_cell').text(), 'new record editedanother new record', "should display the two records"); @@ -9461,19 +9461,19 @@ QUnit.module('relational_fields', { // edit existing subrecord form.$('.oe_kanban_global_click:first()').click(); - $('.modal .o_form_view input').val('new name').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save + $('[role="dialog"] .o_form_view input').val('new name').trigger('input'); + $('footer.modal-footer .btn-primary').click(); // save assert.strictEqual(form.$('.o_kanban_record:first() span').text(), 'new name', 'value of subrecord should have been updated'); // add subrecords // -> single select form.$('.o_field_many2many .o-kanban-button-new').click(); - assert.ok($('.modal .o_list_view').length, "should have opened a list view in a modal"); - assert.strictEqual($('.modal .o_list_view tbody .o_list_record_selector').length, 3, + assert.ok($('[role="dialog"] .o_list_view').length, "should have opened a list view in a modal"); + assert.strictEqual($('[role="dialog"] .o_list_view tbody .o_list_record_selector').length, 3, "list view should contain 3 records"); - $('.modal .o_list_view tbody tr:contains(red)').click(); // select red - assert.ok(!$('.modal .o_list_view').length, "should have closed the modal"); + $('[role="dialog"] .o_list_view tbody tr:contains(red)').click(); // select red + assert.ok(!$('[role="dialog"] .o_list_view').length, "should have closed the modal"); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 3, 'kanban should now contain 3 records'); assert.ok(form.$('.o_kanban_record:contains(red)').length, @@ -9481,23 +9481,23 @@ QUnit.module('relational_fields', { // -> multiple select form.$('.o_field_many2many .o-kanban-button-new').click(); - assert.ok($('.modal .o_select_button').prop('disabled'), "select button should be disabled"); - assert.strictEqual($('.modal .o_list_view tbody .o_list_record_selector').length, 2, + assert.ok($('[role="dialog"] .o_select_button').prop('disabled'), "select button should be disabled"); + assert.strictEqual($('[role="dialog"] .o_list_view tbody .o_list_record_selector').length, 2, "list view should contain 2 records"); - $('.modal .o_list_view thead .o_list_record_selector input').click(); // select all - $('.modal .o_select_button').click(); // validate selection - assert.ok(!$('.modal .o_select_button').prop('disabled'), "select button should be enabled"); - assert.ok(!$('.modal .o_list_view').length, "should have closed the modal"); + $('[role="dialog"] .o_list_view thead .o_list_record_selector input').click(); // select all + $('[role="dialog"] .o_select_button').click(); // validate selection + assert.ok(!$('[role="dialog"] .o_select_button').prop('disabled'), "select button should be enabled"); + assert.ok(!$('[role="dialog"] .o_list_view').length, "should have closed the modal"); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 5, 'kanban should now contain 5 records'); // -> created record form.$('.o_field_many2many .o-kanban-button-new').click(); - $('.modal .modal-footer .btn-primary:nth(1)').click(); // click on 'Create' - assert.ok($('.modal .o_form_view.o_form_editable').length, + $('footer.modal-footer .btn-primary:nth(1)').click(); // click on 'Create' + assert.ok($('[role="dialog"] .o_form_view.o_form_editable').length, "should have opened a form view in edit mode, in a modal"); - $('.modal .o_form_view input').val('A new type').trigger('input'); - $('.modal:nth(1) .modal-footer .btn-primary:first()').click(); // click on 'Save & Close' - assert.ok(!$('.modal').length, "should have closed both modals"); + $('[role="dialog"] .o_form_view input').val('A new type').trigger('input'); + $('[role="dialog"]:nth(1) footer .btn-primary:first()').click(); // click on 'Save & Close' + assert.ok(!$('[role="dialog"]').length, "should have closed both modals"); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 6, 'kanban should now contain 6 records'); assert.ok(form.$('.o_kanban_record:contains(A new type)').length, @@ -9592,7 +9592,7 @@ QUnit.module('relational_fields', { 'delete icon should be visible in edit'); form.$('.o-kanban-button-new').click(); // click on 'Add' - assert.strictEqual($('.modal .modal-footer .btn-primary').length, 1, // only button 'Select' + assert.strictEqual($('footer.modal-footer .btn-primary').length, 1, // only button 'Select' '"Create" button should not be available in the modal'); form.destroy(); @@ -9655,19 +9655,19 @@ QUnit.module('relational_fields', { // edit existing subrecord form.$('.o_list_view tbody tr:first()').click(); - $('.modal .o_form_view input').val('new name').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save + $('[role="dialog"] .o_form_view input').val('new name').trigger('input'); + $('footer.modal-footer .btn-primary').click(); // save assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'new name', 'value of subrecord should have been updated'); // add new subrecords form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal .o_list_view').length, 1, + assert.strictEqual($('[role="dialog"] .o_list_view').length, 1, "a modal should be open"); - assert.strictEqual($('.modal .o_list_view .o_data_row').length, 1, + assert.strictEqual($('[role="dialog"] .o_list_view .o_data_row').length, 1, "the list should contain one row"); - $('.modal .o_list_view .o_data_row').click(); // select a record - assert.strictEqual($('.modal .o_list_view').length, 0, + $('[role="dialog"] .o_list_view .o_data_row').click(); // select a record + assert.strictEqual($('[role="dialog"] .o_list_view').length, 0, "the modal should be closed"); assert.strictEqual(form.$('.o_list_view td.o_list_number').length, 3, 'should contain 3 subrecords'); @@ -9758,7 +9758,7 @@ QUnit.module('relational_fields', { // edit existing subrecord form.$('.o_list_view tbody td:first()').click(); - assert.ok(!$('.modal').length, + assert.ok(!$('[role="dialog"]').length, 'in edit, clicking on a subrecord should not open a dialog'); assert.ok(form.$('.o_list_view tbody tr:first()').hasClass('o_selected_row'), 'first row should be in edition'); @@ -9776,12 +9776,12 @@ QUnit.module('relational_fields', { // add new subrecords form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal .o_list_view').length, 1, + assert.strictEqual($('[role="dialog"] .o_list_view').length, 1, "a modal should be open"); - assert.strictEqual($('.modal .o_list_view .o_data_row').length, 1, + assert.strictEqual($('[role="dialog"] .o_list_view .o_data_row').length, 1, "the list should contain one row"); - $('.modal .o_list_view .o_data_row').click(); // select a record - assert.strictEqual($('.modal .o_list_view').length, 0, + $('[role="dialog"] .o_list_view .o_data_row').click(); // select a record + assert.strictEqual($('[role="dialog"] .o_list_view').length, 0, "the modal should be closed"); assert.strictEqual(form.$('.o_list_view td.o_list_number').length, 3, 'should contain 3 subrecords'); @@ -10048,7 +10048,7 @@ QUnit.module('relational_fields', { }); form.$('.o_field_x2many_list_row_add a').click(); - $('.modal .o_data_row:first').click(); // add a first record to the relation + $('[role="dialog"] .o_data_row:first').click(); // add a first record to the relation assert.strictEqual(form.$('.o_data_row').length, 1, "the record should have been added to the relation"); @@ -10056,7 +10056,7 @@ QUnit.module('relational_fields', { "inner m2m should have been fetched and correctly displayed"); form.$('.o_field_x2many_list_row_add a').click(); - $('.modal .o_data_row:first').click(); // add a second record to the relation + $('[role="dialog"] .o_data_row:first').click(); // add a second record to the relation assert.strictEqual(form.$('.o_data_row').length, 2, "the second record should have been added to the relation"); @@ -10109,13 +10109,13 @@ QUnit.module('relational_fields', { }); form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal .o_data_row').length, 1, + assert.strictEqual($('[role="dialog"] .o_data_row').length, 1, "should contain only one row (gold)"); - $('.modal .o_searchview_input').trigger({type: 'keypress', which: 115}); // s - $('.modal .o_searchview_input').trigger({type: 'keydown', which: 13}); // enter + $('[role="dialog"] .o_searchview_input').trigger({type: 'keypress', which: 115}); // s + $('[role="dialog"] .o_searchview_input').trigger({type: 'keydown', which: 13}); // enter - assert.strictEqual($('.modal .o_data_row').length, 0, "should contain no row"); + assert.strictEqual($('[role="dialog"] .o_data_row').length, 0, "should contain no row"); form.destroy(); }); @@ -10149,8 +10149,8 @@ QUnit.module('relational_fields', { form.$buttons.find('.o_form_button_edit').click(); form.$('td.o_data_cell:first').click(); - $('.modal-body input[type="checkbox"]').click(); - $('.modal .modal-footer .btn-primary').first().click(); + $('main.modal-body input[type="checkbox"]').click(); + $('footer.modal-footer .btn-primary').first().click(); // there is nothing left to save -> should not do a 'write' RPC form.$buttons.find('.o_form_button_save').click(); @@ -10806,9 +10806,9 @@ QUnit.module('relational_fields', { assert.strictEqual($input.autocomplete('widget').find('li').length, 3, "autocomplete dropdown should have 3 entries (2 values + 'Search and Edit...')"); $input.autocomplete('widget').find('li:first()').click(); // adds a tag - assert.strictEqual(form.$('.o_field_many2manytags[name="timmy"] > span').length, 1, + assert.strictEqual(form.$('.o_field_many2manytags[name="timmy"] > button').length, 1, "should contain 1 tag"); - assert.ok(form.$('.o_field_many2manytags[name="timmy"] > span:contains("gold")').length, + assert.ok(form.$('.o_field_many2manytags[name="timmy"] > button:contains("gold")').length, "should contain newly added tag 'gold'"); form.destroy(); @@ -10841,18 +10841,18 @@ QUnit.module('relational_fields', { return this._super.apply(this, arguments); }, }); - assert.strictEqual(form.$('.o_field_many2manytags > span').length, 2, + assert.strictEqual(form.$('.o_field_many2manytags > button').length, 2, "should contain 2 tags"); - assert.ok(form.$('span:contains(gold)').length, + assert.ok(form.$('button:contains(gold)').length, 'should have fetched and rendered gold partner tag'); - assert.ok(form.$('span:contains(silver)').length, + assert.ok(form.$('button:contains(silver)').length, 'should have fetched and rendered silver partner tag'); - assert.strictEqual(form.$('span:first()').data('color'), 2, + assert.strictEqual(form.$('button:first()').data('color'), 2, 'should have correctly fetched the color'); form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_many2manytags > span').length, 2, + assert.strictEqual(form.$('.o_field_many2manytags > button').length, 2, "should still contain 2 tags in edit mode"); assert.ok(form.$('.o_tag_color_2 .o_badge_text:contains(gold)').length, 'first tag should still contain "gold" and be color 2 in edit mode'); @@ -10867,46 +10867,46 @@ QUnit.module('relational_fields', { assert.strictEqual($input.autocomplete('widget').find('li a:contains("red")').length, 1, "autocomplete dropdown should contain 'red'"); $input.autocomplete('widget').find('li').click(); // add 'red' - assert.strictEqual(form.$('.o_field_many2manytags > span').length, 3, + assert.strictEqual(form.$('.o_field_many2manytags > button').length, 3, "should contain 3 tags"); - assert.ok(form.$('.o_field_many2manytags > span:contains("red")').length, + assert.ok(form.$('.o_field_many2manytags > button:contains("red")').length, "should contain newly added tag 'red'"); - assert.ok(form.$('.o_field_many2manytags > span[data-color=8]:contains("red")').length, + assert.ok(form.$('.o_field_many2manytags > button[data-color=8]:contains("red")').length, "should have fetched the color of added tag"); // remove tag with id 14 - form.$('.o_field_many2manytags span[data-id=14] .o_delete').click(); - assert.strictEqual(form.$('.o_field_many2manytags > span').length, 2, + form.$('.o_field_many2manytags button[data-id=14] .o_delete').click(); + assert.strictEqual(form.$('.o_field_many2manytags > button').length, 2, "should contain 2 tags"); - assert.ok(!form.$('.o_field_many2manytags > span:contains("silver")').length, + assert.ok(!form.$('.o_field_many2manytags > button:contains("silver")').length, "should not contain tag 'silver' anymore"); // save the record (should do the write RPC with the correct commands) form.$buttons.find('.o_form_button_save').click(); // checkbox 'Hide in Kanban' - $input = form.$('.o_field_many2manytags span[data-id=13]'); // selects 'red' tag + $input = form.$('.o_field_many2manytags button[data-id=13]'); // selects 'red' tag $input.click(); // opens the colorpicker dropdown - assert.ok(form.$('.o_field_many2manytags span[data-id=13] .o_colorpicker .o_checkbox'), "should have a checkbox in the colorpicker dropdown menu"); + assert.ok(form.$('.o_field_many2manytags button[data-id=13] .o_colorpicker .o_checkbox'), "should have a checkbox in the colorpicker dropdown menu"); $input.click(); - var $checkBox = form.$('.o_field_many2manytags span[data-id=13] .o_colorpicker .o_checkbox input'); + var $checkBox = form.$('.o_field_many2manytags button[data-id=13] .o_colorpicker .o_checkbox input'); assert.notOk($checkBox.is(':checked'), "should have unticked checkbox in colorpicker dropdown menu"); $checkBox.mousedown(); - $input = form.$('.o_field_many2manytags span[data-id=13]'); // refresh + $input = form.$('.o_field_many2manytags button[data-id=13]'); // refresh assert.equal($input.data('color'), "0", "should become transparent when toggling on checkbox"); $input.click(); - $checkBox = form.$('.o_field_many2manytags span[data-id=13] .o_colorpicker .o_checkbox input'); // refresh + $checkBox = form.$('.o_field_many2manytags button[data-id=13] .o_colorpicker .o_checkbox input'); // refresh assert.ok($checkBox.is(':checked'), "should have a ticked checkbox in colorpicker dropdown menu after mousedown"); $checkBox.mousedown(); - $input = form.$('.o_field_many2manytags span[data-id=13]'); // refresh + $input = form.$('.o_field_many2manytags button[data-id=13]'); // refresh assert.equal($input.data('color'), "8", "should revert to old color when toggling off checkbox"); $input.click(); - $checkBox = form.$('.o_field_many2manytags span[data-id=13] .o_colorpicker .o_checkbox input'); // refresh + $checkBox = form.$('.o_field_many2manytags button[data-id=13] .o_colorpicker .o_checkbox input'); // refresh assert.notOk($checkBox.is(':checked'), "should have an unticked checkbox in colorpicker dropdown menu after 2nd click"); // TODO: it would be nice to test the behaviors of the autocomplete dropdown @@ -10939,9 +10939,9 @@ QUnit.module('relational_fields', { return this._super.apply(this, arguments); } }); - assert.strictEqual(form.$('.o_field_many2manytags > span').length, 1, + assert.strictEqual(form.$('.o_field_many2manytags > button').length, 1, "should contain 1 tag"); - assert.ok(form.$('span:contains(gold)').length, + assert.ok(form.$('button:contains(gold)').length, 'should have fetched and rendered gold partner tag'); form.$buttons.find('.o_form_button_edit').click(); @@ -10954,9 +10954,9 @@ QUnit.module('relational_fields', { assert.strictEqual($input.autocomplete('widget').find('li a:contains("silver")').length, 1, "autocomplete dropdown should contain 'silver'"); $input.autocomplete('widget').find('li').click(); // add 'silver' - assert.strictEqual(form.$('.o_field_many2manytags > span').length, 2, + assert.strictEqual(form.$('.o_field_many2manytags > button').length, 2, "should contain 2 tags"); - assert.ok(form.$('.o_field_many2manytags > span:contains("silver")').length, + assert.ok(form.$('.o_field_many2manytags > button:contains("silver")').length, "should contain newly added tag 'silver'"); form.destroy(); @@ -10989,9 +10989,9 @@ QUnit.module('relational_fields', { assert.strictEqual($input.autocomplete('widget').find('li').length, 3, "autocomplete dropdown should have 3 entries (2 values + 'Search and Edit...')"); $input.autocomplete('widget').find('li:first()').click(); // adds a tag - assert.strictEqual(form.$('.o_field_many2manytags > span').length, 1, + assert.strictEqual(form.$('.o_field_many2manytags > button').length, 1, "should contain 1 tag"); - assert.ok(form.$('.o_field_many2manytags > span:contains("gold")').length, + assert.ok(form.$('.o_field_many2manytags > button:contains("gold")').length, "should contain newly added tag 'gold'"); // save the record (should do the write RPC with the correct commands) @@ -11016,20 +11016,20 @@ QUnit.module('relational_fields', { }); // First checks that default color 0 is rendered as 0 color - assert.ok(form.$('span:first()').is('.o_tag_color_0'), + assert.ok(form.$('button:first()').is('.o_tag_color_0'), 'first tag color should be 0'); // Update the color in readonly - form.$('span:first()').click(); + form.$('button:first()').click(); $('.o_colorpicker a[data-color="1"]').trigger('mousedown'); // choose color 1 - assert.strictEqual(form.$('span:first()').data('color'), 1, + assert.strictEqual(form.$('button:first()').data('color'), 1, 'should have correctly updated the color (in readonly)'); // Update the color in edit form.$buttons.find('.o_form_button_edit').click(); - form.$('span:first()').click(); + form.$('button:first()').click(); $('.o_colorpicker a[data-color="6"]').trigger('mousedown'); // choose color 6 - assert.strictEqual(form.$('span:first()').data('color'), 6, + assert.strictEqual(form.$('button:first()').data('color'), 6, 'should have correctly updated the color (in edit)'); form.destroy(); }); @@ -11136,14 +11136,14 @@ QUnit.module('relational_fields', { form.$('.o_field_many2one input').click(); $dropdown.find('.o_m2o_dropdown_option:contains(Search)').mouseenter().click(); // Open Search More - $('.modal .o_search_options .fa-bars').click(); - $('.modal .o_search_options .o_group_by_menu a:contains(Bar)').click(); // group by 'Bar' + $('[role="dialog"] .o_search_options .fa-bars').click(); + $('[role="dialog"] .o_search_options .o_group_by_menu a:contains(Bar)').click(); // group by 'Bar' - $('.modal .o_group_header:first').click(); - assert.strictEqual($('.modal tbody:nth(1) .o_data_row').length, 7, + $('[role="dialog"] .o_group_header:first').click(); + assert.strictEqual($('[role="dialog"] tbody:nth(1) .o_data_row').length, 7, "should display 7 records in the first page"); - $('.modal .o_group_header:first .o_pager_next').click(); - assert.strictEqual($('.modal tbody:nth(1) .o_data_row').length, 1, + $('[role="dialog"] .o_group_header:first .o_pager_next').click(); + assert.strictEqual($('[role="dialog"] tbody:nth(1) .o_data_row').length, 1, "should display 1 record in the second page"); form.destroy(); @@ -11167,7 +11167,7 @@ QUnit.module('relational_fields', { '</form>', res_id: 1, }); - assert.strictEqual(form.$('.o_field_widget[name="partner_ids"] > span').length, 100, + assert.strictEqual(form.$('.o_field_widget[name="partner_ids"] > button').length, 100, 'should have rendered 100 tags'); form.destroy(); }); @@ -11192,14 +11192,14 @@ QUnit.module('relational_fields', { }); form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_many2manytags > span').length, 1, + assert.strictEqual(form.$('.o_field_many2manytags > button').length, 1, "should contain one tag"); // update foo, which will trigger an onchange and update timmy // -> m2mtags input should not have taken the focus form.$('input:first').focus(); form.$('input:first').val('trigger onchange').trigger('input'); - assert.strictEqual(form.$('.o_field_many2manytags > span').length, 0, + assert.strictEqual(form.$('.o_field_many2manytags > button').length, 0, "should contain no tags"); assert.strictEqual(form.$('input:first').get(0), document.activeElement, "foo input should have kept the focus"); @@ -11207,14 +11207,14 @@ QUnit.module('relational_fields', { // add a tag -> m2mtags input should still have the focus form.$('.o_field_many2manytags input').click(); // opens the dropdown form.$('.o_field_many2manytags input').autocomplete('widget').find('li:first').click(); - assert.strictEqual(form.$('.o_field_many2manytags > span').length, 1, + assert.strictEqual(form.$('.o_field_many2manytags > button').length, 1, "should contain a tag"); assert.strictEqual(form.$('.o_field_many2manytags input').get(0), document.activeElement, "m2m tags input should have kept the focus"); // remove a tag -> m2mtags input should still have the focus form.$('.o_field_many2manytags .o_delete').click(); - assert.strictEqual(form.$('.o_field_many2manytags > span').length, 0, + assert.strictEqual(form.$('.o_field_many2manytags > button').length, 0, "should contain no tags"); assert.strictEqual(form.$('.o_field_many2manytags input').get(0), document.activeElement, "m2m tags input should have kept the focus"); @@ -11700,8 +11700,8 @@ QUnit.module('relational_fields', { form.$buttons.find('.o_form_button_edit').click(); form.$('.o_field_x2many_list_row_add a').click(); - var $dropdown = $('.modal .o_field_many2one input').autocomplete('widget'); - $('.modal input').val('new record').trigger('keydown'); + var $dropdown = $('[role="dialog"] .o_field_many2one input').autocomplete('widget'); + $('[role="dialog"] input').val('new record').trigger('keydown'); concurrency.delay(0).then(function () { $dropdown.find('li:first()').click(); // quick create 'new record' assert.verifySteps(['name_create']); @@ -11747,7 +11747,7 @@ QUnit.module('relational_fields', { $cell_o2m.click(); // In modal - var $modal = $('.modal-dialog.modal-lg'); + var $modal = $('.modal-lg'); assert.equal($modal.length, 1, 'there should be one modal opened'); @@ -11793,7 +11793,7 @@ QUnit.module('relational_fields', { form.$('.o_data_cell').click(); // In modal - var $modal = $('.modal-dialog.modal-lg'); + var $modal = $('.modal-lg'); assert.equal($modal.length, 1, 'there should be one modal opened'); @@ -11881,9 +11881,9 @@ QUnit.module('relational_fields', { form.$('.o_external_button').click(); // click on the external button (should do an RPC) - assert.strictEqual($('.modal .modal-title').text().trim(), 'Open: custom label', + assert.strictEqual($('[role="dialog"] .modal-title').text().trim(), 'Open: custom label', "dialog title should display the custom string label"); - $('.modal .o_form_button_cancel').click(); + $('[role="dialog"] .o_form_button_cancel').click(); form.$('.o_field_widget select').val('partner_type').trigger('change'); assert.strictEqual(form.$('.o_field_widget input').val(), "", @@ -12096,7 +12096,7 @@ QUnit.module('relational_fields', { // Add a record in the list x2mList.find('.o_field_x2many_list_row_add a').click(); - var modal = $('.modal-dialog.modal-lg'); + var modal = $('.modal-lg'); var nameInput = modal.find('input.o_input[name=display_name]'); nameInput.val('michelangelo').trigger('input'); diff --git a/addons/web/static/tests/fields/upgrade_fields_tests.js b/addons/web/static/tests/fields/upgrade_fields_tests.js index 427ec7b54e3..14f20bba8ad 100644 --- a/addons/web/static/tests/fields/upgrade_fields_tests.js +++ b/addons/web/static/tests/fields/upgrade_fields_tests.js @@ -33,7 +33,7 @@ QUnit.module('upgrade_fields', { }); form.$('input:checkbox').click(); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "the 'Upgrade to Enterprise' dialog should be opened"); form.destroy(); diff --git a/addons/web/static/tests/services/notification_service_tests.js b/addons/web/static/tests/services/notification_service_tests.js index 68227093cea..feb3a600550 100644 --- a/addons/web/static/tests/services/notification_service_tests.js +++ b/addons/web/static/tests/services/notification_service_tests.js @@ -45,7 +45,7 @@ QUnit.module('Services', { }); var $notification = $('body .o_notification_manager .o_notification'); assert.strictEqual(_.str.trim($notification.html().replace(/\s+/g, ' ')), - "<div class=\"o_notification_title\"> <span class=\"o_icon fa fa-3x fa-lightbulb-o\"></span> a </div> <div class=\"o_notification_content\">b</div>", + "<div class=\"o_notification_title\"> <span role=\"img\" aria-label=\"Notification undefined\" class=\"o_icon fa fa-3x fa-lightbulb-o\" title=\"Notification undefined\"></span> a </div> <div class=\"o_notification_content\">b</div>", "should display notification"); assert.strictEqual($notification.find('.o_close').length, 0, "should not display the close button in "); setTimeout(function () { @@ -68,7 +68,7 @@ QUnit.module('Services', { }); var $notification = $('body .o_notification_manager .o_notification'); assert.strictEqual(_.str.trim($notification.html().replace(/\s+/g, ' ')), - "<div class=\"o_notification_title\"> <span class=\"o_icon fa fa-3x fa-exclamation\"></span> a </div> <div class=\"o_notification_content\">b</div>", + "<div class=\"o_notification_title\"> <span role=\"img\" aria-label=\"Notification undefined\" class=\"o_icon fa fa-3x fa-exclamation\" title=\"Notification undefined\"></span> a </div> <div class=\"o_notification_content\">b</div>", "should display notification"); view.destroy(); setTimeout(done); @@ -184,7 +184,7 @@ QUnit.module('Services', { var $notification = $('body .o_notification_manager .o_notification'); assert.strictEqual($notification.eq(0).find('.o_close').length, 1, "should display the close button in notification"); assert.strictEqual(_.str.trim($notification.eq(0).html().replace(/\s+/g, ' ')), - "<a class=\"fa fa-times o_close\" href=\"#\"></a> <div class=\"o_notification_title\"> <span class=\"o_icon fa fa-3x fa-question-circle-o\"></span> a0 </div> <div class=\"o_notification_content\">b0</div> <div class=\"o_buttons\"> <button type=\"button\" class=\"btn btn-sm btn-primary\"> <span>accept0</span> </button><button type=\"button\" class=\"btn btn-sm btn-default\"> <span>refuse0</span> </button> </div>", + "<a aria-label=\"Close\" class=\"fa fa-times o_close\" href=\"#\" title=\"Close\"></a> <div class=\"o_notification_title\"> <span role=\"img\" aria-label=\"Notification undefined\" class=\"o_icon fa fa-3x fa-question-circle-o\" title=\"Notification undefined\"></span> a0 </div> <div class=\"o_notification_content\">b0</div> <div class=\"o_buttons\"> <button type=\"button\" class=\"btn btn-sm btn-primary\"> <span>accept0</span> </button><button type=\"button\" class=\"btn btn-sm btn-default\"> <span>refuse0</span> </button> </div>", "should display notification"); $notification.find('.o_buttons button:contains(accept0)').click(); diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index 0a7ca319c2f..5a07924413e 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -213,8 +213,8 @@ QUnit.module('Views', { $sidebar.find('input[type="text"]').trigger('click'); assert.strictEqual($('ul.ui-autocomplete li:not(.o_m2o_dropdown_option)').text(), "partner 4", "should display the last choice in one2many autocomplete"); // TODO: remove :not(.o_m2o_dropdown_option) because can't have "create & edit" choice $sidebar.find('.o_calendar_filter_item .o_remove').first().trigger('click'); - assert.ok($('.modal button.btn:contains(Ok)').length, "should display the confirm message"); - $('.modal button.btn:contains(Ok)').trigger('click'); + assert.ok($('footer.modal-footer button.btn:contains(Ok)').length, "should display the confirm message"); + $('footer.modal-footer button.btn:contains(Ok)').trigger('click'); assert.strictEqual($sidebar.find('.o_calendar_filter:has(h3:contains(attendees)) .o_calendar_filter_item').length, 3, "click on remove then should display 3 filter items for 'attendees'"); calendar.destroy(); }); @@ -295,19 +295,19 @@ QUnit.module('Views', { calendar.$('.fc-event:contains(event 4) .fc-content').trigger('click'); - assert.ok($('.modal-body').length, "should open the form view in dialog when click on event"); - assert.ok($('.modal button.btn:contains(Edit)').length, "formViewDialog should be in readonly mode"); - assert.ok($('.modal button.btn:contains(Delete)').length, "formViewDialog should have a delete button"); + assert.ok($('main.modal-body').length, "should open the form view in dialog when click on event"); + assert.ok($('footer.modal-footer button.btn:contains(Edit)').length, "formViewDialog should be in readonly mode"); + assert.ok($('footer.modal-footer button.btn:contains(Delete)').length, "formViewDialog should have a delete button"); - $('.modal button.btn:contains(Edit)').trigger('click'); + $('footer.modal-footer button.btn:contains(Edit)').trigger('click'); - assert.ok($('.modal-body').length, "should switch the modal in edit mode"); - assert.notOk($('.modal button.btn:contains(Delete)').length, "formViewDialog should not have a delete button in edit mode"); + assert.ok($('main.modal-body').length, "should switch the modal in edit mode"); + assert.notOk($('footer.modal-footer button.btn:contains(Delete)').length, "formViewDialog should not have a delete button in edit mode"); - $('.modal-body input:first').val('event 4 modified').trigger('input'); - $('.modal button.btn:contains(Save)').trigger('click'); + $('main.modal-body input:first').val('event 4 modified').trigger('input'); + $('footer.modal-footer button.btn:contains(Save)').trigger('click'); - assert.notOk($('.modal-body').length, "save button should close the modal"); + assert.notOk($('main.modal-body').length, "save button should close the modal"); assert.ok(calendar.$('.fc-event:contains(event 4 modified)').length, "should display the updated records"); // create a new event, quick create only @@ -317,12 +317,12 @@ QUnit.module('Views', { testUtils.triggerMouseEvent($cell, "mousedown"); testUtils.triggerMouseEvent($cell, "mouseup"); - assert.ok($('.modal-dialog.modal-sm').length, "should open the quick create dialog"); + assert.ok($('.modal-sm').length, "should open the quick create dialog"); - $('.modal-body input:first').val('new event in quick create').trigger('input'); - $('.modal button.btn:contains(Create)').trigger('click').trigger('click'); + $('main.modal-body input:first').val('new event in quick create').trigger('input'); + $('footer.modal-footer button.btn:contains(Create)').trigger('click').trigger('click'); - assert.strictEqual(calendar.$('.fc-event:contains(new event in quick create)').length, 1, "should display the new record"); + assert.strictEqual(calendar.$('.fc-event:contains(new event in quick create)').length, 1, "should display the new record after quick create"); assert.strictEqual(calendar.$('td.fc-event-container[colspan]').length, 2, "should the new record have only one day"); // create a new event, quick create only (validated by pressing enter key) @@ -330,9 +330,9 @@ QUnit.module('Views', { testUtils.triggerMouseEvent($cell, "mousedown"); testUtils.triggerMouseEvent($cell, "mouseup"); - assert.ok($('.modal-dialog.modal-sm').length, "should open the quick create dialog"); + assert.ok($('.modal-sm').length, "should open the quick create dialog"); - $('.modal-body input:first') + $('main.modal-body input:first') .val('new event in quick create validated by pressing enter key.') .trigger($.Event('keyup', {keyCode: $.ui.keyCode.ENTER})) .trigger($.Event('keyup', {keyCode: $.ui.keyCode.ENTER})); @@ -347,20 +347,20 @@ QUnit.module('Views', { testUtils.triggerMouseEvent($cell, "mousedown"); testUtils.triggerMouseEvent($cell, "mouseup"); - assert.strictEqual($('.modal-dialog.modal-sm').length, 1, "should open the quick create dialog"); + assert.strictEqual($('.modal-sm').length, 1, "should open the quick create dialog"); - $('.modal-body input:first').val('coucou').trigger('input'); - $('.modal button.btn:contains(Edit)').trigger('click'); + $('main.modal-body input:first').val('coucou').trigger('input'); + $('footer.modal-footer button.btn:contains(Edit)').trigger('click'); - assert.strictEqual($('.modal-dialog.modal-lg .o_form_view').length, 1, "should open the slow create dialog"); - assert.strictEqual($('.modal-dialog.modal-lg .modal-title').text(), "Create: Events", + assert.strictEqual($('.modal-lg .o_form_view').length, 1, "should open the slow create dialog"); + assert.strictEqual($('.modal-lg .modal-title').text(), "Create: Events", "should use the string attribute as modal title"); - assert.strictEqual($('.modal-dialog.modal-lg .o_form_view input[name="name"]').val(), "coucou", + assert.strictEqual($('.modal-lg .o_form_view input[name="name"]').val(), "coucou", "should have set the name from the quick create dialog"); $('.modal-lg button.btn:contains(Save)').trigger('click'); - assert.strictEqual(calendar.$('.fc-event:contains(coucou)').length, 1, "should display the new record"); + assert.strictEqual(calendar.$('.fc-event:contains(coucou)').length, 1, "should display the new record with string attribute"); // create a new event with 2 days @@ -370,14 +370,14 @@ QUnit.module('Views', { testUtils.triggerMouseEvent($cell.next(), "mousemove"); testUtils.triggerMouseEvent($cell.next(), "mouseup"); - $('.modal input:first').val('new event in quick create 2').trigger('input'); - $('.modal button.btn:contains(Edit)').trigger('click'); + $('.modal-dialog input:first').val('new event in quick create 2').trigger('input'); + $('footer.modal-footer button.btn:contains(Edit)').trigger('click'); assert.strictEqual($('.modal-lg input:first').val(), 'new event in quick create 2', "should open the formViewDialog with default values"); $('.modal-lg button.btn:contains(Save)').trigger('click'); - assert.notOk($('.modal').length, "should close dialogs"); + assert.notOk($('[role="dialog"]').length, "should close dialogs"); var $newevent2 = calendar.$('.fc-event:contains(new event in quick create 2)'); assert.ok($newevent2.length, "should display the 2 days new record"); assert.strictEqual($newevent2.closest('.fc-event-container').attr('colspan'), "2", "the new record should have 2 days"); @@ -385,9 +385,9 @@ QUnit.module('Views', { // delete the a record calendar.$('.fc-event:contains(event 4) .fc-content').trigger('click'); - $('.modal button.btn:contains(Delete)').trigger('click'); - assert.ok($('.modal button.btn:contains(Ok)').length, "should display the confirm message"); - $('.modal button.btn:contains(Ok)').trigger('click'); + $('footer.modal-footer button.btn:contains(Delete)').trigger('click'); + assert.ok($('footer.modal-footer button.btn:contains(Ok)').length, "should display the confirm message"); + $('footer.modal-footer button.btn:contains(Ok)').trigger('click'); assert.notOk(calendar.$('.fc-event:contains(event 4) .fc-content').length, "the record should be deleted"); assert.strictEqual(calendar.$('.fc-event-container .fc-event').length, 10, "should display 10 events"); @@ -439,18 +439,18 @@ QUnit.module('Views', { testUtils.triggerMouseEvent($cell, "mousedown"); testUtils.triggerMouseEvent($cell, "mouseup"); - assert.strictEqual($('.modal-dialog.modal-sm .modal-title').text(), 'Create: Events', + assert.strictEqual($('.modal-sm .modal-title').text(), 'Create: Events', "should open the quick create dialog"); - $('.modal-body input:first').val('new event in quick create').trigger('input'); - $('.modal button.btn:contains(Create)').trigger('click').trigger('click'); + $('main.modal-body input:first').val('new event in quick create').trigger('input'); + $('footer.modal-footer button.btn:contains(Create)').trigger('click').trigger('click'); // If the event is not default-prevented, a traceback will be raised, which we do not want assert.ok(event.isDefaultPrevented(), "fail deferred event should have been default-prevented"); - assert.strictEqual($('.modal-dialog.modal-lg .modal-title').text(), 'Create: Events', + assert.strictEqual($('.modal-lg .modal-title').text(), 'Create: Events', "should have switched to a bigger modal for an actual create rather than quickcreate"); - assert.strictEqual($('.modal-dialog.modal-lg .modal-body .o_form_view.o_form_editable').length, 1, + assert.strictEqual($('.modal-lg main .o_form_view.o_form_editable').length, 1, "should open the full event form view in a dialog"); calendar.destroy(); @@ -1328,7 +1328,7 @@ QUnit.module('Views', { var $cell = calendar.$('.fc-day-grid .fc-row:eq(4) .fc-day:eq(2)'); testUtils.triggerMouseEvent($cell, "mousedown"); testUtils.triggerMouseEvent($cell, "mouseup"); - $('.modal-body input:first').val('coucou').trigger('input'); + $('main.modal-body input:first').val('coucou').trigger('input'); testUtils.intercept(calendar, 'do_action', function (event) { assert.deepEqual(event.data.action, @@ -1385,7 +1385,7 @@ QUnit.module('Views', { var $cell = calendar.$('.fc-day-grid .fc-row:eq(4) .fc-day:eq(2)'); testUtils.triggerMouseEvent($cell, "mousedown"); testUtils.triggerMouseEvent($cell, "mouseup"); - $('.modal-body input:first').val('coucou').trigger('input'); + $('main.modal-body input:first').val('coucou').trigger('input'); testUtils.intercept(calendar, 'do_action', function (event) { assert.deepEqual(event.data.action, @@ -1463,7 +1463,7 @@ QUnit.module('Views', { var $cell = calendar.$('.fc-day-grid .fc-row:eq(4) .fc-day:eq(2)'); testUtils.triggerMouseEvent($cell, "mousedown"); testUtils.triggerMouseEvent($cell, "mouseup"); - $('.modal-body input:first').val('coucou').trigger('input'); + $('main.modal-body input:first').val('coucou').trigger('input'); testUtils.intercept(calendar, 'do_action', function (event) { assert.deepEqual(event.data.action, @@ -1600,8 +1600,8 @@ QUnit.module('Views', { testUtils.triggerPositionalMouseEvent(left, top + 200, "mousemove"); testUtils.triggerPositionalMouseEvent(left, top + 200, "mouseup"); - $('.modal-body input:first').val('coucou').trigger('input'); - $('.modal button.btn:contains(Create)').trigger('click'); + $('main.modal-body input:first').val('coucou').trigger('input'); + $('footer.modal-footer button.btn:contains(Create)').trigger('click'); assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should add the missing filter (active)"); assert.strictEqual(calendar.$('.fc-event').length, 4, "should display the created item"); @@ -1617,8 +1617,8 @@ QUnit.module('Views', { testUtils.triggerPositionalMouseEvent(left, top + 200, "mousemove"); testUtils.triggerPositionalMouseEvent(left, top + 200, "mouseup"); - $('.modal-body input:first').val('coucou 2').trigger('input'); - $('.modal button.btn:contains(Create)').trigger('click'); + $('main.modal-body input:first').val('coucou 2').trigger('input'); + $('footer.modal-footer button.btn:contains(Create)').trigger('click'); assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should have the same filters"); assert.strictEqual(calendar.$('.fc-event').length, 4, "should not display the created item"); @@ -1697,10 +1697,10 @@ QUnit.module('Views', { testUtils.triggerPositionalMouseEvent(left, top + 200, "mousemove"); testUtils.triggerPositionalMouseEvent(left, top + 200, "mouseup"); - $('.modal-body input:first').val('coucou').trigger('input'); + $('main.modal-body input:first').val('coucou').trigger('input'); - $('.modal button.btn:contains(Edit)').trigger('click'); - $('.modal button.btn:contains(Save)').trigger('click'); + $('footer.modal-footer button.btn:contains(Edit)').trigger('click'); + $('footer.modal-footer button.btn:contains(Save)').trigger('click'); assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should add the missing filter (active)"); assert.strictEqual(calendar.$('.fc-event').length, 4, "should display the created item"); @@ -1906,10 +1906,10 @@ QUnit.module('Views', { "should open the quick create dialog"); // Creating the event - $('.modal-body input:first').val('new event in quick create').trigger('input'); - $('.modal button.btn:contains(Create)').trigger('click').trigger('click'); + $('main.modal-body input:first').val('new event in quick create').trigger('input'); + $('footer.modal-footer button.btn:contains(Create)').trigger('click').trigger('click'); assert.strictEqual(calendar.$('.fc-event:contains(new event in quick create)').length, 1, - "should display the new record"); + "should display the new record after quick create dialog"); calendar.destroy(); $view.remove(); @@ -1989,14 +1989,14 @@ QUnit.module('Views', { var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); testUtils.triggerMouseEvent($cell, "mousedown"); testUtils.triggerMouseEvent($cell, "mouseup"); - var $input = $('.modal-body input:first'); + var $input = $('[role="dialog"] input:first'); $input.val('new event in quick create').trigger('input'); // Simulate ENTER pressed on Create button (after a TAB) $input.trigger($.Event('keyup', { which: $.ui.keyCode.ENTER, keyCode: $.ui.keyCode.ENTER, })); - $('.modal-footer button:first').click(); + $('footer.modal-footer button:first').click(); def.resolve(); assert.strictEqual(createCount, 1, "should create only one event"); @@ -2221,7 +2221,7 @@ QUnit.module('Views', { var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); testUtils.triggerMouseEvent($cell, "mousedown"); testUtils.triggerMouseEvent($cell, "mouseup"); - var $input = $('.modal-body input:first'); + var $input = $('main.modal-body input:first'); $input.val("It's just a fleshwound").trigger('input'); $('.modal button.btn:contains(Create)').trigger('click'); @@ -2268,7 +2268,7 @@ QUnit.module('Views', { var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); testUtils.triggerMouseEvent($cell, "mousedown"); testUtils.triggerMouseEvent($cell, "mouseup"); - var $input = $('.modal-body input:first'); + var $input = $('main.modal-body input:first'); $input.val("It's just a fleshwound").trigger('input'); $('.modal button.btn:contains(Create)').trigger('click'); diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index 18c82adb0a5..44ac724995b 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -2131,13 +2131,13 @@ QUnit.module('Views', { "should display the name of the many2many on the original form"); form.$('td:contains(gold)').click(); - assert.strictEqual($('.modal-dialog').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, 'The partner_type modal should have opened'); - assert.strictEqual($('.modal-dialog').find('td:contains(first record)').length, 1, + assert.strictEqual($('[role="dialog"]').find('td:contains(first record)').length, 1, "should display the name of the many2many on the modal form"); - $('.modal-dialog').find('td:contains(first record)').click(); - assert.strictEqual($('.modal-dialog').length, 2, + $('[role="dialog"]').find('td:contains(first record)').click(); + assert.strictEqual($('[role="dialog"]').length, 2, 'There should be 2 modals (partner on top of partner_type) opened'); form.destroy(); @@ -2167,7 +2167,7 @@ QUnit.module('Views', { // click on discard form.$buttons.find('.o_form_button_cancel').click(); - assert.ok(!$('.modal:visible').length, 'no confirm modal should be displayed'); + assert.ok(!$('[role="dialog"]:visible').length, 'no confirm modal should be displayed'); assert.strictEqual(form.$('.o_field_widget').text(), 'yop', 'field in readonly should display yop'); assert.strictEqual(nbWrite, 0, 'no write RPC should have been done'); @@ -2200,14 +2200,14 @@ QUnit.module('Views', { // click on discard and cancel the confirm request form.$buttons.find('.o_form_button_cancel').click(); - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal .modal-footer .btn-default').click(); // click on cancel + assert.ok($('[role="dialog"]').length, 'a confirm modal should be displayed'); + $('footer.modal-footer .btn-default').click(); // click on cancel assert.strictEqual(form.$('input').val(), 'new value', 'input should still contain new value'); // click on discard and confirm form.$buttons.find('.o_form_button_cancel').click(); - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal .modal-footer .btn-primary').click(); // click on confirm + assert.ok($('[role="dialog"]').length, 'a confirm modal should be displayed'); + $('footer.modal-footer .btn-primary').click(); // click on confirm assert.strictEqual(form.$('.o_field_widget').text(), 'yop', 'field in readonly should display yop'); assert.strictEqual(nbWrite, 0, 'no write RPC should have been done'); @@ -2287,7 +2287,7 @@ QUnit.module('Views', { // click on discard and confirm form.$buttons.find('.o_form_button_cancel').click(); - $('.modal .modal-footer .btn-primary').click(); // click on confirm + $('footer.modal-footer .btn-primary').click(); // click on confirm assert.notOk(form.$el.prop('outerHTML').match('xphone'), "the string xphone should not be present after discarding"); @@ -2317,7 +2317,7 @@ QUnit.module('Views', { form.$buttons.find('.o_form_button_cancel').click(); - assert.strictEqual($('.modal').length, 0, + assert.strictEqual($('[role="dialog"]').length, 0, 'there should not be a confirm modal'); form.destroy(); @@ -2351,17 +2351,17 @@ QUnit.module('Views', { // discard the changes and check it has properly been discarded form.$buttons.find('.o_form_button_cancel').click(); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, 'there should be a confirm modal'); assert.strictEqual(form.$('input').val(), 'DEF', 'input should be DEF'); - $('.modal .modal-footer .btn-primary').click(); // click on confirm + $('footer.modal-footer .btn-primary').click(); // click on confirm assert.strictEqual(form.$('input').val(), 'ABC', 'input should now be ABC'); // redirty and discard the field foo (to make sure initial changes haven't been lost) form.$('input').val('GHI').trigger('input'); form.$buttons.find('.o_form_button_cancel').click(); assert.strictEqual(form.$('input').val(), 'GHI', 'input should be GHI'); - $('.modal .modal-footer .btn-primary').click(); // click on confirm + $('footer.modal-footer .btn-primary').click(); // click on confirm assert.strictEqual(form.$('input').val(), 'ABC', 'input should now be ABC'); form.destroy(); @@ -2395,7 +2395,7 @@ QUnit.module('Views', { form.$buttons.find('.o_form_button_cancel').click(); - assert.strictEqual($('.modal').length, 0, + assert.strictEqual($('[role="dialog"]').length, 0, 'there should not be a confirm modal'); form.destroy(); @@ -2436,15 +2436,15 @@ QUnit.module('Views', { // click on the pager to switch to the next record and cancel the confirm request form.pager.$('.o_pager_next').click(); // click on next - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal .modal-footer .btn-default').click(); // click on cancel + assert.ok($('[role="dialog"]').length, 'a confirm modal should be displayed'); + $('footer.modal-footer .btn-default').click(); // click on cancel assert.strictEqual(form.$('input').val(), 'new value', 'input should still contain new value'); assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", 'pager value should still be 1'); // click on the pager to switch to the next record and confirm form.pager.$('.o_pager_next').click(); // click on next - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal .modal-footer .btn-primary').click(); // click on confirm + assert.ok($('[role="dialog"]').length, 'a confirm modal should be displayed'); + $('footer.modal-footer .btn-primary').click(); // click on confirm assert.strictEqual(form.$('input').val(), 'blip', 'input should contain blip'); assert.strictEqual(form.pager.$('.o_pager_value').text(), "2", 'pager value should be 2'); @@ -2483,7 +2483,7 @@ QUnit.module('Views', { // click on the pager to switch to the next record and cancel the confirm request form.pager.$('.o_pager_next').click(); // click on next - assert.strictEqual($('.modal:visible').length, 0, 'no confirm modal should be displayed'); + assert.strictEqual($('[role="dialog"]:visible').length, 0, 'no confirm modal should be displayed'); assert.strictEqual(form.pager.$('.o_pager_value').text(), "2", 'pager value should be 2'); assert.strictEqual(form.$('.o_priority .fa-star-o').length, 2, @@ -2495,7 +2495,7 @@ QUnit.module('Views', { 'priority widget should have been updated'); form.pager.$('.o_pager_next').click(); // click on next - assert.strictEqual($('.modal:visible').length, 0, 'no confirm modal should be displayed'); + assert.strictEqual($('[role="dialog"]:visible').length, 0, 'no confirm modal should be displayed'); assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", 'pager value should be 1'); // switch to edit mode @@ -2506,8 +2506,8 @@ QUnit.module('Views', { form.$('input').val('wrong value').trigger('input'); form.$buttons.find('.o_form_button_cancel').click(); - assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed'); - $('.modal .modal-footer .btn-primary').click(); // click on confirm + assert.strictEqual($('[role="dialog"]').length, 1, 'a confirm modal should be displayed'); + $('footer.modal-footer .btn-primary').click(); // click on confirm form.pager.$('.o_pager_next').click(); // click on next assert.strictEqual(form.pager.$('.o_pager_value').text(), "2", 'pager value should be 2'); form.destroy(); @@ -2736,16 +2736,16 @@ QUnit.module('Views', { assert.strictEqual(form.pager.$('.o_pager_limit').text(), "3", 'pager limit should be 3'); assert.strictEqual(form.$('span:contains(yop)').length, 1, 'should have a field with foo value for record 1'); - assert.ok(!$('.modal:visible').length, 'no confirm modal should be displayed'); + assert.ok(!$('[role="dialog"]:visible').length, 'no confirm modal should be displayed'); // open sidebar form.sidebar.$('button.o_dropdown_toggler_btn').click(); form.sidebar.$('a:contains(Delete)').click(); - assert.ok($('.modal').length, 'a confirm modal should be displayed'); + assert.ok($('[role="dialog"]').length, 'a confirm modal should be displayed'); // confirm the delete - $('.modal .modal-footer button.btn-primary').click(); + $('footer.modal-footer button.btn-primary').click(); assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", 'pager value should be 1'); assert.strictEqual(form.pager.$('.o_pager_limit').text(), "2", 'pager limit should be 2'); @@ -2784,9 +2784,9 @@ QUnit.module('Views', { testUtils.intercept(form, 'history_back', function () { assert.step('history_back'); }); - assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed'); - $('.modal .modal-footer button.btn-primary').click(); - assert.strictEqual($('.modal').length, 0, 'no confirm modal should be displayed'); + assert.strictEqual($('[role="dialog"]').length, 1, 'a confirm modal should be displayed'); + $('footer.modal-footer button.btn-primary').click(); + assert.strictEqual($('[role="dialog"]').length, 0, 'no confirm modal should be displayed'); assert.verifySteps(['read', 'unlink', 'history_back']); form.destroy(); @@ -3354,7 +3354,7 @@ QUnit.module('Views', { // open a subrecord and trigger an onchange readInModal = true; form.$('.o_data_row .o_data_cell:first').click(); - $('.modal .o_field_widget[name=name]').val("new name").trigger('input'); + $('[role="dialog"] .o_field_widget[name=name]').val("new name").trigger('input'); form.destroy(); }); @@ -3582,7 +3582,7 @@ QUnit.module('Views', { // discard changes form.$buttons.find('.o_form_button_cancel').click(); - $('.modal .modal-footer .btn-primary').click(); + $('footer.modal-footer .btn-primary').click(); assert.strictEqual(form.$('span[name="foo"]').text(), "blip", "field foo should still be displayed to initial value"); @@ -3627,13 +3627,13 @@ QUnit.module('Views', { assert.strictEqual(form.$('.o_field_widget[name="foo"]').val(), "1234", "field foo should still contain new value"); - assert.strictEqual($('.modal').length, 0, + assert.strictEqual($('[role="dialog"]').length, 0, "Confirm dialog should not be displayed"); // complete the write def.resolve(); - assert.strictEqual($('.modal').length, 0, + assert.strictEqual($('[role="dialog"]').length, 0, "Confirm dialog should not be displayed"); assert.strictEqual(form.$('.o_field_widget[name="foo"]').text(), "1234", "value should have been saved and rerendered in readonly"); @@ -3804,9 +3804,9 @@ QUnit.module('Views', { "onchange should have been correctly applied on field in o2m list"); form.$('.o_data_row').click(); // edit the o2m in the dialog - assert.strictEqual($('.modal .modal-title').text().trim(), 'Open: one2many field', + assert.strictEqual($('[role="dialog"] .modal-title').text().trim(), 'Open: one2many field', "the field string is displayed in the modal title"); - assert.strictEqual($('.modal .o_field_widget').val(), 'foo changed', + assert.strictEqual($('[role="dialog"] .o_field_widget').val(), 'foo changed', "the onchange value hasn't been discarded when opening the o2m"); form.destroy(); @@ -3898,20 +3898,20 @@ QUnit.module('Views', { "the initial value should be the default one"); form.$('.o_data_row td:first').click(); // edit the o2m in a dialog - $('.modal input:nth(1)').val(77).trigger('input'); - assert.strictEqual($('.modal input:first').val(), '[blip] 77', + $('[role="dialog"] input:nth(1)').val(77).trigger('input'); + assert.strictEqual($('[role="dialog"] input:first').val(), '[blip] 77', "onchange should have been correctly applied"); - $('.modal .modal-footer .btn-primary').click(); // save the dialog + $('footer.modal-footer .btn-primary').click(); // save the dialog assert.strictEqual(form.$('.o_data_row td:first').text(), '[blip] 77', "onchange should have been correctly applied"); // create a new o2m record form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal .modal-title').text().trim(), 'Create custom label', + assert.strictEqual($('[role="dialog"] .modal-title').text().trim(), 'Create custom label', "the custom field label is applied in the modal title"); - assert.strictEqual($('.modal input:first').val(), '[blip] 14', + assert.strictEqual($('[role="dialog"] input:first').val(), '[blip] 14', "onchange should have been correctly applied after default get"); - $('.modal .modal-footer .btn-primary').click(); // save the dialog + $('footer.modal-footer .btn-primary').click(); // save the dialog assert.strictEqual(form.$('.o_data_row:nth(1) td:first').text(), '[blip] 14', "onchange should have been correctly applied after default get"); @@ -4340,10 +4340,10 @@ QUnit.module('Views', { // add a o2m subrecord form.$('.o_field_x2many_list_row_add a').click(); - $('.modal-body .o_field_one2many .o_field_x2many_list_row_add a').click(); - $('.modal-body input').val('xtv').trigger('input'); - $('.modal-footer button:first').click(); // save & close - assert.strictEqual($('.modal').length, 0, + $('main.modal-body .o_field_one2many .o_field_x2many_list_row_add a').click(); + $('main.modal-body input').val('xtv').trigger('input'); + $('footer.modal-footer button:first').click(); // save & close + assert.strictEqual($('[role="dialog"]').length, 0, "dialog should be closed"); var row = form.$('.o_field_one2many .o_list_view .o_data_row'); @@ -4639,7 +4639,7 @@ QUnit.module('Views', { assert.strictEqual(row.children()[1].textContent, '1 record', "the cell should contains the number of record: 1"); row.click(); - var modal_row = $('.modal-body .o_form_sheet .o_field_one2many .o_list_view .o_data_row'); + var modal_row = $('main.modal-body .o_form_sheet .o_field_one2many .o_list_view .o_data_row'); assert.strictEqual(modal_row.children().length, 2, "the row should contains the 2 fields defined in the form view"); assert.strictEqual($(modal_row).text(), "gold2", @@ -4986,29 +4986,29 @@ QUnit.module('Views', { form.$buttons.find('.o_form_button_edit').click(); // Open first dialog form.$('.o_external_button').click(); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "One FormViewDialog should be opened"); - var $firstModal = $('.modal'); - assert.strictEqual($('.modal .modal-title').first().text().trim(), 'Open: Product', + var $firstModal = $('[role="dialog"]'); + assert.strictEqual($('[role="dialog"] .modal-title').first().text().trim(), 'Open: Product', "dialog title should display the python field string as label"); assert.strictEqual($firstModal.find('input').val(), 'xphone', "display_name should be correctly displayed"); // Open second dialog $firstModal.find('.o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal').length, 2, + assert.strictEqual($('[role="dialog"]').length, 2, "two FormViewDialogs should be opened"); - var $secondModal = $('.modal:nth(1)'); + var $secondModal = $('[role="dialog"]:nth(1)'); // Add new value $secondModal.find('input').val('xtv').trigger('input'); - $secondModal.find('.modal-footer button:first').click(); // Save & close - assert.strictEqual($('.modal').length, 1, + $secondModal.find('footer.modal-footer button:first').click(); // Save & close + assert.strictEqual($('[role="dialog"]').length, 1, "last opened dialog should be closed"); // Check that data in first dialog is correctly updated assert.strictEqual($firstModal.find('tr.o_data_row td').text(), 'xtv', "should have added a line with xtv as new record"); - $firstModal.find('.modal-footer button:first').click(); // Save & close + $firstModal.find('footer.modal-footer button:first').click(); // Save & close form.destroy(); }); @@ -5210,12 +5210,12 @@ QUnit.module('Views', { "record 1 should be first"); form.$buttons.find('.o_form_button_edit').click(); form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "FormViewDialog should be opened"); - $('.modal input[name="foo"]').val('xop').trigger("input"); - $('.modal .modal-footer button:eq(1)').click(); // Save & new - $('.modal input[name="foo"]').val('zop').trigger("input"); - $('.modal .modal-footer button:first').click(); // Save & close + $('[role="dialog"] input[name="foo"]').val('xop').trigger("input"); + $('footer.modal-footer button:eq(1)').click(); // Save & new + $('[role="dialog"] input[name="foo"]').val('zop').trigger("input"); + $('footer.modal-footer button:first').click(); // Save & close // client-side sort assert.ok(form.$('.o_field_one2many tbody tr:eq(0) td:contains(zop)').length, @@ -5237,8 +5237,8 @@ QUnit.module('Views', { // client-side sort on edit form.$buttons.find('.o_form_button_edit').click(); form.$('.o_field_one2many tbody tr:eq(1) td:contains(yop)').click(); - $('.modal input[name="foo"]').val('zzz').trigger("input"); - $('.modal .modal-footer button:first').click(); // Save + $('[role="dialog"] input[name="foo"]').val('zzz').trigger("input"); + $('footer.modal-footer button:first').click(); // Save assert.ok(form.$('.o_field_one2many tbody tr:eq(0) td:contains(zzz)').length, "record zzz should be first"); assert.ok(form.$('.o_field_one2many tbody tr:eq(1) td:contains(zop)').length, @@ -5524,7 +5524,7 @@ QUnit.module('Views', { }); form.$('.o_data_row:first').click(); - assert.strictEqual($('.modal .modal-title').first().text().trim(), 'Open: custom label', + assert.strictEqual($('[role="dialog"] .modal-title').first().text().trim(), 'Open: custom label', "modal should use the python field string as title"); form.destroy(); @@ -5610,10 +5610,10 @@ QUnit.module('Views', { form.$buttons.find('.o_form_button_edit').click(); form.$('[name="product_id"] .o_external_button').click(); - assert.strictEqual($('.modal-body .o_field_translate').length, 1, + assert.strictEqual($('main.modal-body .o_field_translate').length, 1, "there should be a translate button in the modal"); - $('.modal-body .o_field_translate').click(); + $('main.modal-body .o_field_translate').click(); assert.strictEqual(nbTranslateCalls, 1, "should call_button translate once"); @@ -5780,7 +5780,7 @@ QUnit.module('Views', { form.$('.o_statusbar_buttons button').click(); assert.ok(form.$('.o_statusbar_buttons button').prop('disabled'), 'button should be disabled'); - $('.modal .modal-footer button.btn-default').click(); + $('footer.modal-footer button.btn-default').click(); assert.ok(!form.$('.o_statusbar_buttons button').prop('disabled'), 'button should no longer be disabled'); @@ -5789,7 +5789,7 @@ QUnit.module('Views', { // click on button, and click on ok in confirm dialog form.$('.o_statusbar_buttons button').click(); assert.verifySteps(['default_get']); - $('.modal .modal-footer button.btn-primary').click(); + $('footer.modal-footer button.btn-primary').click(); assert.verifySteps(['default_get', 'create', 'read', 'execute_action']); @@ -5845,17 +5845,17 @@ QUnit.module('Views', { form.$('.o_external_button').click(); - assert.notOk($('.modal .oe_button_box button').attr('disabled'), + assert.notOk($('[role="dialog"] .oe_button_box button').attr('disabled'), "stat buttons should be enabled"); - $('.modal .oe_button_box button').click(); + $('[role="dialog"] .oe_button_box button').click(); - assert.ok($('.modal .oe_button_box button').attr('disabled'), + assert.ok($('[role="dialog"] .oe_button_box button').attr('disabled'), "stat buttons should be disabled"); def.resolve(); - assert.notOk($('.modal .oe_button_box button').attr('disabled'), + assert.notOk($('[role="dialog"] .oe_button_box button').attr('disabled'), "stat buttons should be enabled"); form.destroy(); @@ -6034,16 +6034,16 @@ QUnit.module('Views', { form.$buttons.find('.o_form_button_edit').click(); form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "One FormViewDialog should be opened"); // set a value on the m2o var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - $('.modal .o_field_many2one input').click(); + $('[role="dialog"] .o_field_many2one input').click(); $dropdown.find('li:first()').click(); - $('.modal .modal-footer button:eq(1)').click(); // Save & new - $('.modal .o_field_many2one input').click(); - $('.modal .modal-footer button:first').click(); // Save & close + $('footer.modal-footer button:eq(1)').click(); // Save & new + $('[role="dialog"] .o_field_many2one input').click(); + $('footer.modal-footer button:first').click(); // Save & close form.destroy(); }); @@ -6133,20 +6133,20 @@ QUnit.module('Views', { }); form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual($('.modal input.o_field_widget[name=foo]').length, 1, + assert.strictEqual($('[role="dialog"] input.o_field_widget[name=foo]').length, 1, 'foo should be editable'); checkOnchange = true; - $('.modal .o_field_widget[name=foo]').val('foo value').trigger('input'); - $('.modal .o_field_widget[name=display_name]').val('readonly').trigger('input'); - assert.strictEqual($('.modal span.o_field_widget[name=foo]').length, 1, + $('[role="dialog"] .o_field_widget[name=foo]').val('foo value').trigger('input'); + $('[role="dialog"] .o_field_widget[name=display_name]').val('readonly').trigger('input'); + assert.strictEqual($('[role="dialog"] span.o_field_widget[name=foo]').length, 1, 'foo should be readonly'); - $('.modal .modal-footer .btn-primary').click(); // close the modal + $('footer.modal-footer .btn-primary').click(); // close the modal checkOnchange = false; form.$('.o_data_row').click(); // re-open previous record - assert.strictEqual($('.modal .o_field_widget[name=foo]').text(), 'foo value', + assert.strictEqual($('[role="dialog"] .o_field_widget[name=foo]').text(), 'foo value', "the edited value should have been kept"); - $('.modal .modal-footer .btn-primary').click(); // close the modal + $('footer.modal-footer .btn-primary').click(); // close the modal form.$buttons.find('.o_form_button_save').click(); // save the record @@ -6219,8 +6219,8 @@ QUnit.module('Views', { form.$buttons.find('.o_form_button_save').click(); // save duplicated record form.sidebar.$('a:contains(Delete)').click(); // delete duplicated record - assert.strictEqual($('.modal').length, 1, "should have opened a confirm dialog"); - $('.modal .modal-footer .btn-primary').click(); // confirm + assert.strictEqual($('[role="dialog"]').length, 1, "should have opened a confirm dialog"); + $('footer.modal-footer .btn-primary').click(); // confirm assert.strictEqual(form.$('.o_field_widget').text(), 'first record', "should have come back to previous record"); @@ -6301,12 +6301,12 @@ QUnit.module('Views', { }); form.$('.o_external_button').click(); // open the many2one record in a modal - $('.modal .o_external_button').click(); // in the modal, open the many2one record in another modal + $('[role="dialog"] .o_external_button').click(); // in the modal, open the many2one record in another modal - $('.modal:nth(1) .o_field_widget[name=display_name]').val('new name').trigger('input'); - $('.modal:nth(1) .modal-footer .btn-primary').first().click(); // save changes + $('[role="dialog"]:nth(1) .o_field_widget[name=display_name]').val('new name').trigger('input'); + $('[role="dialog"]:nth(1) footer .btn-primary').first().click(); // save changes - assert.strictEqual($('.modal .o_field_widget[name=trululu] input').val(), 'new name', + assert.strictEqual($('[role="dialog"] .o_field_widget[name=trululu] input').val(), 'new name', "record should have been reloaded"); assert.verifySteps([ "read", // main record @@ -6409,11 +6409,11 @@ QUnit.module('Views', { viewOptions: {mode: 'edit'}, }); form.$('.o_external_button').click(); - assert.strictEqual($('.modal-body .o_form_view .o_list_view .o_data_cell').text(), "yopblip", + assert.strictEqual($('main.modal-body .o_form_view .o_list_view .o_data_cell').text(), "yopblip", "table has some initial order"); - $('.modal-body .o_form_view .o_list_view th').click(); - assert.strictEqual($('.modal-body .o_form_view .o_list_view .o_data_cell').text(), "blipyop", + $('main.modal-body .o_form_view .o_list_view th').click(); + assert.strictEqual($('main.modal-body .o_form_view .o_list_view .o_data_cell').text(), "blipyop", "table is now sorted"); form.destroy(); }); @@ -6849,7 +6849,7 @@ QUnit.module('Views', { core.bus.on('clear_cache', form, assert.step.bind(assert, 'clear_cache')); form.sidebar.$('a:contains(Delete)').click(); - $('.modal .modal-footer .btn-primary').click(); // confirm + $('footer.modal-footer .btn-primary').click(); // confirm assert.verifySteps(['unlink', 'clear_cache']); diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js index 04c1c603118..2cc7a2431ef 100644 --- a/addons/web/static/tests/views/kanban_tests.js +++ b/addons/web/static/tests/views/kanban_tests.js @@ -182,12 +182,12 @@ QUnit.module('Views', { "last column should contain 3 records"); envIDs = [4]; kanban.$('.o_kanban_group:last .o_column_archive_records').click(); // Click on 'Archive All' - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal .modal-footer .btn-default').click(); // Click on 'Cancel' + assert.ok($('[role="dialog"]').length, 'a confirm modal should be displayed'); + $('footer.modal-footer .btn-default').click(); // Click on 'Cancel' assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 3, "still last column should contain 3 records"); kanban.$('.o_kanban_group:last .o_column_archive_records').click(); - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal .modal-footer .btn-primary').click(); // Click on 'Ok' + assert.ok($('[role="dialog"]').length, 'a confirm modal should be displayed'); + $('footer.modal-footer .btn-primary').click(); // Click on 'Ok' assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 0, "last column should not contain any records"); kanban.destroy(); }); @@ -1204,16 +1204,16 @@ QUnit.module('Views', { which: $.ui.keyCode.ENTER, })); - assert.strictEqual($('.modal .o_form_view.o_form_editable').length, 1, + assert.strictEqual($('[role="dialog"] .o_form_view.o_form_editable').length, 1, "a form view dialog should have been opened (in edit)"); - assert.strictEqual($('.modal .o_field_many2one input').val(), 'hello', + assert.strictEqual($('[role="dialog"] .o_field_many2one input').val(), 'hello', "the correct product_id should already be set"); // specify a name and save - $('.modal input[name=foo]').val('test').trigger('input'); - $('.modal-footer .btn-primary').click(); + $('[role="dialog"] input[name=foo]').val('test').trigger('input'); + $('footer.modal-footer .btn-primary').click(); - assert.strictEqual($('.modal').length, 0, "the modal should be closed"); + assert.strictEqual($('[role="dialog"]').length, 0, "the modal should be closed"); assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 3, "there should be 3 records in first column"); var $firstRecord = kanban.$('.o_kanban_group:first .o_kanban_record:first'); @@ -1793,13 +1793,13 @@ QUnit.module('Views', { // delete second column (first cancel the confirm request, then confirm) kanban.$('.o_kanban_group:last .o_column_delete').click(); // click on delete - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal .modal-footer .btn-default').click(); // click on cancel + assert.ok($('[role="dialog"]').length, 'a confirm modal should be displayed'); + $('footer.modal-footer .btn-default').click(); // click on cancel assert.strictEqual(kanban.$('.o_kanban_group:last').data('id'), 5, 'column [5, "xmo"] should still be there'); kanban.$('.o_kanban_group:last .o_column_delete').click(); // click on delete - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal .modal-footer .btn-primary').click(); // click on confirm + assert.ok($('[role="dialog"]').length, 'a confirm modal should be displayed'); + $('footer.modal-footer .btn-primary').click(); // click on confirm assert.strictEqual(kanban.$('.o_kanban_group:last').data('id'), 3, 'last column should now be [3, "hello"]'); assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should still have two columns"); @@ -1870,7 +1870,7 @@ QUnit.module('Views', { assert.strictEqual(kanban.$('.o_kanban_group').length, 3, "should have two columns"); kanban.$('.o_kanban_group:last .o_column_delete').click(); - $('.modal .modal-footer .btn-primary').click(); + $('footer.modal-footer .btn-primary').click(); assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have twos columns"); @@ -1912,33 +1912,33 @@ QUnit.module('Views', { // edit the title of column [5, 'xmo'] and close without saving kanban.$('.o_kanban_group[data-id=5] .o_column_edit').click(); // click on 'Edit' - assert.ok($('.modal .o_form_editable').length, 'a form view should be open in a modal'); - assert.strictEqual($('.modal .o_form_editable input').val(), 'xmo', + assert.ok($('[role="dialog"] .o_form_editable').length, 'a form view should be open in a modal'); + assert.strictEqual($('[role="dialog"] .o_form_editable input').val(), 'xmo', 'the name should be "xmo"'); - $('.modal .o_form_editable input').val('ged').trigger('input'); // change the value + $('[role="dialog"] .o_form_editable input').val('ged').trigger('input'); // change the value nbRPCs = 0; - $('.modal .modal-header .close').click(); // click on the cross to close the modal - assert.ok(!$('.modal').length, 'the modal should be closed'); + $('header.modal-header .close').click(); // click on the cross to close the modal + assert.ok(!$('[role="dialog"]').length, 'the modal should be closed'); assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'xmo', 'title of the column should still be "xmo"'); assert.strictEqual(nbRPCs, 0, 'no RPC should have been done'); // edit the title of column [5, 'xmo'] and discard kanban.$('.o_kanban_group[data-id=5] .o_column_edit').click(); // click on 'Edit' - $('.modal .o_form_editable input').val('ged').trigger('input'); // change the value + $('[role="dialog"] .o_form_editable input').val('ged').trigger('input'); // change the value nbRPCs = 0; - $('.modal .modal-footer .btn-default').click(); // click on discard - assert.ok(!$('.modal').length, 'the modal should be closed'); + $('footer.modal-footer .btn-default').click(); // click on discard + assert.ok(!$('[role="dialog"]').length, 'the modal should be closed'); assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'xmo', 'title of the column should still be "xmo"'); assert.strictEqual(nbRPCs, 0, 'no RPC should have been done'); // edit the title of column [5, 'xmo'] and save kanban.$('.o_kanban_group[data-id=5] .o_column_edit').click(); // click on 'Edit' - $('.modal .o_form_editable input').val('ged').trigger('input'); // change the value + $('[role="dialog"] .o_form_editable input').val('ged').trigger('input'); // change the value nbRPCs = 0; - $('.modal .modal-footer .btn-primary').click(); // click on save - assert.ok(!$('.modal').length, 'the modal should be closed'); + $('footer.modal-footer .btn-primary').click(); // click on save + assert.ok(!$('[role="dialog"]').length, 'the modal should be closed'); assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'ged', 'title of the column should be "ged"'); assert.strictEqual(nbRPCs, 4, 'should have done 1 write, 1 read_group and 2 search_read'); @@ -2058,16 +2058,16 @@ QUnit.module('Views', { // click to see the examples kanban.$('.o_column_quick_create .o_kanban_examples').click(); - assert.strictEqual($('.modal .o_kanban_examples_dialog').length, 1, + assert.strictEqual($('[role="dialog"] .o_kanban_examples_dialog').length, 1, "should have open the examples dialog"); - assert.strictEqual($('.modal .o_kanban_examples_dialog_nav li').length, 2, + assert.strictEqual($('[role="dialog"] .o_kanban_examples_dialog_nav li').length, 2, "should have two examples (in the menu)"); - assert.strictEqual($('.modal .o_kanban_examples_dialog_nav a').text(), + assert.strictEqual($('[role="dialog"] .o_kanban_examples_dialog_nav a').text(), ' A first example A second example ', "example names should be correct"); - assert.strictEqual($('.modal .o_kanban_examples_dialog_content .tab-pane').length, 2, + assert.strictEqual($('[role="dialog"] .o_kanban_examples_dialog_content .tab-pane').length, 2, "should have two examples"); - var $firstPane = $('.modal .o_kanban_examples_dialog_content .tab-pane:first'); + var $firstPane = $('[role="dialog"] .o_kanban_examples_dialog_content .tab-pane:first'); assert.strictEqual($firstPane.find('.o_kanban_examples_group').length, 3, "there should be 3 stages in the first example"); assert.strictEqual($firstPane.find('h6').text(), 'Column 1Column 2Column 3', @@ -2075,7 +2075,7 @@ QUnit.module('Views', { assert.strictEqual($firstPane.find('.o_kanban_examples_description').text().trim(), "Some description", "the correct description should be displayed"); - var $secondPane = $('.modal .o_kanban_examples_dialog_content .tab-pane:nth(1)'); + var $secondPane = $('[role="dialog"] .o_kanban_examples_dialog_content .tab-pane:nth(1)'); assert.strictEqual($secondPane.find('.o_kanban_examples_group').length, 2, "there should be 2 stages in the second example"); assert.strictEqual($secondPane.find('h6').text(), 'Col 1Col 2', diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 8aa70c1c099..ed57c6968ac 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -880,7 +880,7 @@ QUnit.module('Views', { list.sidebar.$('a:contains(Delete)').click(); assert.ok($('body').hasClass('modal-open'), 'body should have modal-open clsss'); - $('body .modal-dialog button span:contains(Ok)').click(); + $('body [role="dialog"] button span:contains(Ok)').click(); assert.strictEqual(list.$('tbody td.o_list_record_selector').length, 3, "should have 3 records"); list.destroy(); @@ -916,13 +916,13 @@ QUnit.module('Views', { assert.verifySteps(['/web/dataset/search_read']); list.sidebar.$('a:contains(Archive)').click(); - assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed'); - $('.modal .modal-footer .btn-default').click(); // Click on 'Cancel' + assert.strictEqual($('[role="dialog"]').length, 1, 'a confirm modal should be displayed'); + $('footer.modal-footer .btn-default').click(); // Click on 'Cancel' assert.strictEqual(list.$('tbody td.o_list_record_selector').length, 4, "still should have 4 records"); list.sidebar.$('a:contains(Archive)').click(); - assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed'); - $('.modal .modal-footer .btn-primary').click(); // Click on 'Ok' + assert.strictEqual($('[role="dialog"]').length, 1, 'a confirm modal should be displayed'); + $('footer.modal-footer .btn-primary').click(); // Click on 'Ok' assert.strictEqual(list.$('tbody td.o_list_record_selector').length, 3, "should have 3 records"); assert.verifySteps(['/web/dataset/search_read', '/web/dataset/call_kw/foo/write', '/web/dataset/search_read']); list.destroy(); @@ -2759,10 +2759,10 @@ QUnit.module('Views', { list.$('.o_data_cell:first').click(); list.$('input[name="foo"]').val("hello").trigger('input'); list.$buttons.find('.o_list_button_discard').click(); - assert.strictEqual($('.modal:visible').length, 1, + assert.strictEqual($('[role="dialog"]:visible').length, 1, "a modal to ask for discard should be visible"); - $('.modal:visible .btn-primary').click(); + $('[role="dialog"]:visible .btn-primary').click(); assert.strictEqual(list.$('.o_data_cell:first').text(), "yop", "first cell should still contain 'yop'"); @@ -3555,7 +3555,7 @@ QUnit.module('Views', { // delete a record list.$('.o_data_row:first .o_list_record_selector input').click(); list.sidebar.$('a:contains(Delete)').click(); - $('.modal .modal-footer .btn-primary').click(); // confirm + $('footer.modal-footer .btn-primary').click(); // confirm assert.verifySteps([ 'create', diff --git a/addons/web/static/tests/views/view_dialogs_tests.js b/addons/web/static/tests/views/view_dialogs_tests.js index 39484795f5a..2d6af1b5e14 100644 --- a/addons/web/static/tests/views/view_dialogs_tests.js +++ b/addons/web/static/tests/views/view_dialogs_tests.js @@ -90,9 +90,9 @@ QUnit.module('Views', { res_id: 1, }).open(); - assert.notOk($('div.modal .modal-body button').length, + assert.notOk($('main.modal-body button').length, "should not have any button in body"); - assert.strictEqual($('div.modal .modal-footer button').length, 1, + assert.strictEqual($('footer.modal-footer button').length, 1, "should have only one button in footer"); parent.destroy(); }); @@ -118,7 +118,7 @@ QUnit.module('Views', { res_id: 1, }).open(); - assert.strictEqual($('div.modal button.btn-primary').length, 1, + assert.strictEqual($('[role="dialog"] button.btn-primary').length, 1, "should have 1 buttons in modal"); $('.o_field_x2many_list_row_add a').click(); @@ -127,7 +127,7 @@ QUnit.module('Views', { keyCode: $.ui.keyCode.ESCAPE, })); - assert.strictEqual($('div.modal button.btn-primary').length, 1, + assert.strictEqual($('[role="dialog"] button.btn-primary').length, 1, "should still have 1 buttons in modal"); parent.destroy(); }); @@ -334,14 +334,14 @@ QUnit.module('Views', { form.$('.o_field_widget .o_field_many2one[name=instrument] input').click(); $('ul.ui-autocomplete.ui-front.ui-menu.ui-widget.ui-widget-content li.o_m2o_dropdown_option').first().click(); - var $modal = $('.modal-dialog.modal-lg'); + var $modal = $('.modal-lg'); assert.equal($modal.length, 1, 'There should be one modal'); $modal.find('.o_field_x2many_list_row_add a').click(); - var $modals = $('.modal-dialog.modal-lg'); + var $modals = $('.modal-lg'); assert.equal($modals.length, 2, 'There should be two modals'); @@ -351,7 +351,7 @@ QUnit.module('Views', { $second_modal.find('.o_select_button').click(); - $modal = $('.modal-dialog.modal-lg'); + $modal = $('.modal-lg'); assert.equal($modal.length, 1, 'There should be one modal'); diff --git a/addons/web/static/tests/widgets/data_export_tests.js b/addons/web/static/tests/widgets/data_export_tests.js index 4569a5a6290..4948db07474 100644 --- a/addons/web/static/tests/widgets/data_export_tests.js +++ b/addons/web/static/tests/widgets/data_export_tests.js @@ -107,15 +107,15 @@ QUnit.module('widgets', { list.$('thead th.o_list_record_selector input').click(); list.sidebar.$('a:contains(Export)').click(); - assert.strictEqual($('.modal').length, 1, "a modal dialog should be open"); + assert.strictEqual($('[role="dialog"]').length, 1, "a modal dialog should be open"); assert.strictEqual($('span.o_tree_column:contains(Activities)').length, 1, "the Activities field should be in the list of exportable fields"); // select the field Description, click on add, then export and close - $('.modal span:contains(Description)').click(); - $('.modal .o_add_field').click(); - $('.modal span:contains(Export To File)').click(); - $('.modal span:contains(Close)').click(); + $('[role="dialog"] span:contains(Description)').click(); + $('[role="dialog"] .o_add_field').click(); + $('[role="dialog"] span:contains(Export To File)').click(); + $('[role="dialog"] span:contains(Close)').click(); list.destroy(); framework.blockUI = blockUI; @@ -185,26 +185,26 @@ QUnit.module('widgets', { // Open the export modal list.$('thead th.o_list_record_selector input').click(); list.sidebar.$('a:contains(Export)').click(); - assert.strictEqual($('.modal').length, 1, + assert.strictEqual($('[role="dialog"]').length, 1, "a modal dialog should be open"); // Select 'Activities' in fields to export - assert.strictEqual($('.modal select.o_fields_list option').length, 0, + assert.strictEqual($('[role="dialog"] select.o_fields_list option').length, 0, "the fields list should be empty"); - $('.modal .o_export_tree_item:contains(Activities)').click(); - $('.modal button:contains(Add)').click(); - assert.strictEqual($('.modal select.o_fields_list option').length, 1, + $('[role="dialog"] .o_export_tree_item:contains(Activities)').click(); + $('[role="dialog"] button:contains(Add)').click(); + assert.strictEqual($('[role="dialog"] select.o_fields_list option').length, 1, "there should be one item in the fields list"); // Save fields list - $('.modal a:contains(Save fields list)').click(); - $('.modal .o_save_list > input').val('fields list').trigger('input'); - $('.modal .o_save_list > button').click(); + $('[role="dialog"] a:contains(Save fields list)').click(); + $('[role="dialog"] .o_save_list > input').val('fields list').trigger('input'); + $('[role="dialog"] .o_save_list > button').click(); assert.verifySteps(['build_search_data', 'create'], "create should have been called"); // Close the modal and destroy list - $('.modal button span:contains(Close)').click(); + $('[role="dialog"] button span:contains(Close)').click(); list.destroy(); // restore create function |
