| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // To avoid creating tons of unnecessary nodes. We assume we cannot fit more | 5 // To avoid creating tons of unnecessary nodes. We assume we cannot fit more |
| 6 // than this many items in the miniview. | 6 // than this many items in the miniview. |
| 7 var MAX_MINIVIEW_ITEMS = 15; | 7 var MAX_MINIVIEW_ITEMS = 15; |
| 8 | 8 |
| 9 // Extra spacing at the top of the layout. | 9 // Extra spacing at the top of the layout. |
| 10 var LAYOUT_SPACING_TOP = 25; | 10 var LAYOUT_SPACING_TOP = 25; |
| (...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 } | 640 } |
| 641 | 641 |
| 642 function showFirstRunNotification() { | 642 function showFirstRunNotification() { |
| 643 showNotification(localStrings.getString('firstrunnotification'), | 643 showNotification(localStrings.getString('firstrunnotification'), |
| 644 localStrings.getString('closefirstrunnotification'), | 644 localStrings.getString('closefirstrunnotification'), |
| 645 null, 30000); | 645 null, 30000); |
| 646 var notificationElement = $('notification'); | 646 var notificationElement = $('notification'); |
| 647 notification.classList.add('first-run'); | 647 notification.classList.add('first-run'); |
| 648 } | 648 } |
| 649 | 649 |
| 650 /** | |
| 651 * This handles the option menu. | |
| 652 * @param {Element} button The button element. | |
| 653 * @param {Element} menu The menu element. | |
| 654 * @constructor | |
| 655 */ | |
| 656 function OptionMenu(button, menu) { | |
| 657 this.button = button; | |
| 658 this.menu = menu; | |
| 659 this.button.onclick = bind(this.handleClick, this); | |
| 660 this.button.onmousedown = bind(this.handleMouseDown, this); | |
| 661 this.button.onkeydown = bind(this.handleKeyDown, this); | |
| 662 this.boundHideMenu_ = bind(this.hide, this); | |
| 663 this.boundMaybeHide_ = bind(this.maybeHide_, this); | |
| 664 this.menu.onmouseover = bind(this.handleMouseOver, this); | |
| 665 this.menu.onmouseout = bind(this.handleMouseOut, this); | |
| 666 this.menu.onmouseup = bind(this.handleMouseUp, this); | |
| 667 } | |
| 668 | |
| 669 OptionMenu.prototype = { | |
| 670 show: function() { | |
| 671 this.positionMenu_(); | |
| 672 this.menu.style.display = 'block'; | |
| 673 this.button.classList.add('open'); | |
| 674 this.button.focus(); | |
| 675 | |
| 676 // Listen to document and window events so that we hide the menu when the | |
| 677 // user clicks outside the menu or tabs away or the whole window is blurred. | |
| 678 document.addEventListener('focus', this.boundMaybeHide_, true); | |
| 679 document.addEventListener('mousedown', this.boundMaybeHide_, true); | |
| 680 }, | |
| 681 | |
| 682 positionMenu_: function() { | |
| 683 var rect = this.button.getBoundingClientRect(); | |
| 684 this.menu.style.top = rect.bottom + 'px'; | |
| 685 if (document.documentElement.dir == 'rtl') | |
| 686 this.menu.style.left = rect.left + 'px'; | |
| 687 else | |
| 688 this.menu.style.right = (document.body.clientWidth - rect.right) + 'px' | |
| 689 }, | |
| 690 | |
| 691 hide: function() { | |
| 692 this.menu.style.display = 'none'; | |
| 693 this.button.classList.remove('open'); | |
| 694 this.setSelectedIndex(-1); | |
| 695 | |
| 696 document.removeEventListener('focus', this.boundMaybeHide_, true); | |
| 697 document.removeEventListener('mousedown', this.boundMaybeHide_, true); | |
| 698 }, | |
| 699 | |
| 700 isShown: function() { | |
| 701 return this.menu.style.display == 'block'; | |
| 702 }, | |
| 703 | |
| 704 /** | |
| 705 * Callback for document mousedown and focus. It checks if the user tried to | |
| 706 * navigate to a different element on the page and if so hides the menu. | |
| 707 * @param {Event} e The mouse or focus event. | |
| 708 * @private | |
| 709 */ | |
| 710 maybeHide_: function(e) { | |
| 711 if (!this.menu.contains(e.target) && !this.button.contains(e.target)) { | |
| 712 this.hide(); | |
| 713 } | |
| 714 }, | |
| 715 | |
| 716 handleMouseDown: function(e) { | |
| 717 if (this.isShown()) { | |
| 718 this.hide(); | |
| 719 } else { | |
| 720 this.show(); | |
| 721 } | |
| 722 }, | |
| 723 | |
| 724 handleClick: function(e) { | |
| 725 e.stopPropagation(); | |
| 726 }, | |
| 727 | |
| 728 handleMouseOver: function(e) { | |
| 729 var el = e.target; | |
| 730 if (!el.hasAttribute('command')) { | |
| 731 this.setSelectedIndex(-1); | |
| 732 } else { | |
| 733 var index = Array.prototype.indexOf.call(this.menu.children, el); | |
| 734 this.setSelectedIndex(index); | |
| 735 } | |
| 736 }, | |
| 737 | |
| 738 handleMouseOut: function(e) { | |
| 739 this.setSelectedIndex(-1); | |
| 740 }, | |
| 741 | |
| 742 handleMouseUp: function(e) { | |
| 743 var item = this.getSelectedItem(); | |
| 744 if (item) { | |
| 745 this.executeItem(item); | |
| 746 } | |
| 747 }, | |
| 748 | |
| 749 handleKeyDown: function(e) { | |
| 750 var item = this.getSelectedItem(); | |
| 751 | |
| 752 var self = this; | |
| 753 function selectNextVisible(m) { | |
| 754 var children = self.menu.children; | |
| 755 var len = children.length; | |
| 756 var i = self.selectedIndex_; | |
| 757 if (i == -1 && m == -1) { | |
| 758 // Edge case when we need to go the last item fisrt. | |
| 759 i = 0; | |
| 760 } | |
| 761 while (true) { | |
| 762 i = (i + m + len) % len; | |
| 763 item = children[i]; | |
| 764 if (item && item.hasAttribute('command') && | |
| 765 item.style.display != 'none') { | |
| 766 break; | |
| 767 } | |
| 768 } | |
| 769 if (item) { | |
| 770 self.setSelectedIndex(i); | |
| 771 } | |
| 772 } | |
| 773 | |
| 774 switch (e.keyIdentifier) { | |
| 775 case 'Down': | |
| 776 if (!this.isShown()) { | |
| 777 this.show(); | |
| 778 } | |
| 779 selectNextVisible(1); | |
| 780 e.preventDefault(); | |
| 781 break; | |
| 782 case 'Up': | |
| 783 if (!this.isShown()) { | |
| 784 this.show(); | |
| 785 } | |
| 786 selectNextVisible(-1); | |
| 787 e.preventDefault(); | |
| 788 break; | |
| 789 case 'Esc': | |
| 790 case 'U+001B': // Maybe this is remote desktop playing a prank? | |
| 791 this.hide(); | |
| 792 break; | |
| 793 case 'Enter': | |
| 794 case 'U+0020': // Space | |
| 795 if (this.isShown()) { | |
| 796 if (item) { | |
| 797 this.executeItem(item); | |
| 798 } else { | |
| 799 this.hide(); | |
| 800 } | |
| 801 } else { | |
| 802 this.show(); | |
| 803 } | |
| 804 e.preventDefault(); | |
| 805 break; | |
| 806 } | |
| 807 }, | |
| 808 | |
| 809 selectedIndex_: -1, | |
| 810 setSelectedIndex: function(i) { | |
| 811 if (i != this.selectedIndex_) { | |
| 812 var items = this.menu.children; | |
| 813 var oldItem = items[this.selectedIndex_]; | |
| 814 if (oldItem) { | |
| 815 oldItem.removeAttribute('selected'); | |
| 816 } | |
| 817 var newItem = items[i]; | |
| 818 if (newItem) { | |
| 819 newItem.setAttribute('selected', 'selected'); | |
| 820 } | |
| 821 this.selectedIndex_ = i; | |
| 822 } | |
| 823 }, | |
| 824 | |
| 825 getSelectedItem: function() { | |
| 826 return this.menu.children[this.selectedIndex_] || null; | |
| 827 }, | |
| 828 | |
| 829 executeItem: function(item) { | |
| 830 var command = item.getAttribute('command'); | |
| 831 if (command in this.commands) { | |
| 832 this.commands[command].call(this, item); | |
| 833 } | |
| 834 | |
| 835 this.hide(); | |
| 836 } | |
| 837 }; | |
| 838 | |
| 839 var optionMenu = new OptionMenu( | |
| 840 document.querySelector('#most-visited h2 .settings-wrapper'), | |
| 841 $('option-menu')); | |
| 842 optionMenu.commands = { | |
| 843 'clear-all-blacklisted' : function() { | |
| 844 mostVisited.clearAllBlacklisted(); | |
| 845 chrome.send('getMostVisited'); | |
| 846 } | |
| 847 }; | |
| 848 | |
| 849 $('main').addEventListener('click', function(e) { | 650 $('main').addEventListener('click', function(e) { |
| 850 var p = e.target; | 651 var p = e.target; |
| 851 while (p && p.tagName != 'H2') { | 652 while (p && p.tagName != 'H2') { |
| 653 // In case the user clicks on a button we do not want to expand/collapse a |
| 654 // section. |
| 655 if (p.tagName == 'BUTTON') |
| 656 return; |
| 852 p = p.parentNode; | 657 p = p.parentNode; |
| 853 } | 658 } |
| 854 | 659 |
| 855 if (!p) { | 660 if (!p) { |
| 856 return; | 661 return; |
| 857 } | 662 } |
| 858 | 663 |
| 859 p = p.parentNode; | 664 p = p.parentNode; |
| 860 if (!getSectionMaxiview(p)) { | 665 if (!getSectionMaxiview(p)) { |
| 861 return; | 666 return; |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1059 * The sync code is not yet built by default on all platforms so we have to | 864 * The sync code is not yet built by default on all platforms so we have to |
| 1060 * make sure we don't send the initial sync message to the backend unless the | 865 * make sure we don't send the initial sync message to the backend unless the |
| 1061 * backend told us that the sync code is present. | 866 * backend told us that the sync code is present. |
| 1062 */ | 867 */ |
| 1063 function callGetSyncMessageIfSyncIsPresent() { | 868 function callGetSyncMessageIfSyncIsPresent() { |
| 1064 if (document.documentElement.getAttribute('syncispresent') == 'true') { | 869 if (document.documentElement.getAttribute('syncispresent') == 'true') { |
| 1065 chrome.send('GetSyncMessage'); | 870 chrome.send('GetSyncMessage'); |
| 1066 } | 871 } |
| 1067 } | 872 } |
| 1068 | 873 |
| 1069 function hideAllMenus() { | |
| 1070 optionMenu.hide(); | |
| 1071 } | |
| 1072 | |
| 1073 window.addEventListener('blur', hideAllMenus); | |
| 1074 window.addEventListener('keydown', function(e) { | |
| 1075 if (e.keyIdentifier == 'Alt' || e.keyIdentifier == 'Meta') { | |
| 1076 hideAllMenus(); | |
| 1077 } | |
| 1078 }, true); | |
| 1079 | |
| 1080 // Tooltip for elements that have text that overflows. | 874 // Tooltip for elements that have text that overflows. |
| 1081 document.addEventListener('mouseover', function(e) { | 875 document.addEventListener('mouseover', function(e) { |
| 1082 // We don't want to do this while we are dragging because it makes things very | 876 // We don't want to do this while we are dragging because it makes things very |
| 1083 // janky | 877 // janky |
| 1084 if (mostVisited.isDragging()) { | 878 if (mostVisited.isDragging()) { |
| 1085 return; | 879 return; |
| 1086 } | 880 } |
| 1087 | 881 |
| 1088 var el = findAncestor(e.target, function(el) { | 882 var el = findAncestor(e.target, function(el) { |
| 1089 return el.xtitle; | 883 return el.xtitle; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1141 window.setTimeout(function() { | 935 window.setTimeout(function() { |
| 1142 mostVisited.ensureSmallGridCorrect(); | 936 mostVisited.ensureSmallGridCorrect(); |
| 1143 document.body.classList.remove('loading'); | 937 document.body.classList.remove('loading'); |
| 1144 }, 1); | 938 }, 1); |
| 1145 | 939 |
| 1146 // Only show the first run notification if first run. | 940 // Only show the first run notification if first run. |
| 1147 if (firstRun) { | 941 if (firstRun) { |
| 1148 showFirstRunNotification(); | 942 showFirstRunNotification(); |
| 1149 } | 943 } |
| 1150 } | 944 } |
| OLD | NEW |