1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 * @fileoverview The local InstantExtended NTP.
12 * Controls rendering the new tab page for InstantExtended.
13 * @return {Object} A limited interface for testing the local NTP.
20 * Alias for document.getElementById.
21 * @param {string} id The ID of the element to find.
22 * @return {HTMLElement} The found element or null if not found.
25 return document
.getElementById(id
);
30 * Specifications for an NTP design (not comprehensive).
32 * fakeboxWingSize: Extra distance for fakebox to extend beyond beyond the list
34 * fontFamily: Font family to use for title and thumbnail iframes.
35 * fontSize: Font size to use for the iframes, in px.
36 * mainClass: Class applied to #ntp-contents to control CSS.
37 * numTitleLines: Number of lines to display in titles.
38 * showFavicon: Whether to show favicon.
39 * thumbnailTextColor: The 4-component color that thumbnail iframe may use to
40 * display text message in place of missing thumbnail.
41 * thumbnailFallback: (Optional) A value in THUMBNAIL_FALLBACK to specify the
42 * thumbnail fallback strategy. If unassigned, then the thumbnail.html
43 * iframe would handle the fallback.
44 * tileWidth: The width of each suggestion tile, in px.
45 * tileMargin: Spacing between successive tiles, in px.
46 * titleColor: The 4-component color of title text.
47 * titleColorAgainstDark: The 4-component color of title text against a dark
49 * titleTextAlign: (Optional) The alignment of title text. If unspecified, the
50 * default value is 'center'.
51 * titleTextFade: (Optional) The number of pixels beyond which title
52 * text begins to fade. This overrides the default ellipsis style.
55 * fakeboxWingSize: number,
59 * numTitleLines: number,
60 * showFavicon: boolean,
61 * thumbnailTextColor: string,
62 * thumbnailFallback: string|null|undefined,
66 * titleColorAgainstDark: string,
67 * titleTextAlign: string|null|undefined,
68 * titleTextFade: number|null|undefined
73 fontFamily
: 'arial, sans-serif',
75 mainClass
: 'thumb-ntp',
78 thumbnailTextColor
: [50, 50, 50, 255],
79 thumbnailFallback
: 'dot', // Draw single dot.
82 titleColor
: [50, 50, 50, 255],
83 titleColorAgainstDark
: [210, 210, 210, 255],
84 titleTextAlign
: 'inherit',
85 titleTextFade
: 122 - 36 // 112px wide title with 32 pixel fade at end.
90 * Modifies NTP_DESIGN parameters for icon NTP.
92 function modifyNtpDesignForIcons() {
93 NTP_DESIGN
.fakeboxWingSize
= 132;
94 NTP_DESIGN
.mainClass
= 'icon-ntp';
95 NTP_DESIGN
.numTitleLines
= 2;
96 NTP_DESIGN
.showFavicon
= false;
97 NTP_DESIGN
.thumbnailFallback
= null;
98 NTP_DESIGN
.tileWidth
= 48 + 2 * 18;
99 NTP_DESIGN
.tileMargin
= 60 - 18 * 2;
100 NTP_DESIGN
.titleColor
= [120, 120, 120, 255];
101 NTP_DESIGN
.titleColorAgainstDark
= [210, 210, 210, 255];
102 NTP_DESIGN
.titleTextAlign
= 'center';
103 delete NTP_DESIGN
.titleTextFade
;
108 * Enum for classnames.
113 ALTERNATE_LOGO
: 'alternate-logo', // Shows white logo if required by theme
115 DEFAULT_THEME
: 'default-theme',
116 DELAYED_HIDE_NOTIFICATION
: 'mv-notice-delayed-hide',
117 FAKEBOX_DISABLE
: 'fakebox-disable', // Makes fakebox non-interactive
118 FAKEBOX_FOCUS
: 'fakebox-focused', // Applies focus styles to the fakebox
119 // Applies drag focus style to the fakebox
120 FAKEBOX_DRAG_FOCUS
: 'fakebox-drag-focused',
121 HIDE_FAKEBOX_AND_LOGO
: 'hide-fakebox-logo',
122 HIDE_NOTIFICATION
: 'mv-notice-hide',
123 // Vertically centers the most visited section for a non-Google provided page.
124 NON_GOOGLE_PAGE
: 'non-google-page',
125 RTL
: 'rtl' // Right-to-left language text.
130 * Enum for HTML element ids.
135 ATTRIBUTION
: 'attribution',
136 ATTRIBUTION_TEXT
: 'attribution-text',
137 CUSTOM_THEME_STYLE
: 'ct-style',
139 FAKEBOX_INPUT
: 'fakebox-input',
140 FAKEBOX_TEXT
: 'fakebox-text',
142 NOTIFICATION
: 'mv-notice',
143 NOTIFICATION_CLOSE_BUTTON
: 'mv-notice-x',
144 NOTIFICATION_MESSAGE
: 'mv-msg',
145 NTP_CONTENTS
: 'ntp-contents',
146 RESTORE_ALL_LINK
: 'mv-restore',
163 * Enum for the state of the NTP when it is disposed.
167 var NTP_DISPOSE_STATE
= {
168 NONE
: 0, // Preserve the NTP appearance and functionality
170 HIDE_FAKEBOX_AND_LOGO
: 2
175 * The notification displayed when a page is blacklisted.
182 * The container for the theme attribution.
189 * The "fakebox" - an input field that looks like a regular searchbox. When it
190 * is focused, any text the user types goes directly into the omnibox.
197 * The container for NTP elements.
204 * The last blacklisted tile rid if any, which by definition should not be
208 var lastBlacklistedTile
= null;
212 * Current number of tiles columns shown based on the window width, including
213 * those that just contain filler.
216 var numColumnsShown
= 0;
220 * The browser embeddedSearch.newTabPage object.
227 * The browser embeddedSearch.searchBox object.
230 var searchboxApiHandle
;
234 * The state of the NTP when a query is entered into the Omnibox.
235 * @type {NTP_DISPOSE_STATE}
237 var omniboxInputBehavior
= NTP_DISPOSE_STATE
.NONE
;
241 * The state of the NTP when a query is entered into the Fakebox.
242 * @type {NTP_DISPOSE_STATE}
244 var fakeboxInputBehavior
= NTP_DISPOSE_STATE
.HIDE_FAKEBOX_AND_LOGO
;
247 /** @type {number} @const */
248 var MAX_NUM_TILES_TO_SHOW
= 8;
251 /** @type {number} @const */
252 var MIN_NUM_COLUMNS
= 2;
255 /** @type {number} @const */
256 var MAX_NUM_COLUMNS
= 4;
259 /** @type {number} @const */
264 * Minimum total padding to give to the left and right of the most visited
265 * section. Used to determine how many tiles to show.
269 var MIN_TOTAL_HORIZONTAL_PADDING
= 200;
273 * Heuristic to determine whether a theme should be considered to be dark, so
274 * the colors of various UI elements can be adjusted.
275 * @param {ThemeBackgroundInfo|undefined} info Theme background information.
276 * @return {boolean} Whether the theme is dark.
279 function getIsThemeDark(info
) {
282 // Heuristic: light text implies dark theme.
283 var rgba
= info
.textColorRgba
;
284 var luminance
= 0.3 * rgba
[0] + 0.59 * rgba
[1] + 0.11 * rgba
[2];
285 return luminance
>= 128;
290 * Updates the NTP based on the current theme.
293 function renderTheme() {
294 var fakeboxText
= $(IDS
.FAKEBOX_TEXT
);
296 fakeboxText
.innerHTML
= '';
297 if (configData
.translatedStrings
.searchboxPlaceholder
) {
298 fakeboxText
.textContent
=
299 configData
.translatedStrings
.searchboxPlaceholder
;
303 var info
= ntpApiHandle
.themeBackgroundInfo
;
304 var isThemeDark
= getIsThemeDark(info
);
305 ntpContents
.classList
.toggle(CLASSES
.DARK
, isThemeDark
);
310 var background
= [convertToRGBAColor(info
.backgroundColorRgba
),
313 info
.imageHorizontalAlignment
,
314 info
.imageVerticalAlignment
].join(' ').trim();
316 document
.body
.style
.background
= background
;
317 document
.body
.classList
.toggle(CLASSES
.ALTERNATE_LOGO
, info
.alternateLogo
);
318 updateThemeAttribution(info
.attributionUrl
);
319 setCustomThemeStyle(info
);
321 var themeinfo
= {cmd
: 'updateTheme'};
322 if (!info
.usingDefaultTheme
) {
323 themeinfo
.tileBorderColor
= convertToRGBAColor(info
.sectionBorderColorRgba
);
324 themeinfo
.tileHoverBorderColor
= convertToRGBAColor(info
.headerColorRgba
);
326 themeinfo
.isThemeDark
= isThemeDark
;
328 var titleColor
= NTP_DESIGN
.titleColor
;
329 if (!info
.usingDefaultTheme
&& info
.textColorRgba
) {
330 titleColor
= info
.textColorRgba
;
331 } else if (isThemeDark
) {
332 titleColor
= NTP_DESIGN
.titleColorAgainstDark
;
334 themeinfo
.tileTitleColor
= convertToRGBAColor(titleColor
);
336 $('mv-single').contentWindow
.postMessage(themeinfo
, '*');
341 * Updates the NTP based on the current theme, then rerenders all tiles.
344 function onThemeChange() {
350 * Updates the NTP style according to theme.
351 * @param {Object=} opt_themeInfo The information about the theme. If it is
352 * omitted the style will be reverted to the default.
355 function setCustomThemeStyle(opt_themeInfo
) {
356 var customStyleElement
= $(IDS
.CUSTOM_THEME_STYLE
);
357 var head
= document
.head
;
358 if (opt_themeInfo
&& !opt_themeInfo
.usingDefaultTheme
) {
359 ntpContents
.classList
.remove(CLASSES
.DEFAULT_THEME
);
362 ' color: ' + convertToRGBAColor(opt_themeInfo
.textColorLightRgba
) + ';' +
365 ' color: ' + convertToRGBAColor(opt_themeInfo
.textColorRgba
) + ';' +
367 '#mv-notice-links span {' +
368 ' color: ' + convertToRGBAColor(opt_themeInfo
.textColorLightRgba
) + ';' +
371 ' -webkit-filter: drop-shadow(0 0 0 ' +
372 convertToRGBAColor(opt_themeInfo
.textColorRgba
) + ');' +
374 '.mv-page-ready .mv-mask {' +
375 ' border: 1px solid ' +
376 convertToRGBAColor(opt_themeInfo
.sectionBorderColorRgba
) + ';' +
378 '.mv-page-ready:hover .mv-mask, .mv-page-ready .mv-focused ~ .mv-mask {' +
380 convertToRGBAColor(opt_themeInfo
.headerColorRgba
) + ';' +
383 if (customStyleElement
) {
384 customStyleElement
.textContent
= themeStyle
;
386 customStyleElement
= document
.createElement('style');
387 customStyleElement
.type
= 'text/css';
388 customStyleElement
.id
= IDS
.CUSTOM_THEME_STYLE
;
389 customStyleElement
.textContent
= themeStyle
;
390 head
.appendChild(customStyleElement
);
394 ntpContents
.classList
.add(CLASSES
.DEFAULT_THEME
);
395 if (customStyleElement
)
396 head
.removeChild(customStyleElement
);
402 * Renders the attribution if the URL is present, otherwise hides it.
403 * @param {string} url The URL of the attribution image, if any.
406 function updateThemeAttribution(url
) {
408 setAttributionVisibility_(false);
412 var attributionImage
= attribution
.querySelector('img');
413 if (!attributionImage
) {
414 attributionImage
= new Image();
415 attribution
.appendChild(attributionImage
);
417 attributionImage
.style
.content
= url
;
418 setAttributionVisibility_(true);
423 * Sets the visibility of the theme attribution.
424 * @param {boolean} show True to show the attribution.
427 function setAttributionVisibility_(show
) {
429 attribution
.style
.display
= show
? '' : 'none';
435 * Converts an Array of color components into RRGGBBAA format.
436 * @param {Array<number>} color Array of rgba color components.
437 * @return {string} Color string in RRGGBBAA format.
440 function convertToRRGGBBAAColor(color
) {
441 return color
.map(function(t
) {
442 return ('0' + t
.toString(16)).slice(-2); // To 2-digit, 0-padded hex.
448 * Converts an Array of color components into RGBA format "rgba(R,G,B,A)".
449 * @param {Array<number>} color Array of rgba color components.
450 * @return {string} CSS color in RGBA format.
453 function convertToRGBAColor(color
) {
454 return 'rgba(' + color
[0] + ',' + color
[1] + ',' + color
[2] + ',' +
455 color
[3] / 255 + ')';
460 * Called when page data change.
462 function onMostVisitedChange() {
468 * Fetches new data, creates, and renders tiles.
470 function reloadTiles() {
471 var pages
= ntpApiHandle
.mostVisited
;
473 for (var i
= 0; i
< Math
.min(MAX_NUM_TILES_TO_SHOW
, pages
.length
); ++i
) {
474 cmds
.push({cmd
: 'tile', rid
: pages
[i
].rid
});
476 cmds
.push({cmd
: 'show', maxVisible
: numColumnsShown
* NUM_ROWS
});
478 $('mv-single').contentWindow
.postMessage(cmds
, '*');
483 * Shows the blacklist notification and triggers a delay to hide it.
485 function showNotification() {
486 notification
.classList
.remove(CLASSES
.HIDE_NOTIFICATION
);
487 notification
.classList
.remove(CLASSES
.DELAYED_HIDE_NOTIFICATION
);
488 notification
.scrollTop
;
489 notification
.classList
.add(CLASSES
.DELAYED_HIDE_NOTIFICATION
);
494 * Hides the blacklist notification.
496 function hideNotification() {
497 notification
.classList
.add(CLASSES
.HIDE_NOTIFICATION
);
498 notification
.classList
.remove(CLASSES
.DELAYED_HIDE_NOTIFICATION
);
503 * Handles a click on the notification undo link by hiding the notification and
508 if (lastBlacklistedTile
!= null) {
509 ntpApiHandle
.undoMostVisitedDeletion(lastBlacklistedTile
);
515 * Handles a click on the restore all notification link by hiding the
516 * notification and informing Chrome.
518 function onRestoreAll() {
520 ntpApiHandle
.undoAllMostVisitedDeletions();
525 * Recomputes the number of tile columns, and width of various contents based
526 * on the width of the window.
527 * @return {boolean} Whether the number of tile columns has changed.
529 function updateContentWidth() {
530 var tileRequiredWidth
= NTP_DESIGN
.tileWidth
+ NTP_DESIGN
.tileMargin
;
531 // If innerWidth is zero, then use the maximum snap size.
532 var maxSnapSize
= MAX_NUM_COLUMNS
* tileRequiredWidth
-
533 NTP_DESIGN
.tileMargin
+ MIN_TOTAL_HORIZONTAL_PADDING
;
534 var innerWidth
= window
.innerWidth
|| maxSnapSize
;
535 // Each tile has left and right margins that sum to NTP_DESIGN.tileMargin.
536 var availableWidth
= innerWidth
+ NTP_DESIGN
.tileMargin
-
537 NTP_DESIGN
.fakeboxWingSize
* 2 - MIN_TOTAL_HORIZONTAL_PADDING
;
538 var newNumColumns
= Math
.floor(availableWidth
/ tileRequiredWidth
);
539 if (newNumColumns
< MIN_NUM_COLUMNS
)
540 newNumColumns
= MIN_NUM_COLUMNS
;
541 else if (newNumColumns
> MAX_NUM_COLUMNS
)
542 newNumColumns
= MAX_NUM_COLUMNS
;
544 if (numColumnsShown
=== newNumColumns
)
547 numColumnsShown
= newNumColumns
;
548 var tilesContainerWidth
= numColumnsShown
* tileRequiredWidth
;
549 $(IDS
.TILES
).style
.width
= tilesContainerWidth
+ 'px';
551 // -2 to account for border.
552 var fakeboxWidth
= (tilesContainerWidth
- NTP_DESIGN
.tileMargin
- 2);
553 fakeboxWidth
+= NTP_DESIGN
.fakeboxWingSize
* 2;
554 fakebox
.style
.width
= fakeboxWidth
+ 'px';
561 * Resizes elements because the number of tile columns may need to change in
562 * response to resizing. Also shows or hides extra tiles tiles according to the
563 * new width of the page.
565 function onResize() {
566 updateContentWidth();
567 $('mv-single').contentWindow
.postMessage(
568 {cmd
: 'tilesVisible', maxVisible
: numColumnsShown
* NUM_ROWS
}, '*');
573 * Handles new input by disposing the NTP, according to where the input was
576 function onInputStart() {
577 if (fakebox
&& isFakeboxFocused()) {
578 setFakeboxFocus(false);
579 setFakeboxDragFocus(false);
581 } else if (!isFakeboxFocused()) {
588 * Disposes the NTP, according to where the input was entered.
589 * @param {boolean} wasFakeboxInput True if the input was in the fakebox.
591 function disposeNtp(wasFakeboxInput
) {
592 var behavior
= wasFakeboxInput
? fakeboxInputBehavior
: omniboxInputBehavior
;
593 if (behavior
== NTP_DISPOSE_STATE
.DISABLE_FAKEBOX
)
594 setFakeboxActive(false);
595 else if (behavior
== NTP_DISPOSE_STATE
.HIDE_FAKEBOX_AND_LOGO
)
596 setFakeboxAndLogoVisibility(false);
601 * Restores the NTP (re-enables the fakebox and unhides the logo.)
603 function restoreNtp() {
604 setFakeboxActive(true);
605 setFakeboxAndLogoVisibility(true);
610 * @param {boolean} focus True to focus the fakebox.
612 function setFakeboxFocus(focus
) {
613 document
.body
.classList
.toggle(CLASSES
.FAKEBOX_FOCUS
, focus
);
617 * @param {boolean} focus True to show a dragging focus to the fakebox.
619 function setFakeboxDragFocus(focus
) {
620 document
.body
.classList
.toggle(CLASSES
.FAKEBOX_DRAG_FOCUS
, focus
);
624 * @return {boolean} True if the fakebox has focus.
626 function isFakeboxFocused() {
627 return document
.body
.classList
.contains(CLASSES
.FAKEBOX_FOCUS
) ||
628 document
.body
.classList
.contains(CLASSES
.FAKEBOX_DRAG_FOCUS
);
633 * @param {boolean} enable True to enable the fakebox.
635 function setFakeboxActive(enable
) {
636 document
.body
.classList
.toggle(CLASSES
.FAKEBOX_DISABLE
, !enable
);
641 * @param {!Event} event The click event.
642 * @return {boolean} True if the click occurred in an enabled fakebox.
644 function isFakeboxClick(event
) {
645 return fakebox
.contains(event
.target
) &&
646 !document
.body
.classList
.contains(CLASSES
.FAKEBOX_DISABLE
);
651 * @param {boolean} show True to show the fakebox and logo.
653 function setFakeboxAndLogoVisibility(show
) {
654 document
.body
.classList
.toggle(CLASSES
.HIDE_FAKEBOX_AND_LOGO
, !show
);
659 * Shortcut for document.getElementById.
660 * @param {string} id of the element.
661 * @return {HTMLElement} with the id.
664 return document
.getElementById(id
);
669 * Utility function which creates an element with an optional classname and
670 * appends it to the specified parent.
671 * @param {Element} parent The parent to append the new element.
672 * @param {string} name The name of the new element.
673 * @param {string=} opt_class The optional classname of the new element.
674 * @return {Element} The new element.
676 function createAndAppendElement(parent
, name
, opt_class
) {
677 var child
= document
.createElement(name
);
679 child
.classList
.add(opt_class
);
680 parent
.appendChild(child
);
686 * @param {!Element} element The element to register the handler for.
687 * @param {number} keycode The keycode of the key to register.
688 * @param {!Function} handler The key handler to register.
690 function registerKeyHandler(element
, keycode
, handler
) {
691 element
.addEventListener('keydown', function(event
) {
692 if (event
.keyCode
== keycode
)
699 * @return {Object} the handle to the embeddedSearch API.
701 function getEmbeddedSearchApiHandle() {
704 if (window
.chrome
&& window
.chrome
.embeddedSearch
)
705 return window
.chrome
.embeddedSearch
;
711 * Event handler for the focus changed and blacklist messages on link elements.
712 * Used to toggle visual treatment on the tiles (depending on the message).
713 * @param {Event} event Event received.
715 function handlePostMessage(event
) {
716 var cmd
= event
.data
.cmd
;
717 var args
= event
.data
;
718 if (cmd
== 'tileBlacklisted') {
720 lastBlacklistedTile
= args
.tid
;
722 ntpApiHandle
.deleteMostVisitedItem(args
.tid
);
728 * Prepares the New Tab Page by adding listeners, rendering the current
729 * theme, the most visited pages section, and Google-specific elements for a
730 * Google-provided page.
733 notification
= $(IDS
.NOTIFICATION
);
734 attribution
= $(IDS
.ATTRIBUTION
);
735 ntpContents
= $(IDS
.NTP_CONTENTS
);
737 if (configData
.isGooglePage
) {
738 var logo
= document
.createElement('div');
740 logo
.title
= 'Google';
742 fakebox
= document
.createElement('div');
743 fakebox
.id
= IDS
.FAKEBOX
;
744 var fakeboxHtml
= [];
745 fakeboxHtml
.push('<div id="' + IDS
.FAKEBOX_TEXT
+ '"></div>');
746 fakeboxHtml
.push('<input id="' + IDS
.FAKEBOX_INPUT
+
747 '" autocomplete="off" tabindex="-1" type="url" aria-hidden="true">');
748 fakeboxHtml
.push('<div id="cursor"></div>');
749 fakebox
.innerHTML
= fakeboxHtml
.join('');
751 ntpContents
.insertBefore(fakebox
, ntpContents
.firstChild
);
752 ntpContents
.insertBefore(logo
, ntpContents
.firstChild
);
754 document
.body
.classList
.add(CLASSES
.NON_GOOGLE_PAGE
);
757 // Modify design for experimental icon NTP, if specified.
758 if (configData
.useIcons
)
759 modifyNtpDesignForIcons();
760 document
.querySelector('#ntp-contents').classList
.add(NTP_DESIGN
.mainClass
);
762 // Hide notifications after fade out, so we can't focus on links via keyboard.
763 notification
.addEventListener('webkitTransitionEnd', hideNotification
);
765 var notificationMessage
= $(IDS
.NOTIFICATION_MESSAGE
);
766 notificationMessage
.textContent
=
767 configData
.translatedStrings
.thumbnailRemovedNotification
;
769 var undoLink
= $(IDS
.UNDO_LINK
);
770 undoLink
.addEventListener('click', onUndo
);
771 registerKeyHandler(undoLink
, KEYCODE
.ENTER
, onUndo
);
772 undoLink
.textContent
= configData
.translatedStrings
.undoThumbnailRemove
;
774 var restoreAllLink
= $(IDS
.RESTORE_ALL_LINK
);
775 restoreAllLink
.addEventListener('click', onRestoreAll
);
776 registerKeyHandler(restoreAllLink
, KEYCODE
.ENTER
, onUndo
);
777 restoreAllLink
.textContent
=
778 configData
.translatedStrings
.restoreThumbnailsShort
;
780 $(IDS
.ATTRIBUTION_TEXT
).textContent
=
781 configData
.translatedStrings
.attributionIntro
;
783 var notificationCloseButton
= $(IDS
.NOTIFICATION_CLOSE_BUTTON
);
784 createAndAppendElement(
785 notificationCloseButton
, 'div', CLASSES
.BLACKLIST_BUTTON_INNER
);
786 notificationCloseButton
.addEventListener('click', hideNotification
);
788 window
.addEventListener('resize', onResize
);
789 updateContentWidth();
791 var topLevelHandle
= getEmbeddedSearchApiHandle();
793 ntpApiHandle
= topLevelHandle
.newTabPage
;
794 ntpApiHandle
.onthemechange
= onThemeChange
;
795 ntpApiHandle
.onmostvisitedchange
= onMostVisitedChange
;
797 ntpApiHandle
.oninputstart
= onInputStart
;
798 ntpApiHandle
.oninputcancel
= restoreNtp
;
800 if (ntpApiHandle
.isInputInProgress
)
803 searchboxApiHandle
= topLevelHandle
.searchBox
;
806 // Listener for updating the key capture state.
807 document
.body
.onmousedown = function(event
) {
808 if (isFakeboxClick(event
))
809 searchboxApiHandle
.startCapturingKeyStrokes();
810 else if (isFakeboxFocused())
811 searchboxApiHandle
.stopCapturingKeyStrokes();
813 searchboxApiHandle
.onkeycapturechange = function() {
814 setFakeboxFocus(searchboxApiHandle
.isKeyCaptureEnabled
);
816 var inputbox
= $(IDS
.FAKEBOX_INPUT
);
818 inputbox
.onpaste = function(event
) {
819 event
.preventDefault();
820 // Send pasted text to Omnibox.
821 var text
= event
.clipboardData
.getData('text/plain');
823 searchboxApiHandle
.paste(text
);
825 inputbox
.ondrop = function(event
) {
826 event
.preventDefault();
827 var text
= event
.dataTransfer
.getData('text/plain');
829 searchboxApiHandle
.paste(text
);
831 setFakeboxDragFocus(false);
833 inputbox
.ondragenter = function() {
834 setFakeboxDragFocus(true);
836 inputbox
.ondragleave = function() {
837 setFakeboxDragFocus(false);
841 // Update the fakebox style to match the current key capturing state.
842 setFakeboxFocus(searchboxApiHandle
.isKeyCaptureEnabled
);
845 if (searchboxApiHandle
.rtl
) {
846 $(IDS
.NOTIFICATION
).dir
= 'rtl';
847 // Grabbing the root HTML element.
848 document
.documentElement
.setAttribute('dir', 'rtl');
849 // Add class for setting alignments based on language directionality.
850 document
.documentElement
.classList
.add(CLASSES
.RTL
);
853 var iframe
= document
.createElement('iframe');
854 // Change the order of tabbing the page to start with NTP tiles.
855 iframe
.setAttribute('tabindex', '1');
856 iframe
.id
= 'mv-single';
860 if (searchboxApiHandle
.rtl
)
862 if (window
.configData
.useIcons
)
863 args
.push('icons=1');
864 if (NTP_DESIGN
.numTitleLines
> 1)
865 args
.push('ntl=' + NTP_DESIGN
.numTitleLines
);
867 args
.push('removeTooltip=' +
868 encodeURIComponent(configData
.translatedStrings
.removeThumbnailTooltip
));
870 iframe
.src
= '//most-visited/single.html?' + args
.join('&');
871 $(IDS
.TILES
).appendChild(iframe
);
873 iframe
.onload = function() {
878 window
.addEventListener('message', handlePostMessage
);
883 * Binds event listeners.
886 document
.addEventListener('DOMContentLoaded', init
);
895 if (!window
.localNTPUnitTest
) {