'use strict'; var AdvancedSettings = require('./views/advanced_settings'), CreateAccount = require('./views/create_account'), Day = require('./views/day'), EditEvent = require('./views/edit_event'), Marionette = require('marionette-client'), ModifyAccount = require('./views/modify_account'), Month = require('./views/month'), MonthDay = require('./views/month_day'), ReadEvent = require('./views/read_event'), Settings = require('./views/settings'), Week = require('./views/week'); function Calendar(client) { this.client = client.scope({ searchTimeout: 5000 }); this.actions = new Marionette.Actions(this.client); // Initialize our view remotes. this.advancedSettings = new AdvancedSettings(client); this.createAccount = new CreateAccount(client); this.day = new Day(client); this.editEvent = new EditEvent(client); this.modifyAccount = new ModifyAccount(client); this.month = new Month(client); this.monthDay = new MonthDay(client); this.readEvent = new ReadEvent(client); this.settings = new Settings(client); this.week = new Week(client); } module.exports = Calendar; Calendar.ORIGIN = 'app://calendar.gaiamobile.org'; Calendar.prototype = { launch: function() { var client = this.client; client.apps.launch(Calendar.ORIGIN); client.apps.switchToApp(Calendar.ORIGIN); // Wait for the document body to know we're really 'launched'. this.client.helper.waitForElement('body'); }, get addEventButton() { return this.client.findElement('#time-header a[href="/event/add/"]'); }, get headerContent() { return this.client.findElement('#current-month-year'); }, get timeHeader() { return this.client.findElement('#time-header'); }, get themeColor() { return this.client.findElement('meta[name="theme-color"]') .getAttribute('content'); }, openModifyEventView: function() { this.addEventButton.click(); this.editEvent.waitForDisplay(); return this; }, openSettingsView: function() { this._toggleSettingsView(true); return this; }, closeSettingsView: function() { this._toggleSettingsView(false); return this; }, _toggleSettingsView: function(isOpen) { var client = this.client; client.helper .waitForElement(this.timeHeader) .tap(25, 25); // Wait for the animation to be complete before trying to click on // items in the drawer. var drawer = this.client.findElement('#settings .settings-drawer'); this.client.waitFor(function() { return drawer.getAttribute('data-animstate') === 'done'; }); if (!isOpen) { var body = this.client.findElement('body'); // Also wait for the UI to be in a non-settings state after // waiting for the animation to finish and the app UI to go // back to non-settings state. this.client.waitFor(function() { return body.getAttribute('data-path') !== '/settings/'; }); } return this; }, openAdvancedSettingsView: function() { this.openSettingsView(); this.settings.setupAdvancedSettings(); this.advancedSettings.waitForDisplay(); return this; }, closeAdvancedSettingsView: function() { var advancedSettings = this.advancedSettings; advancedSettings.close(); advancedSettings.waitForHide(); }, openDayView: function() { this.client .findElement('#view-selector a[href="/day/"]') .click(); this.day.waitForDisplay(); return this; }, openMonthView: function() { this.client .findElement('#view-selector a[href="/month/"]') .click(); this.month.waitForDisplay(); return this; }, openWeekView: function() { this.client .findElement('#view-selector a[href="/week/"]') .click(); this.week.waitForDisplay(); return this; }, clickToday: function() { this.client .findElement('#view-selector a[href="#today"]') .click(); return this; }, setupAccount: function(options) { this.openAdvancedSettingsView(); this.advancedSettings.createAccount(); this.createAccount.waitForDisplay(); this.createAccount.chooseAccountType(options.accountType); var modifyAccount = this.modifyAccount; modifyAccount.waitForDisplay(); [ 'user', 'password', 'fullUrl' ].forEach(function(key) { if (key in options) { modifyAccount[key] = options[key]; } }); modifyAccount.save(); modifyAccount.waitForHide(); this.closeSettingsView(); return this; }, teardownAccount: function(calendarName, user) { this.openAdvancedSettingsView(); this.advancedSettings.clickAccount(calendarName, user); var modifyAccount = this.modifyAccount; modifyAccount.waitForDisplay(); modifyAccount.delete(); modifyAccount.waitForHide(); this.closeAdvancedSettingsView(); this.closeSettingsView(); return this; }, sync: function() { this.openSettingsView(); this.settings.sync(); this.closeSettingsView(); return this; }, /** * Create an event. * * Options: * (String) calendar - calendar name [defaults to "Offline calendar"]. * (String) title - event title. * (String) location - event location. * (Date) startDate - event start date. * (Date) endDate - event end date. * (Number) startHour - shortcut for creating an event that starts today. * (Number) duration - length of event in hours. * (Boolean) allDay - whether this is an all day event. * (Array) reminders - array of strings like '5 minutes before'. */ createEvent: function(opts) { var startDate; if (opts.startDate) { startDate = opts.startDate; } else { startDate = new Date(); // startHour can be zero! if (opts.startHour != null) { startDate.setHours(opts.startHour, 0, 0, 0); } } var endDate; if (opts.endDate) { endDate = opts.endDate; } else { // 1h by default var duration = opts.duration || 1; endDate = new Date(startDate.getTime() + duration * 60 * 60 * 1000); } this.openModifyEventView(); var editEvent = this.editEvent; editEvent.title = opts.title; editEvent.location = opts.location || ''; editEvent.description = opts.description || ''; editEvent.calendar = opts.calendar || 'Offline calendar'; editEvent.startDate = startDate; editEvent.endDate = endDate; if (opts.allDay) { editEvent.allDay = opts.allDay; } else { editEvent.startTime = startDate; editEvent.endTime = endDate; } // no reminders by default to avoid triggering notifications by mistake. // see: https://bugzil.la/1012507 editEvent.reminders = opts.reminders == null ? [] : opts.reminders; editEvent.save(); editEvent.waitForHide(); return this; }, /** * Tests if content is bigger than container. If something is wrong it * throws errors. */ checkOverflow: function(element, msg) { msg = msg ? msg + ': ' : ''; var wid = element.scriptWith(function(el) { return { content: el.scrollWidth, container: el.clientWidth }; }); if (!wid.content) { throw new Error(msg + 'invalid content width'); } if (!wid.container) { throw new Error(msg + 'invalid container width'); } // we use a buffer of 1px to account for potential rounding issues // see: Bug 959901 if (Math.abs(wid.content - wid.container) > 1) { msg += 'content (' + wid.content + 'px) is wider than container (' + wid.container + 'px)'; throw new Error(msg); } return this; }, formatDate: function(date) { var month = date.getMonth() + 1, day = date.getDate(), year = date.getFullYear(); if (month.toString().length === 1) { month = '0' + month; } if (day.toString().length === 1) { day = '0' + day; } return [month, day, year].join('/'); }, swipeLeft: function() { return this._swipe({ direction: 'left' }); }, swipeRight: function() { return this._swipe({ direction: 'right' }); }, /** * Options: * (String) direction is one of 'left', 'right'. */ _swipe: function(options) { var bodySize = this.client.executeScript(function() { return { height: document.body.clientHeight, width: document.body.clientWidth }; }); // (x1, y1) is swipe start. // (x2, y2) is swipe end. var x1, x2, y1, y2; y1 = y2 = bodySize.height * 0.5; if (options.direction === 'left') { x1 = bodySize.width * 0.8; x2 = 0; } else if (options.direction === 'right') { x1 = bodySize.width * 0.2; x2 = bodySize.width; } else { throw new Error('swipe needs a direction'); } var body = this.client.findElement('body'); this.actions .flick(body, x1, y1, x2, y2) .perform(); return this; }, switch12HourTimeFormat: function() { this._switchTimeFormat(true); }, switch24HourTimeFormat: function() { this._switchTimeFormat(false); }, _switchTimeFormat: function(is12Hour) { var client = this.client; // Switch to System frame to get the permission // of writing settings values. client.switchToFrame(); client.settings.set('locale.hour12', is12Hour); client.apps.switchToApp(Calendar.ORIGIN); } };