1/** 2 * RCRiotOrder RiotJS mixin provides functionality to work with orders/carts in progress. Relies on /rcapi/order/... 3 * API callback paths. 4 */ 5(function($) { 6 /** 7 * Current order/cart data. Global reference for all users of this mixin. 8 * @type {} 9 */ 10 var orderdata = null 11 /** 12 * Optional bitly-generated short URL to share the current browser session order via URL link. 13 * @type {null} 14 */ 15 var orderShortUrl = null 16 /** 17 * RCRiotOrder mixin object 18 */ 19 var RCRiotOrder = { 20 /** 21 * Global observable for all users of this mixin for global mixin events. 22 */ 23 RCRiotOrder: riot.observable(), 24 init: function() { 25 this.mixin('RiotNotify') 26 if(!this.RCRiotUtils) { 27 this.mixin('RCRiotUtils') 28 } 29 this.orderStorage = 'local' 30 this.initOrderData() 31 }, 32 /** 33 * Given a price object provided from an availability search or price quote, add an order line item to the order 34 * in progress in the browser session with the specified priced item. 35 * @param price 36 * @returns promise that resolves with order data once the server responds with updated order data 37 */ 38 addOrderLineItem: function(price) { 39 var p, ro = this, od, ind, i = 0 40 if(this.orderStorage == 'local') { 41 od = this.getOrderData() 42 while(typeof ind == 'undefined') { 43 if(od.lis.hasOwnProperty('ind-' + i)) { 44 i++ 45 } else { 46 ind = 'ind-' + i 47 } 48 } 49 od.lis[ind] = price 50 od.lict++ 51 od.litot += parseFloat(price.p) 52 this.setOrderData(od) 53 p = $.Deferred() 54 p.resolve(od) 55 } else { 56 ro = this 57 p = $.Deferred(function() { 58 orderShortUrl = null; 59 ro.RCRiotOrder.trigger('UpdateStart'); 60 $.getJSON('/rcapi/order/add', price.qp).done(function(data) { 61 ro.setOrderData(data); 62 p.resolve(data) 63 }).always(function() { 64 ro.RCRiotOrder.trigger('UpdateStop'); 65 }).fail(function (e) { 66 p.reject(e) 67 }) 68 }) 69 } 70 return p 71 }, 72 /** 73 * Initiates checkout for the complete order in the current browser session by directing the browser to the 74 * appropriate checkout URL. 75 */ 76 doOrderCheckout: function() { 77 window.location = this.getOrderCheckoutURL() 78 }, 79 /** 80 * Generates if necessary and provides a bit.ly URL suitable for sharing the order in the current browser session 81 * with any other device via a simple URL 82 * @returns promise that resolves with the URL for the current browser session once fetched from local cache or 83 * bit.ly or fails with an exception 84 */ 85 getShortUrl: function(url) { 86 var self = this, 87 a = this.opts.bitly_access_token, 88 p = $.Deferred(), 89 u = location.protocol + '//' + location.host + '/' + url || this.getOrderSearchURL(), 90 r = 'https://api-ssl.bitly.com/v3/shorten?access_token='
90+ 91 a + '&longUrl=' + encodeURIComponent(url || u + '?rcod=' + this.getOrderHash()); 92 93 $.getJSON(r, {}) 94 .done(function(response) { 95 orderShortUrl = response.data.url; 96 p.resolve(response.data.url); 97 }) 98 .fail(function(err) { 99 p.reject(err); 100 }); 101 return p; 102 }, 103 /** 104 * Utility function to convert order data in the session to a BASE64 encoded JSON payload for URL sharing. 105 * @returns {string} 106 */ 107 getOrderHash: function() { 108 return btoa(JSON.stringify(this.getOrderData())) 109 }, 110 /** 111 * Redirects the browser to a provided path for the purpose of starting or refining an order. 112 * @param path 113 */ 114 doOrderSearch: function(path) { 115 window.location = path 116 }, 117 /** 118 * Remove an order line item from the order in progress based on the index in the order.lis collection. 119 * @param index 120 * @returns promise that resolves with order data once the server confirms line item removal or fails with ajax 121 * error 122 */ 123 removeOrderLineItem: function(index) { 124 if(this.orderStorage == 'local') { 125 var od = this.getOrderData() 126 od.lict-- 127 od.litot -= od.lis[index].p 128 delete(od.lis[index]) 129 this.setOrderData(od) 130 return $.Deferred(function() { return od; }) 131 } else { 132 var ro = this, p = $.Deferred() 133 this.RCRiotOrder.trigger('UpdateStart') 134 $.getJSON('/rcapi/order/remove', {'index': index}) 135 .done(function (data) { 136 orderShortUrl = null; 137 ro.setOrderData(data) 138 p.resolve(data) 139 }) 140 .fail(function (err) { 141 p.reject(err) 142 }) 143 .always(function () { 144 ro.RCRiotOrder.trigger('UpdateStop') 145 }) 146 return p 147 } 148 }, 149 /** 150 * Initiates the checkout / purchase process for a single line item in the order as opposed to all line items in 151 * the order at once 152 * 153 * @param {string} index the index in the orderdata.lis line items collection for purchase 154 */ 155 buyOrderLineItem: function(index) { 156 var od = this.getOrderData() 157 this.buyNow(od.lis[index]) 158 }, 159 /** 160 * Provides the URL path to the checkout screen for the order in the current browser session. 161 * 162 * @returns {string} the URL path for order checkout 163 */ 164 getOrderCheckoutURL: function() { 165 return '/rescms/order/checkout' 166 }, 167 /** 168 * Set current browser session order data and persist to localStorage 169 */ 170 setOrderData: function(data) { 171 localStorage.setItem('rcriotorder', JSON.stringify(data)) 172 orderdata = data 173 this.RCRiotOrder.trigger('OrderUpdated', data) 174 }, 175 /** 176 * Provide a detailed quote from the server. 177 * @param price 178 * @returns {*} 179 */ 180 showDetailedQuote: function(price, buytext) { 181 var p = $.Deferred(function() { 182 var qp = price.qp 183 qp.buy_text = buytext 184 $.getJSON('/rescms/ajax/item/pricing/quote', price.qp).done(function (data) { 185 p.resolve(data) 186 }).fail(function (e) { 187 p.reject(e) 188 }) 189 }) 190 return p 191 }, 192 /** 193 * Trigger an event to request that someone on the page show the current order, usually the trigger widget 194 */ 195 showOrderDetail: function() { 196 var self = this 197 RiotTagsModal.closeAll().done(function() { 198 self.RCRiotOrder.trigger('RequestShowOrder') 199 }) 200 }, 201 /** 202 * Get current browser session order data 203 * @returns {} 204 */ 205 getOrderData: function() { 206 return orderdata 207 }, 208 209 /** 210 * Prompts user if an existing order already exists, sets order, and opens 211 * trips modal window. 212 */ 213 openTrips: function(rcod, lsod) { 214 var od; 215 if ((typeof lsod.lict == 'undefined' && lsod.lict == 0) || 216 confirm('This Trips Collection will replace any Trips Collection you may have in progress. Would you like to proceed?')) { 217 od = JSON.parse(atob(rcod)); 218 this.setOrderData(od); 219 window.location.hash = ''; 220 setTimeout(this.showOrderDetail, 250); 221 } 222 }, 223 224 /** 225 * Loads current cart data from localStorage if available. Otherwise checks with the server for an order in 226 * progress and updates local storage. 227 */ 228 initOrderData: function() { 229 if(orderdata != null) return; 230 var self = this, params = this.RCRiotUtils.parseHash(), lsod = this.getLocalStorageOrderData(); 231 if (params.hasOwnProperty('short-url')) {
232 $.get('rescms/order/shorturl/' + params['short-url']).done(function (data) { 233 if (data) { 234 self.openTrips(data, lsod); 235 } 236 }); 237 } 238 else if (params.hasOwnProperty('rcod')) { 239 self.openTrips(params['rcod'], lsod); 240 } 241 if(orderdata == null ) { 242 if(lsod.lict) { 243 this.setOrderData(lsod) 244 } else if(this.orderStorage == 'session') { 245 $.getJSON('/rcapi/order/get').done(function (data) { 246 self.setOrderData(data) 247 }) 248 } else { 249 self.setOrderData({ 250 lict: 0, 251 lis: {}, 252 litot: 0 253 }) 254 } 255 } 256 }, 257 getLocalStorageOrderData: function() { 258 var od = {} 259 if(ostr = localStorage.getItem('rcriotorder')) { 260 od = JSON.parse(ostr) 261 } 262 return od 263 }, 264 /** 265 * Our captain's favorite function, given a price object returned from an availability search open a new window 266 * to buy that thing. 267 * 268 * @param price the priced item to purchase 269 */ 270 buyNow: function(price) { 271 window.open(this.RCRiotUtils.getBuyUrl(price)).focus(); 272 }, 273 274 /** 275 * @TODO this path needs to come from tag options 276 * @returns {string} 277 */ 278 getOrderSearchURL: function() { 279 return '/mytrip' 280 }, 281 282 hasOrderLineItems: function() { 283 var retval = false, od = this.getOrderData() 284 if(typeof od.lict != ' undefined' && parseInt(od.lict) > 0) { 285 retval = true 286 } 287 return retval 288 } 289 } 290 riot.mixin('RCRiotOrder', RCRiotOrder); 291})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.