1 // Copyright (c) 2012 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. 4 5 cr.define('print_preview', function() { 6 'use strict'; 7 8 /** 9 * Component that renders a destination item in a destination list. 10 * @param {!cr.EventTarget} eventTarget Event target to dispatch selection 11 * events to. 12 * @param {!print_preview.Destination} destination Destination data object to 13 * render. 14 * @param {RegExp} query Active filter query. 15 * @constructor 16 * @extends {print_preview.Component} 17 */ 18 function DestinationListItem(eventTarget, destination, query) { 19 print_preview.Component.call(this); 20 21 /** 22 * Event target to dispatch selection events to. 23 * @type {!cr.EventTarget} 24 * @private 25 */ 26 this.eventTarget_ = eventTarget; 27 28 /** 29 * Destination that the list item renders. 30 * @type {!print_preview.Destination} 31 * @private 32 */ 33 this.destination_ = destination; 34 35 /** 36 * Active filter query text. 37 * @type {RegExp} 38 * @private 39 */ 40 this.query_ = query; 41 42 /** 43 * FedEx terms-of-service widget or {@code null} if this list item does not 44 * render the FedEx Office print destination. 45 * @type {print_preview.FedexTos} 46 * @private 47 */ 48 this.fedexTos_ = null; 49 }; 50 51 /** 52 * Event types dispatched by the destination list item. 53 * @enum {string} 54 */ 55 DestinationListItem.EventType = { 56 // Dispatched when the list item is activated. 57 SELECT: 'print_preview.DestinationListItem.SELECT', 58 REGISTER_PROMO_CLICKED: 59 'print_preview.DestinationListItem.REGISTER_PROMO_CLICKED' 60 }; 61 62 /** 63 * CSS classes used by the destination list item. 64 * @enum {string} 65 * @private 66 */ 67 DestinationListItem.Classes_ = { 68 ICON: 'destination-list-item-icon', 69 NAME: 'destination-list-item-name', 70 STALE: 'stale' 71 }; 72 73 DestinationListItem.prototype = { 74 __proto__: print_preview.Component.prototype, 75 76 /** @override */ 77 createDom: function() { 78 this.setElementInternal(this.cloneTemplateInternal( 79 'destination-list-item-template')); 80 81 var iconImg = this.getElement().getElementsByClassName( 82 print_preview.DestinationListItem.Classes_.ICON)[0]; 83 iconImg.src = this.destination_.iconUrl; 84 85 var nameEl = this.getElement().getElementsByClassName( 86 DestinationListItem.Classes_.NAME)[0]; 87 var textContent = this.destination_.displayName; 88 if (this.query_) { 89 // When search query is specified, make it obvious why the particular 90 // printer made it to the list. Display name is always visible, even if 91 // it does not match the search query. 92 this.addTextWithHighlight_(nameEl, textContent); 93 // Show the first matching property. 94 this.destination_.extraPropertiesToMatch.some(function(property) { 95 if (property.match(this.query_)) { 96 var hintSpan = document.createElement('span'); 97 hintSpan.className = 'search-hint'; 98 nameEl.appendChild(hintSpan); 99 this.addTextWithHighlight_(hintSpan, property); 100 // Add the same property to the element title. 101 textContent += ' (' + property + ')'; 102 return true; 103 } 104 }, this); 105 } else { 106 // Show just the display name and nothing else to lessen visual clutter. 107 nameEl.textContent = textContent; 108 } 109 nameEl.title = textContent; 110 111 this.initializeOfflineStatusElement_(); 112 this.initializeRegistrationPromoElement_(); 113 }, 114 115 /** @override */ 116 enterDocument: function() { 117 print_preview.Component.prototype.enterDocument.call(this); 118 this.tracker.add(this.getElement(), 'click', this.onActivate_.bind(this)); 119 }, 120 121 /** 122 * Initializes the element which renders the print destination's 123 * offline status. 124 * @private 125 */ 126 initializeOfflineStatusElement_: function() { 127 if (this.destination_.isOffline) { 128 this.getElement().classList.add(DestinationListItem.Classes_.STALE); 129 var offlineStatusEl = this.getChildElement('.offline-status'); 130 offlineStatusEl.textContent = this.destination_.offlineStatusText; 131 setIsVisible(offlineStatusEl, true); 132 } 133 }, 134 135 /** 136 * Initialize registration promo element for Privet unregistered printers. 137 */ 138 initializeRegistrationPromoElement_: function() { 139 if (this.destination_.connectionStatus == 140 print_preview.Destination.ConnectionStatus.UNREGISTERED) { 141 var registerBtnEl = this.getChildElement('.register-promo-button'); 142 registerBtnEl.addEventListener('click', 143 this.onRegisterPromoClicked_.bind(this)); 144 145 var registerPromoEl = this.getChildElement('.register-promo'); 146 setIsVisible(registerPromoEl, true); 147 } 148 }, 149 150 /** 151 * Adds text to parent element wrapping search query matches in highlighted 152 * spans. 153 * @param {!Element} parent Element to build the text in. 154 * @param {string} text The text string to highlight segments in. 155 * @private 156 */ 157 addTextWithHighlight_: function(parent, text) { 158 var sections = text.split(this.query_); 159 for (var i = 0; i < sections.length; ++i) { 160 if (i % 2 == 0) { 161 parent.appendChild(document.createTextNode(sections[i])); 162 } else { 163 var span = document.createElement('span'); 164 span.className = 'destination-list-item-query-highlight'; 165 span.textContent = sections[i]; 166 parent.appendChild(span); 167 } 168 } 169 }, 170 171 /** 172 * Called when the destination item is activated. Dispatches a SELECT event 173 * on the given event target. 174 * @private 175 */ 176 onActivate_: function() { 177 if (this.destination_.id == 178 print_preview.Destination.GooglePromotedId.FEDEX && 179 !this.destination_.isTosAccepted) { 180 if (!this.fedexTos_) { 181 this.fedexTos_ = new print_preview.FedexTos(); 182 this.fedexTos_.render(this.getElement()); 183 this.tracker.add( 184 this.fedexTos_, 185 print_preview.FedexTos.EventType.AGREE, 186 this.onTosAgree_.bind(this)); 187 } 188 this.fedexTos_.setIsVisible(true); 189 } else if (this.destination_.connectionStatus != 190 print_preview.Destination.ConnectionStatus.UNREGISTERED) { 191 var selectEvt = new Event(DestinationListItem.EventType.SELECT); 192 selectEvt.destination = this.destination_; 193 this.eventTarget_.dispatchEvent(selectEvt); 194 } 195 }, 196 197 /** 198 * Called when the user agrees to the print destination's terms-of-service. 199 * Selects the print destination that was agreed to. 200 * @private 201 */ 202 onTosAgree_: function() { 203 var selectEvt = new Event(DestinationListItem.EventType.SELECT); 204 selectEvt.destination = this.destination_; 205 this.eventTarget_.dispatchEvent(selectEvt); 206 }, 207 208 /** 209 * Called when the registration promo is clicked. 210 * @private 211 */ 212 onRegisterPromoClicked_: function() { 213 var promoClickedEvent = new Event( 214 DestinationListItem.EventType.REGISTER_PROMO_CLICKED); 215 promoClickedEvent.destination = this.destination_; 216 this.eventTarget_.dispatchEvent(promoClickedEvent); 217 } 218 }; 219 220 // Export 221 return { 222 DestinationListItem: DestinationListItem 223 }; 224 }); 225