Carousel.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. define("dojox/mobile/Carousel", [
  2. "dojo/_base/kernel",
  3. "dojo/_base/array",
  4. "dojo/_base/connect",
  5. "dojo/_base/declare",
  6. "dojo/_base/event",
  7. "dojo/_base/lang",
  8. "dojo/_base/sniff",
  9. "dojo/dom-class",
  10. "dojo/dom-construct",
  11. "dojo/dom-style",
  12. "dijit/_Contained",
  13. "dijit/_Container",
  14. "dijit/_WidgetBase",
  15. "./PageIndicator",
  16. "./SwapView",
  17. "require"
  18. ], function(kernel, array, connect, declare, event, lang, has, domClass, domConstruct, domStyle, Contained, Container, WidgetBase, PageIndicator, SwapView, require){
  19. /*=====
  20. var Contained = dijit._Contained;
  21. var Container = dijit._Container;
  22. var WidgetBase = dijit._WidgetBase;
  23. var PageIndicator = dojox.mobile.PageIndicator;
  24. var SwapView = dojox.mobile.SwapView;
  25. =====*/
  26. // module:
  27. // dojox/mobile/Carousel
  28. // summary:
  29. // A carousel widget that manages a list of images
  30. kernel.experimental("dojox.mobile.Carousel");
  31. return declare("dojox.mobile.Carousel", [WidgetBase, Container, Contained], {
  32. // summary:
  33. // A carousel widget that manages a list of images
  34. // description:
  35. // The carousel widget manages a list of images that can be
  36. // displayed horizontally, and allows the user to scroll through
  37. // the list and select a single item.
  38. // numVisible: Number
  39. // The number of visible items.
  40. numVisible: 3,
  41. // title: String
  42. // A title of the carousel to be displayed on the title bar.
  43. title: "",
  44. // pageIndicator: Boolean
  45. // If true, a page indicator, a series of small dots that indicate
  46. // the current page, is displayed on the title bar.
  47. pageIndicator: true,
  48. // navButton: Boolean
  49. // If true, navigation buttons are displyaed on the title bar.
  50. navButton: false,
  51. // height: String
  52. // Explicitly specified height of the widget (ex. "300px"). If
  53. // "inherit" is specified, the height is inherited from its offset
  54. // parent.
  55. height: "300px",
  56. // store: Object
  57. // Reference to data provider object used by this widget.
  58. store: null,
  59. // query: Object
  60. // A query that can be passed to 'store' to initially filter the
  61. // items.
  62. query: null,
  63. // queryOptions: Object
  64. // An optional parameter for the query.
  65. queryOptions: null,
  66. buildRendering: function(){
  67. this.inherited(arguments);
  68. this.domNode.className = "mblCarousel";
  69. var h;
  70. if(this.height === "inherit"){
  71. if(this.domNode.offsetParent){
  72. h = this.domNode.offsetParent.offsetHeight + "px";
  73. }
  74. }else if(this.height){
  75. h = this.height;
  76. }
  77. this.domNode.style.height = h;
  78. this.headerNode = domConstruct.create("DIV", {className:"mblCarouselHeaderBar"}, this.domNode);
  79. if(this.navButton){
  80. this.btnContainerNode = domConstruct.create("DIV", {
  81. className: "mblCarouselBtnContainer"
  82. }, this.headerNode);
  83. domStyle.set(this.btnContainerNode, "float", "right"); // workaround for webkit rendering problem
  84. this.prevBtnNode = domConstruct.create("BUTTON", {
  85. className: "mblCarouselBtn",
  86. title: "Previous",
  87. innerHTML: "<"
  88. }, this.btnContainerNode);
  89. this.nextBtnNode = domConstruct.create("BUTTON", {
  90. className: "mblCarouselBtn",
  91. title: "Next",
  92. innerHTML: ">"
  93. }, this.btnContainerNode);
  94. this.connect(this.prevBtnNode, "onclick", "onPrevBtnClick");
  95. this.connect(this.nextBtnNode, "onclick", "onNextBtnClick");
  96. }
  97. if(this.pageIndicator){
  98. if(!this.title){
  99. this.title = " ";
  100. }
  101. this.piw = new PageIndicator();
  102. domStyle.set(this.piw, "float", "right"); // workaround for webkit rendering problem
  103. this.headerNode.appendChild(this.piw.domNode);
  104. }
  105. this.titleNode = domConstruct.create("DIV", {
  106. className: "mblCarouselTitle"
  107. }, this.headerNode);
  108. this.containerNode = domConstruct.create("DIV", {className:"mblCarouselPages"}, this.domNode);
  109. connect.subscribe("/dojox/mobile/viewChanged", this, "handleViewChanged");
  110. },
  111. startup: function(){
  112. if(this._started){ return; }
  113. if(this.store){
  114. var store = this.store;
  115. this.store = null;
  116. this.setStore(store, this.query, this.queryOptions);
  117. }
  118. this.inherited(arguments);
  119. },
  120. setStore: function(store, query, queryOptions){
  121. // summary:
  122. // Sets the store to use with this widget.
  123. if(store === this.store){ return; }
  124. this.store = store;
  125. this.query = query;
  126. this.queryOptions = queryOptions;
  127. this.refresh();
  128. },
  129. refresh: function(){
  130. if(!this.store){ return; }
  131. this.store.fetch({
  132. query: this.query,
  133. queryOptions: this.queryOptions,
  134. onComplete: lang.hitch(this, "generate"),
  135. onError: lang.hitch(this, "onError")
  136. });
  137. },
  138. generate: function(/*Array*/items, /*Object*/ dataObject){
  139. array.forEach(this.getChildren(), function(child){
  140. if(child instanceof SwapView){
  141. child.destroyRecursive();
  142. }
  143. });
  144. this.items = items;
  145. this.swapViews = [];
  146. this.images = [];
  147. var nPages = Math.ceil(items.length / this.numVisible);
  148. var h = this.domNode.offsetHeight - this.headerNode.offsetHeight;
  149. for(var i = 0; i < nPages; i++){
  150. var w = new SwapView({height:h+"px"});
  151. this.addChild(w);
  152. this.swapViews.push(w);
  153. w._carouselImages = [];
  154. if(i === 0 && this.piw){
  155. this.piw.refId = w.id;
  156. }
  157. for(var j = 0; j < this.numVisible; j++){
  158. var idx = i * this.numVisible + j;
  159. var item = idx < items.length ? items[idx] :
  160. {src:require.toUrl("dojo/resources/blank.gif"), height:"1px"};
  161. var disp = w.domNode.style.display;
  162. w.domNode.style.display = ""; // need to be visible during the size calculation
  163. var box = this.createBox(item, h);
  164. w.containerNode.appendChild(box);
  165. box.appendChild(this.createHeaderText(item));
  166. var img = this.createContent(item, idx);
  167. box.appendChild(img);
  168. box.appendChild(this.createFooterText(item));
  169. this.resizeContent(item, box, img);
  170. w.domNode.style.display = disp;
  171. if(item.height !== "1px"){
  172. this.images.push(img);
  173. w._carouselImages.push(img);
  174. }
  175. }
  176. }
  177. if(this.swapViews[0]){
  178. this.loadImages(this.swapViews[0]);
  179. }
  180. if(this.swapViews[1]){
  181. this.loadImages(this.swapViews[1]); // pre-fetch the next view images
  182. }
  183. this.currentView = this.swapViews[0];
  184. if(this.piw){
  185. this.piw.reset();
  186. }
  187. },
  188. createBox: function(item, h){
  189. var width = item.width || (90/this.numVisible + "%");
  190. var height = item.height || h + "px";
  191. var m = has("ie") ? 5/this.numVisible-1 : 5/this.numVisible;
  192. var margin = item.margin || (m + "%");
  193. var box = domConstruct.create("DIV", {
  194. className: "mblCarouselBox"
  195. });
  196. domStyle.set(box, {
  197. margin: "0px " + margin,
  198. width: width,
  199. height: height
  200. });
  201. return box;
  202. },
  203. createHeaderText: function(item){
  204. this.headerTextNode = domConstruct.create("DIV", {
  205. className: "mblCarouselImgHeaderText",
  206. innerHTML: item.headerText ? item.headerText : "&nbsp;"
  207. });
  208. return this.headerTextNode;
  209. },
  210. createContent: function(item, idx){
  211. var props = {
  212. alt: item.alt || "",
  213. tabIndex: "0", // for keyboard navigation on a desktop browser
  214. className: "mblCarouselImg"
  215. };
  216. var img = domConstruct.create("IMG", props);
  217. img._idx = idx;
  218. if(item.height !== "1px"){
  219. this.connect(img, "onclick", "onClick");
  220. this.connect(img, "onkeydown", "onClick");
  221. connect.connect(img, "ondragstart", event.stop);
  222. }else{
  223. img.style.visibility = "hidden";
  224. }
  225. return img;
  226. },
  227. createFooterText: function(item){
  228. this.footerTextNode = domConstruct.create("DIV", {
  229. className: "mblCarouselImgFooterText",
  230. innerHTML: item.footerText ? item.footerText : "&nbsp;"
  231. });
  232. return this.footerTextNode;
  233. },
  234. resizeContent: function(item, box, img){
  235. if(item.height !== "1px"){
  236. img.style.height = (box.offsetHeight - this.headerTextNode.offsetHeight - this.footerTextNode.offsetHeight) + "px";
  237. }
  238. },
  239. onError: function(errText){
  240. },
  241. onPrevBtnClick: function(e){
  242. if(this.currentView){
  243. this.currentView.goTo(-1);
  244. }
  245. },
  246. onNextBtnClick: function(e){
  247. if(this.currentView){
  248. this.currentView.goTo(1);
  249. }
  250. },
  251. onClick: function(e){
  252. if(e && e.type === "keydown" && e.keyCode !== 13){ return; }
  253. var img = e.currentTarget;
  254. for(var i = 0; i < this.images.length; i++){
  255. if(this.images[i] === img){
  256. domClass.add(img, "mblCarouselImgSelected");
  257. }else{
  258. domClass.remove(this.images[i], "mblCarouselImgSelected");
  259. }
  260. }
  261. domStyle.set(img, "opacity", 0.4);
  262. setTimeout(function(){
  263. domStyle.set(img, "opacity", 1);
  264. }, 1000);
  265. connect.publish("/dojox/mobile/carouselSelect", [this, img, this.items[img._idx], img._idx]);
  266. },
  267. loadImages: function(view){
  268. if(!view){ return; }
  269. var imgs = view._carouselImages;
  270. array.forEach(imgs, function(img){
  271. if(!img.src){
  272. var item = this.items[img._idx];
  273. img.src = item.src;
  274. }
  275. }, this);
  276. },
  277. handleViewChanged: function(view){
  278. if(view.getParent() !== this){ return; }
  279. this.currentView = view;
  280. // lazy-load images in the next view
  281. this.loadImages(view.nextView(view.domNode));
  282. },
  283. _setTitleAttr: function(/*String*/title){
  284. this.title = title;
  285. this.titleNode.innerHTML = this._cv ? this._cv(title) : title;
  286. }
  287. });
  288. });