1// BETA VERSION -- 6/30/17 2// TODO: need to test all link and slideshow senarios 3// TODO: when textOverImage is false cardItem needs to be flexed 4// FIXME: slideshow loop + link all causes a problem with cloned items 5// NOTE: refer to https://owlcarousel2.github.io/OwlCarousel2/docs/started-welcome.html for carousel options 6 7 8extend(saffire, { 9 widgets: { 10 cardWidget: function(el, opts) { 11 var $el = el; 12 var widget = {}; 13 var defaults = { 14 buyNowButton: { 15 visible: true, 16 text: 'BUY NOW' 17 }, 18 cardWidgetLoaded: function(data, owl, hasData) {}, 19 contentType: 'application/json; charset=utf-8', 20 currentWidgetModuleItemID: 0, 21 dataType: 'json', 22 itemsPerPanel: 1, 23 hasImages: true, 24 lazyLoadImages: true, 25 imageIsBackground: true, 26 link: [], // [], ['all'], ['image', 'title', 'description'] 27 maxItemsVisible: 4, 28 moreButton: { 29 visible: true, 30 text: 'MORE >' 31 }, 32 scriptPath: "services/eventsservice.asmx", 33 showDescription: false, 34 slideshow: false, 35 slideshowOptions: { 36 loop: true, 37 margin: 10, 38 nav: true 39 }, 40 textOverImage: true 41 }; 42 43 opts = extend(defaults, opts); 44 45 /** 46 * Retreives data for the widget. 47 * @protected 48 */ 49 widget.data = saffire.utils.getWidgetData(opts); 50 widget.data.then(function(res) { 51 widget.items = res.Sponsors || res.Slides; 52 (widget.items.length < 1) ? widget.noData(res): widget.setup(res); 53 }); 54 55 /** 56 * Sets up the HTML for the Widget. 57 * @public 58 */ 59 widget.setup = function(data) { 60 $el.addClass('loading'); 61 // convert image links to SSL if the page is encrypted 62 PAGESSL ? convertSources() : null; 63 64 // initialize an array to hold the card items 65 widget.cards = []; 66 67 // what needs to be links? 68 var linkAll = opts.link.indexOf('all') > -1; 69 var linkImage = opts.link.indexOf('image') > -1; 70 var linkTitle = opts.link.indexOf('title') > -1; 71 var linkDescription = opts.link.indexOf('description') > -1; 72 73 // build widget content 74 this.items.map(function(item, index) { 75 if (((index + 1) <= opts.maxItemsVisible) || opts.maxItemsVisible === 0) { 76 77 var cardItem = new Element(item, 'card-widget-item', linkAll, 'div', ''); 78 var cardContent = new Element(item, 'card-content', (linkTitle && linkDescription), 'div', ''); 79 var buttonWrap = new Element(item, 'buttonwrap', false, 'div', widget.buildButtons(item)); 80 var title = new Element(item, 'card-widget-title', (linkTitle && !linkDescription), 'span', item.Title); 81 82 // add contents to the text and button container 83 cardContent.$html.append(title.$html); 84 if (opts.showDescription) { 85 var description = new Element(item, 'card-widget-description', (!linkTitle && linkDescription), 'span', item.Description); 86 cardContent.$html.append(description.$html); 87 } 88 cardContent.$html.append(buttonWrap.$html); 89 90 // determine if the card has an image and how to attach it 91 // TODO: lines 85 - 103 could be simplified 92 if (opts.hasImages && (item.ImageWithPath !== null)) { 93 var image = new Element(item, 'image-container', linkImage, 'div', ''); 94 var imageAlternateText = ""; 95 96 if (item.ImageAlternateText !== null) { 97 imageAlternateText = (item.ImageAlternateText); 98 } 99 100 101 if (opts.imageIsBackground) { 102 var imgPath = item.ImageWithPath; 103 var cleanImgPath = imgPath.replace(/(?=[() ])/g, '\\'); 104 if (opts.lazyLoadImages) { 105 image.$html.addClass('lozad'); 106 image.$html.attr('data-background-image', cleanImgPath); 107 } else { 108 image.$html.attr('style', 'background-image:url(\'' + cleanImgPath + '\');'); 109 } 110 } else { 111 if (opts.lazyLoadImages) { 112 image.$html.append('<img \ 113 class="card-widget-image lozad" \ 114 src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" \ 115 data-src="'+ item.ImageWithPath +'" \ 116 alt="' + imageAlternateText + '" \ 117 >'); 118 } else { 119 image.$html.append('<img class="card-widget-image" src="' + item.ImageWithPath + '" alt="' + imageAlternateText + '">'); 120 } 121 } 122 123 if (opts.textOverImage) { 124 image.$html.append(cardContent.$html); 125 cardItem.$html.append(image.$html); 126 } else { 127 cardItem.$html.append(image.$html); 128 cardItem.$html.append(cardContent.$html); 129 } 130 } else { 131 cardItem.$html.append(cardContent.$html); 132 } 133 134 widget.cards.push(cardItem.$html); 135 // $el.append(cardItem.$html); 136 } 137 }); 138 139 attachCards(); 140 141 // initialize widget 142 // widget.initialize(); 143 } 144 145 146 /** 147 * Returns HTML buttons for the card 148 * @protected 149 */ 150 widget.buildButtons = function(data) { 151 var target = data.URLOpenInANewWindow ? ' target="_blank"' : ''; 152 var buyButton = (opts.buyNowButton.visible && data.PurchaseURL) ? '<a class="buyNowButton" href="' + data.PurchaseURL + '" ' + target + '>' + opts.buyNowButton.text + '</a>' : ''; 153 var moreButton = (opts.moreButton.visible && data.URL) ? '<a class="moreButton" href="' + data.URL + '" ' + target + '>' + opts.moreButton.text + '</a>' : ''; 154 155 return buyButton + moreButton; 156 } 157 158 159 /** 160 * Initialize slidshow if available and call loaded callback 161 * @public 162 */ 163 widget.initialize = function() { 164 if (opts.slideshow) { 165 $el.addClass('owl-carousel'); 166 widget.owl = $el.owlCarousel(opts.slideshowOptions); 167 } 168 opts.cardWidgetLoaded(widget, widget.owl, true); // callback if needed for the constructor 169 $el.removeClass('loading'); 170 // lazyLoadStuff(); 171 var observer = lozad('.lozad', { 172 rootMargin: '200px 0px', // syntax similar to that of CSS Margin 173 threshold: 0.1 // ratio of element convergence 174 }); 175 observer.observe(); 176 } 177 178 /** 179 * Attaches cards to the DOM 180 * @protected 181 */ 182 function attachCards() { 183 184 if (opts.slideshow && opts.itemsPerPanel > 1) { 185 var panels = []; 186 var content = ''; 187 188 for (var i = 0; i < widget.cards.length; i++) { 189 var endOfArray = i === (widget.cards.length - 1); 190 if ( (i !== 0) && (i % opts.itemsPerPanel === 0)) { 191 panels.push(new Element('', 'carousel-panel', false, 'div', content)); 192 content = widget.cards[i].prop('outerHTML'); 193 if (endOfArray) { 194 panels.push(new Element('', 'carousel-panel', false, 'div', content)); 195 } 196 } else { 197 content += widget.cards[i].prop('outerHTML'); 198 if (endOfArray) { 199 panels.push(new Element('', 'carousel-panel', false, 'div', content)); 200 } 201 } 202 } 203 for (var i = 0; i < panels.length; i++) { 204 $el.append(panels[i].$html); 205 } 206 } else { 207 for (var i = 0; i < widget.cards.length; i++) { 208 $el.append(widget.cards[i]); 209 } 210 } 211 212 widget.initialize(); 213 } 214 215 /** 216 * Converts the image links in widget.items to be SSL call. 217 * @protected 218 */ 219 function convertSources() { 220 for (var i = 0; i < widget.items.length; i++) { 221 if(widget.items[i].ImageWithPath){ 222 widget.items[i].ImageWithPath = widget.items[i].ImageWithPath.replace(/^http:\/\//i, 'https://'); 223 } 224 } 225 } 226 227 /**
228 * html object constructor 229 * @protected 230 */ 231 function Element(item, customClass, link, type, content) { 232 if (link) { 233 this.class = item.URL ? '' : 'void-link'; 234 this.url = item.URL || 'javascript:void(0);'; 235 this.target = item.URLOpenInANewWindow ? ' target="_blank"' : ''; 236 this.$html = $('<a href="' + this.url + '" class="' + customClass + ' ' + this.class + '" ' + this.target + '>' + content + '</a>'); 237 } else { 238 // TODO: This section could be simplified 239 if (type === 'div') { 240 this.$html = $('<div class="' + customClass + '">' + content + '</div>'); 241 } else if (type === 'span') { 242 this.$html = $('<span class="' + customClass + '">' + content + '</span>'); 243 } else { 244 this.$html = ''; 245 console.log("Element constructor recieved Invalid data"); 246 console.log(item, customClass, link, type, content); 247 } 248 } 249 250 } 251 252 253 254 /** 255 * There weren't any images returned from the call 256 * @protected 257 */ 258 widget.noData = function(data) { 259 var id = $el.attr('id'); 260 console.log("Service returned no data for " + id, data); 261 $('body').addClass(id + '-no-data'); 262 opts.cardWidgetLoaded(widget, widget.owl, false); 263 }; 264 265 /** 266 * public API. 267 * @public 268 */ 269 return { 270 data: widget.data, 271 options: opts, 272 owl: function() { 273 return widget.owl; 274 }, 275 reinitialize: function() { 276 widget.initialize(); 277 } 278 }; 279 280 } 281 282 } 283});
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.