schedule.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. var AIRTIME = (function(AIRTIME){
  2. var mod;
  3. if (AIRTIME.schedule === undefined) {
  4. AIRTIME.schedule = {};
  5. }
  6. mod = AIRTIME.schedule;
  7. return AIRTIME;
  8. }(AIRTIME || {}));
  9. var serverTimezoneOffset = 0;
  10. function closeDialogCalendar(event, ui) {
  11. $el = $(this);
  12. $el.dialog('destroy');
  13. $el.remove();
  14. //need to refetch the events to update scheduled status.
  15. $("#schedule_calendar").fullCalendar( 'refetchEvents' );
  16. }
  17. function checkShowLength(json) {
  18. var percent = json.percentFilled;
  19. if (percent > 100){
  20. $("#show_time_warning")
  21. .text($.i18n._("Shows longer than their scheduled time will be cut off by a following show."))
  22. .show();
  23. }
  24. else {
  25. $("#show_time_warning")
  26. .empty()
  27. .hide();
  28. }
  29. }
  30. function confirmCancelShow(show_instance_id){
  31. if (confirm($.i18n._('Cancel Current Show?'))) {
  32. var url = baseUrl+"Schedule/cancel-current-show";
  33. $.ajax({
  34. url: url,
  35. data: {format: "json", id: show_instance_id},
  36. success: function(data){
  37. scheduleRefetchEvents(data);
  38. }
  39. });
  40. }
  41. }
  42. function confirmCancelRecordedShow(show_instance_id){
  43. if (confirm($.i18n._('Stop recording current show?'))) {
  44. var url = baseUrl+"Schedule/cancel-current-show";
  45. $.ajax({
  46. url: url,
  47. data: {format: "json", id: show_instance_id},
  48. success: function(data){
  49. scheduleRefetchEvents(data);
  50. }
  51. });
  52. }
  53. }
  54. function uploadToSoundCloud(show_instance_id, el){
  55. var url = baseUrl+"Schedule/upload-to-sound-cloud",
  56. $el = $(el),
  57. $span = $el.find(".soundcloud");
  58. $.post(url, {id: show_instance_id, format: "json"});
  59. //first upload to soundcloud.
  60. if ($span.length === 0){
  61. $span = $("<span/>", {"class": "progress"});
  62. $el.find(".fc-event-title").after($span);
  63. }
  64. else {
  65. $span.removeClass("soundcloud").addClass("progress");
  66. }
  67. }
  68. function checkCalendarSCUploadStatus(){
  69. var url = baseUrl+'Library/get-upload-to-soundcloud-status',
  70. span,
  71. id;
  72. function checkSCUploadStatusCallback(json) {
  73. if (json.sc_id > 0) {
  74. span.removeClass("progress").addClass("soundcloud");
  75. }
  76. else if (json.sc_id == "-3") {
  77. span.removeClass("progress").addClass("sc-error");
  78. }
  79. }
  80. function checkSCUploadStatusRequest() {
  81. span = $(this);
  82. id = span.parents("div.fc-event").data("event").id;
  83. $.post(url, {format: "json", id: id, type:"show"}, checkSCUploadStatusCallback);
  84. }
  85. $("#schedule_calendar span.progress").each(checkSCUploadStatusRequest);
  86. setTimeout(checkCalendarSCUploadStatus, 5000);
  87. }
  88. function findViewportDimensions() {
  89. var viewportwidth,
  90. viewportheight;
  91. // the more standards compliant browsers (mozilla/netscape/opera/IE7) use
  92. // window.innerWidth and window.innerHeight
  93. if (typeof window.innerWidth != 'undefined') {
  94. viewportwidth = window.innerWidth, viewportheight = window.innerHeight;
  95. }
  96. // IE6 in standards compliant mode (i.e. with a valid doctype as the first
  97. // line in the document)
  98. else if (typeof document.documentElement != 'undefined'
  99. && typeof document.documentElement.clientWidth != 'undefined'
  100. && document.documentElement.clientWidth != 0) {
  101. viewportwidth = document.documentElement.clientWidth;
  102. viewportheight = document.documentElement.clientHeight;
  103. }
  104. // older versions of IE
  105. else {
  106. viewportwidth = document.getElementsByTagName('body')[0].clientWidth;
  107. viewportheight = document.getElementsByTagName('body')[0].clientHeight;
  108. }
  109. return {
  110. width: viewportwidth,
  111. height: viewportheight-45
  112. };
  113. }
  114. function buildScheduleDialog (json, instance_id) {
  115. var dialog = $(json.dialog),
  116. viewport = findViewportDimensions(),
  117. height = Math.floor(viewport.height * 0.96),
  118. width = Math.floor(viewport.width * 0.96),
  119. fnServer = AIRTIME.showbuilder.fnServerData,
  120. //subtract padding in pixels
  121. widgetWidth = width - 60,
  122. libWidth = Math.floor(widgetWidth * 0.5),
  123. builderWidth = Math.floor(widgetWidth * 0.5);
  124. dialog.find("#library_content")
  125. .height(height - 115)
  126. .width(libWidth);
  127. dialog.find("#show_builder")
  128. .height(height - 115)
  129. .width(builderWidth);
  130. dialog.dialog({
  131. autoOpen: false,
  132. title: json.title,
  133. width: width,
  134. height: height,
  135. resizable: false,
  136. draggable: true,
  137. modal: true,
  138. close: closeDialogCalendar,
  139. buttons: [
  140. {
  141. text: $.i18n._("Ok"),
  142. "class": "btn",
  143. click: function() {
  144. $(this).dialog("close");
  145. }
  146. }
  147. ]
  148. });
  149. //set the start end times so the builder datatables knows its time range.
  150. fnServer.start = json.start;
  151. fnServer.end = json.end;
  152. fnServer.ops = {};
  153. fnServer.ops.showFilter = 0;
  154. fnServer.ops.showInstanceFilter = instance_id;
  155. fnServer.ops.myShows = 0;
  156. AIRTIME.library.libraryInit();
  157. AIRTIME.showbuilder.builderDataTable();
  158. //set max heights of datatables.
  159. dialog.find(".lib-content .dataTables_scrolling")
  160. .css("max-height", height - 90 - 200);
  161. dialog.find(".sb-content .dataTables_scrolling")
  162. .css("max-height", height - 90 - 65);
  163. dialog.dialog('open');
  164. }
  165. function buildContentDialog (json){
  166. var dialog = $(json.dialog),
  167. viewport = findViewportDimensions(),
  168. height = viewport.height * 2/3,
  169. width = viewport.width * 4/5;
  170. if (json.show_error == true){
  171. alertShowErrorAndReload();
  172. }
  173. dialog.find("#show_progressbar").progressbar({
  174. value: json.percentFilled
  175. });
  176. dialog.dialog({
  177. autoOpen: false,
  178. title: $.i18n._("Contents of Show") +" '" + json.showTitle + "'",
  179. width: width,
  180. height: height,
  181. modal: true,
  182. close: closeDialogCalendar,
  183. buttons: [
  184. {
  185. text: $.i18n._("Ok"),
  186. "class": "btn",
  187. click: function() {
  188. dialog.remove();
  189. }
  190. }
  191. ]
  192. });
  193. dialog.dialog('open');
  194. }
  195. /**
  196. * Use user preference for time scale; defaults to month if preference was never set
  197. */
  198. function getTimeScalePreference(data) {
  199. return data.calendarInit.timeScale;
  200. }
  201. /**
  202. * Use user preference for time interval; defaults to 30m if preference was never set
  203. */
  204. function getTimeIntervalPreference(data) {
  205. return parseInt(data.calendarInit.timeInterval);
  206. }
  207. function createFullCalendar(data){
  208. serverTimezoneOffset = data.calendarInit.timezoneOffset;
  209. var mainHeight = $(window).height() - 200 - 35;
  210. $('#schedule_calendar').fullCalendar({
  211. header: {
  212. left: 'prev, next, today',
  213. center: 'title',
  214. right: 'agendaDay, agendaWeek, month'
  215. },
  216. defaultView: getTimeScalePreference(data),
  217. slotMinutes: getTimeIntervalPreference(data),
  218. firstDay: data.calendarInit.weekStartDay,
  219. editable: false,
  220. allDaySlot: false,
  221. axisFormat: 'H:mm',
  222. timeFormat: {
  223. agenda: 'H:mm{ - H:mm}',
  224. month: 'H:mm{ - H:mm}'
  225. },
  226. //i18n_months is in common.js
  227. monthNames: i18n_months,
  228. monthNamesShort: [
  229. $.i18n._('Jan'),
  230. $.i18n._('Feb'),
  231. $.i18n._('Mar'),
  232. $.i18n._('Apr'),
  233. $.i18n._('May'),
  234. $.i18n._('Jun'),
  235. $.i18n._('Jul'),
  236. $.i18n._('Aug'),
  237. $.i18n._('Sep'),
  238. $.i18n._('Oct'),
  239. $.i18n._('Nov'),
  240. $.i18n._('Dec')
  241. ],
  242. buttonText: {
  243. today: $.i18n._('today'),
  244. month: $.i18n._('month'),
  245. week: $.i18n._('week'),
  246. day: $.i18n._('day')
  247. },
  248. dayNames: [
  249. $.i18n._('Sunday'),
  250. $.i18n._('Monday'),
  251. $.i18n._('Tuesday'),
  252. $.i18n._('Wednesday'),
  253. $.i18n._('Thursday'),
  254. $.i18n._('Friday'),
  255. $.i18n._('Saturday')
  256. ],
  257. dayNamesShort: [
  258. $.i18n._('Sun'),
  259. $.i18n._('Mon'),
  260. $.i18n._('Tue'),
  261. $.i18n._('Wed'),
  262. $.i18n._('Thu'),
  263. $.i18n._('Fri'),
  264. $.i18n._('Sat')
  265. ],
  266. contentHeight: mainHeight,
  267. theme: true,
  268. lazyFetching: false,
  269. serverTimestamp: parseInt(data.calendarInit.timestamp, 10),
  270. serverTimezoneOffset: parseInt(data.calendarInit.timezoneOffset, 10),
  271. events: getFullCalendarEvents,
  272. //callbacks (in full-calendar-functions.js)
  273. viewDisplay: viewDisplay,
  274. dayClick: dayClick,
  275. eventRender: eventRender,
  276. eventAfterRender: eventAfterRender,
  277. eventDrop: eventDrop,
  278. eventResize: eventResize,
  279. windowResize: windowResize
  280. });
  281. }
  282. //Alert the error and reload the page
  283. //this function is used to resolve concurrency issue
  284. function alertShowErrorAndReload(){
  285. alert($.i18n._("The show instance doesn't exist anymore!"));
  286. window.location.reload();
  287. }
  288. $(document).ready(function() {
  289. checkCalendarSCUploadStatus();
  290. $.contextMenu({
  291. selector: 'div.fc-event',
  292. trigger: "left",
  293. ignoreRightClick: true,
  294. build: function($el, e) {
  295. var data,
  296. items,
  297. callback;
  298. data = $el.data("event");
  299. function processMenuItems(oItems) {
  300. //define a schedule callback.
  301. if (oItems.schedule !== undefined) {
  302. callback = function() {
  303. $.post(oItems.schedule.url, {format: "json", id: data.id}, function(json){
  304. buildScheduleDialog(json, data.id);
  305. });
  306. };
  307. oItems.schedule.callback = callback;
  308. }
  309. //define a clear callback.
  310. if (oItems.clear !== undefined) {
  311. callback = function() {
  312. if (confirm($.i18n._("Remove all content?"))) {
  313. $.post(oItems.clear.url, {format: "json", id: data.id}, function(json){
  314. scheduleRefetchEvents(json);
  315. });
  316. }
  317. };
  318. oItems.clear.callback = callback;
  319. }
  320. //define an edit callback.
  321. if (oItems.edit !== undefined) {
  322. if(oItems.edit.items !== undefined){
  323. var edit = oItems.edit.items;
  324. //edit a single instance
  325. callback = function() {
  326. $.get(edit.instance.url, {format: "json", showId: data.showId, instanceId: data.id, type: "instance"}, function(json){
  327. beginEditShow(json);
  328. });
  329. };
  330. edit.instance.callback = callback;
  331. //edit this instance and all
  332. callback = function() {
  333. $.get(edit.all.url, {format: "json", showId: data.showId, instanceId: data.id, type: "all"}, function(json){
  334. beginEditShow(json);
  335. });
  336. };
  337. edit.all.callback = callback;
  338. }else{
  339. callback = function() {
  340. $.get(oItems.edit.url, {format: "json", showId: data.showId, instanceId: data.id, type: oItems.edit._type}, function(json){
  341. beginEditShow(json);
  342. });
  343. };
  344. oItems.edit.callback = callback;
  345. }
  346. }
  347. //define a content callback.
  348. if (oItems.content !== undefined) {
  349. callback = function() {
  350. $.get(oItems.content.url, {format: "json", id: data.id}, function(json){
  351. buildContentDialog(json);
  352. });
  353. };
  354. oItems.content.callback = callback;
  355. }
  356. //define a soundcloud upload callback.
  357. if (oItems.soundcloud_upload !== undefined) {
  358. callback = function() {
  359. uploadToSoundCloud(data.id, this.context);
  360. };
  361. oItems.soundcloud_upload.callback = callback;
  362. }
  363. //define a view on soundcloud callback.
  364. if (oItems.soundcloud_view !== undefined) {
  365. callback = function() {
  366. window.open(oItems.soundcloud_view.url);
  367. };
  368. oItems.soundcloud_view.callback = callback;
  369. }
  370. //define a cancel recorded show callback.
  371. if (oItems.cancel_recorded !== undefined) {
  372. callback = function() {
  373. confirmCancelRecordedShow(data.id);
  374. };
  375. oItems.cancel_recorded.callback = callback;
  376. }
  377. //define a view recorded callback.
  378. if (oItems.view_recorded !== undefined) {
  379. callback = function() {
  380. $.get(oItems.view_recorded.url, {format: "json"}, function(json){
  381. //in library.js
  382. buildEditMetadataDialog(json);
  383. });
  384. };
  385. oItems.view_recorded.callback = callback;
  386. }
  387. //define a cancel callback.
  388. if (oItems.cancel !== undefined) {
  389. callback = function() {
  390. confirmCancelShow(data.id);
  391. };
  392. oItems.cancel.callback = callback;
  393. }
  394. //define a delete callback.
  395. if (oItems.del !== undefined) {
  396. //repeating show multiple delete options
  397. if (oItems.del.items !== undefined) {
  398. var del = oItems.del.items;
  399. //delete a single instance
  400. callback = function() {
  401. $.post(del.single.url, {format: "json", id: data.id}, function(json){
  402. scheduleRefetchEvents(json);
  403. });
  404. };
  405. del.single.callback = callback;
  406. //delete this instance and all following instances.
  407. callback = function() {
  408. $.post(del.following.url, {format: "json", id: data.id}, function(json){
  409. scheduleRefetchEvents(json);
  410. });
  411. };
  412. del.following.callback = callback;
  413. }
  414. //single show
  415. else {
  416. callback = function() {
  417. $.post(oItems.del.url, {format: "json", id: data.id}, function(json){
  418. scheduleRefetchEvents(json);
  419. });
  420. };
  421. oItems.del.callback = callback;
  422. }
  423. }
  424. items = oItems;
  425. }
  426. $.ajax({
  427. url: baseUrl+"schedule/make-context-menu",
  428. type: "GET",
  429. data: {instanceId : data.id, showId: data.showId, format: "json"},
  430. dataType: "json",
  431. async: false,
  432. success: function(json){
  433. processMenuItems(json.items);
  434. }
  435. });
  436. return {
  437. items: items,
  438. determinePosition : function($menu, x, y) {
  439. $menu.css('display', 'block')
  440. .position({ my: "left top", at: "right top", of: this, offset: "-20 10", collision: "fit"})
  441. .css('display', 'none');
  442. }
  443. };
  444. }
  445. });
  446. });