Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/apps/system/js/cards_view.js
diff options
context:
space:
mode:
Diffstat (limited to 'apps/system/js/cards_view.js')
-rw-r--r--apps/system/js/cards_view.js676
1 files changed, 0 insertions, 676 deletions
diff --git a/apps/system/js/cards_view.js b/apps/system/js/cards_view.js
deleted file mode 100644
index 8bce02b..0000000
--- a/apps/system/js/cards_view.js
+++ /dev/null
@@ -1,676 +0,0 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-//
-// CardsView is responsible for managing opened apps
-//
-
-'use strict';
-
-var CardsView = (function() {
-
- //display icon of an app on top of app's card
- var DISPLAY_APP_ICON = false;
- var USER_DEFINED_ORDERING = false;
- // If 'true', scrolling moves the list one card
- // at time, and snaps the list so the current card
- // is centered in the view
- // If 'false', use free, physics-based scrolling
- // (Gaia default)
- var SNAPPING_SCROLLING = true;
- // if 'true' user can close the app
- // by dragging it upwards
- var MANUAL_CLOSING = true;
-
- var cardsView = document.getElementById('cards-view');
- var screenElement = document.getElementById('screen');
- var cardsList = cardsView.firstElementChild;
- var displayedApp;
- var runningApps;
- // Unkillable apps which have attention screen now
- var attentionScreenApps = [];
- // Card which we are re-ordering now
- var reorderedCard = null;
- var currentDisplayed = 0;
- // Timer between scrolling CardList further,
- // when reordering Cards
- var scrollWhileSortingTimer;
- // We don't allow user to scroll CardList
- // before the timer ticks while in reordering
- // mode
- var allowScrollingWhileSorting = false;
- // Initial margin of the reordered card
- var dragMargin = 0;
- // Are we reordering or removing the card now?
- var draggingCardUp = false;
- // Are we moving card left or right?
- var sortingDirection;
- // List of sorted apps
- var userSortedApps = [];
- var HVGA = document.documentElement.clientWidth < 480;
- var cardsViewShown = false;
-
- // init events
- var gd = new GestureDetector(cardsView);
- gd.startDetecting();
-
- // A list of all the URLs we've created via URL.createObjectURL which we
- // haven't yet revoked.
- var screenshotObjectURLs = [];
-
- /*
- * Returns an icon URI
- *
- * @param{String} the app's origin
- */
- function getIconURI(origin) {
- var icons = runningApps[origin].manifest.icons;
- if (!icons) {
- return null;
- }
-
- var sizes = Object.keys(icons).map(function parse(str) {
- return parseInt(str, 10);
- });
-
- sizes.sort(function(x, y) { return y - x; });
-
- var index = sizes[(HVGA) ? sizes.length - 1 : 0];
- var iconPath = icons[index];
-
- if (iconPath.indexOf('data:') !== 0) {
- iconPath = origin + iconPath;
- }
-
- return iconPath;
- }
-
- // Build and display the card switcher overlay
- // Note that we rebuild the switcher each time we need it rather
- // than trying to keep it in sync with app launches. Performance is
- // not an issue here given that the user has to hold the HOME button down
- // for one second before the switcher will appear.
- function showCardSwitcher() {
- if (cardSwitcherIsShown())
- return;
-
- // events to handle
- window.addEventListener('lock', CardsView);
-
- // Close utility tray if it is opened.
- UtilityTray.hide(true);
-
- // Apps info from WindowManager
- displayedApp = WindowManager.getDisplayedApp();
- currentDisplayed = 0;
- runningApps = WindowManager.getRunningApps();
-
- // Switch to homescreen
- WindowManager.launch(null);
- cardsViewShown = true;
-
- // If user is not able to sort apps manualy,
- // display most recetly active apps on the far left
- if (!USER_DEFINED_ORDERING) {
- var sortable = [];
- for (var origin in runningApps)
- sortable.push({origin: origin, app: runningApps[origin]});
-
- sortable.sort(function(a, b) {
- return b.app.launchTime - a.app.launchTime;
- });
- runningApps = {};
-
- // I assume that object properties are enumerated in
- // the same order they were defined.
- // There is nothing about that in spec, but I've never
- // seen any unexpected behavior.
- sortable.forEach(function(element) {
- runningApps[element.origin] = element.app;
- });
-
- // First add an item to the cardsList for each running app
- for (var origin in runningApps) {
- addCard(origin, runningApps[origin], function showCards() {
- screenElement.classList.add('cards-view');
- cardsView.classList.add('active');
- });
- }
-
- } else { // user ordering
-
- // first run
- if (userSortedApps.length === 0) {
- for (var origin in runningApps) {
- userSortedApps.push(origin);
- }
- } else {
- for (var origin in runningApps) {
- // if we have some new app opened
- if (userSortedApps.indexOf(origin) === -1) {
- userSortedApps.push(origin);
- }
- }
- }
-
- userSortedApps.forEach(function(origin) {
- addCard(origin, runningApps[origin], function showCards() {
- screenElement.classList.add('cards-view');
- cardsView.classList.add('active');
- });
- });
-
- cardsView.addEventListener('contextmenu', CardsView);
-
- }
-
- if (SNAPPING_SCROLLING) {
- cardsView.style.overflow = 'hidden'; //disabling native scrolling
- }
-
- if (SNAPPING_SCROLLING || MANUAL_CLOSING) {
- cardsView.addEventListener('mousedown', CardsView);
- }
-
- // Make sure we're in portrait mode
- screen.mozLockOrientation('portrait-primary');
-
- // If there is a displayed app, take keyboard focus away
- if (displayedApp)
- runningApps[displayedApp].frame.blur();
-
- function addCard(origin, app, displayedAppCallback) {
- // Display card switcher background first to make user focus on the
- // frame closing animation without disturbing by homescreen display.
- if (displayedApp == origin && displayedAppCallback) {
- setTimeout(displayedAppCallback);
- }
- // Not showing homescreen
- if (app.frame.classList.contains('homescreen')) {
- return;
- }
-
- // Build a card representation of each window.
- // And add it to the card switcher
- var card = document.createElement('li');
- card.classList.add('card');
- card.dataset.origin = origin;
-
- //display app icon on the tab
- if (DISPLAY_APP_ICON) {
- var iconURI = getIconURI(origin);
- if (iconURI) {
- var appIcon = document.createElement('img');
- appIcon.classList.add('appIcon');
- appIcon.src = iconURI;
- card.appendChild(appIcon);
- }
- }
-
- var title = document.createElement('h1');
- title.textContent = app.name;
- card.appendChild(title);
-
- var frameForScreenshot = app.iframe;
-
- if (PopupManager.getPopupFromOrigin(origin)) {
- var popupFrame = PopupManager.getPopupFromOrigin(origin);
- frameForScreenshot = popupFrame;
-
- var subtitle = document.createElement('p');
- subtitle.textContent =
- PopupManager.getOpenedOriginFromOpener(origin);
- card.appendChild(subtitle);
- card.classList.add('popup');
- } else if (getOffOrigin(app.frame.dataset.url ?
- app.frame.dataset.url : app.frame.src, origin)) {
- var subtitle = document.createElement('p');
- subtitle.textContent = getOffOrigin(app.frame.dataset.url ?
- app.frame.dataset.url : app.frame.src, origin);
- card.appendChild(subtitle);
- }
-
- if (TrustedUIManager.hasTrustedUI(origin)) {
- var popupFrame = TrustedUIManager.getDialogFromOrigin(origin);
- frameForScreenshot = popupFrame.frame;
- var header = document.createElement('section');
- header.setAttribute('role', 'region');
- header.classList.add('skin-organic');
- header.innerHTML = '<header><button><span class="icon icon-close">';
- header.innerHTML += '</span></button><h1>' + popupFrame.name;
- header.innerHTML += '</h1></header>';
- card.appendChild(header);
- card.classList.add('trustedui');
- } else if (attentionScreenApps.indexOf(origin) == -1) {
- var closeButton = document.createElement('div');
- closeButton.classList.add('close-card');
- card.appendChild(closeButton);
- }
-
- cardsList.appendChild(card);
- // rect is the final size (considering CSS transform) of the card.
- var rect = card.getBoundingClientRect();
-
- // And then switch it with screenshots when one will be ready
- // (instead of -moz-element backgrounds)
- frameForScreenshot.getScreenshot(rect.width, rect.height).onsuccess =
- function gotScreenshot(screenshot) {
- if (screenshot.target.result) {
- var objectURL = URL.createObjectURL(screenshot.target.result);
- screenshotObjectURLs.push(objectURL);
- card.style.backgroundImage = 'url(' + objectURL + ')';
- }
- };
-
- // Set up event handling
- // A click elsewhere in the card switches to that task
- card.addEventListener('tap', runApp);
- }
- }
-
- function runApp(e) {
- // Handle close events
- if (e.target.classList.contains('close-card')) {
- var element = e.target.parentNode;
- cardsList.removeChild(element);
- closeApp(element, true);
- return;
- }
-
- var origin = this.dataset.origin;
- alignCard(currentDisplayed, function cardAligned() {
- WindowManager.launch(origin);
- });
- }
-
- function closeApp(element, removeImmediately) {
- // Stop the app itself
- WindowManager.kill(element.dataset.origin);
-
- // Fix for non selectable cards when we remove the last card
- // Described in https://bugzilla.mozilla.org/show_bug.cgi?id=825293
- if (cardsList.children.length === currentDisplayed) {
- currentDisplayed--;
- }
-
- // If there are no cards left, then dismiss the task switcher.
- if (!cardsList.children.length)
- hideCardSwitcher(removeImmediately);
- }
-
- function getOriginObject(url) {
- var parser = document.createElement('a');
- parser.href = url;
-
- return {
- protocol: parser.protocol,
- hostname: parser.hostname,
- port: parser.port
- };
- }
-
- function getOffOrigin(src, origin) {
- // Use src and origin as cache key
- var cacheKey = JSON.stringify(Array.prototype.slice.call(arguments));
- if (!getOffOrigin.cache[cacheKey]) {
- var native = getOriginObject(origin);
- var current = getOriginObject(src);
- if (current.protocol == 'http:') {
- // Display http:// protocol anyway
- getOffOrigin.cache[cacheKey] = current.protocol + '//' +
- current.hostname;
- } else if (native.protocol == current.protocol &&
- native.hostname == current.hostname &&
- native.port == current.port) {
- // Same origin policy
- getOffOrigin.cache[cacheKey] = '';
- } else if (current.protocol == 'app:') {
- // Avoid displaying app:// protocol
- getOffOrigin.cache[cacheKey] = '';
- } else {
- getOffOrigin.cache[cacheKey] = current.protocol + '//' +
- current.hostname;
- }
- }
-
- return getOffOrigin.cache[cacheKey];
- }
-
- getOffOrigin.cache = {};
-
- function hideCardSwitcher(removeImmediately) {
- if (!cardSwitcherIsShown())
- return;
-
- // events to handle
- window.removeEventListener('lock', CardsView);
-
- // Make the cardsView overlay inactive
- cardsView.classList.remove('active');
- cardsViewShown = false;
-
- // Release our screenshot blobs.
- screenshotObjectURLs.forEach(function(url) {
- URL.revokeObjectURL(url);
- });
- screenshotObjectURLs = [];
-
- // And remove all the cards from the document after the transition
- function removeCards() {
- cardsView.removeEventListener('transitionend', removeCards);
- screenElement.classList.remove('cards-view');
-
- while (cardsList.firstElementChild) {
- cardsList.removeChild(cardsList.firstElementChild);
- }
- }
- if (removeImmediately) {
- removeCards();
- } else {
- cardsView.addEventListener('transitionend', removeCards);
- }
- }
-
- function cardSwitcherIsShown() {
- return cardsViewShown;
- }
-
- //scrolling cards
- var initialCardViewPosition;
- var initialTouchPosition = {};
- var threshold = window.innerWidth / 4;
- // Distance after which dragged card starts moving
- var moveCardThreshold = window.innerHeight / 6;
- var removeCardThreshold = window.innerHeight / 4;
-
- function alignCard(number, callback) {
- if (!cardsList.children[number])
- return;
-
- var scrollLeft = cardsView.scrollLeft;
- var targetScrollLeft = cardsList.children[number].offsetLeft;
-
- if (Math.abs(scrollLeft - targetScrollLeft) < 4) {
- cardsView.scrollLeft = cardsList.children[number].offsetLeft;
- if (callback)
- callback();
- return;
- }
-
- cardsView.scrollLeft = scrollLeft + (targetScrollLeft - scrollLeft) / 2;
-
- window.mozRequestAnimationFrame(function newFrameCallback() {
- alignCard(number, callback);
- });
- }
-
- function onStartEvent(evt) {
- evt.stopPropagation();
- evt.target.setCapture(true);
- cardsView.addEventListener('mousemove', CardsView);
- cardsView.addEventListener('swipe', CardsView);
-
- initialCardViewPosition = cardsView.scrollLeft;
- initialTouchPosition = {
- x: evt.touches ? evt.touches[0].pageX : evt.pageX,
- y: evt.touches ? evt.touches[0].pageY : evt.pageY
- };
- }
-
- function onMoveEvent(evt) {
- evt.stopPropagation();
- var touchPosition = {
- x: evt.touches ? evt.touches[0].pageX : evt.pageX,
- y: evt.touches ? evt.touches[0].pageY : evt.pageY
- };
-
- if (evt.target.classList.contains('card') && MANUAL_CLOSING) {
- var differenceY = initialTouchPosition.y - touchPosition.y;
- if (differenceY > moveCardThreshold) {
- // We don't want user to scroll the CardsView when one of the card is
- // already dragger upwards
- draggingCardUp = true;
- evt.target.style.MozTransform = 'scale(0.6) translate(0, -' +
- differenceY + 'px)';
- }
- }
-
- // If we are not reordering or removing Cards now
- // and Snapping Scrolling is enabled, we want to scroll
- // the CardList
- if (SNAPPING_SCROLLING && reorderedCard === null && !draggingCardUp) {
- var differenceX = initialTouchPosition.x - touchPosition.x;
- cardsView.scrollLeft = initialCardViewPosition + differenceX;
- }
-
- // If re are in reordering mode (there is a DOM element in)
- // reorderedCard variable) we are able to put this element somewere
- // among the others
- if (USER_DEFINED_ORDERING && reorderedCard !== null) {
- var differenceX = touchPosition.x - initialTouchPosition.x;
- // Probably there is more clever solution for calculating
- // position of transformed DOM element, but this was my
- // first thought and it seems to work
- var moveOffset = (cardsList.children[currentDisplayed].offsetLeft / 0.6) +
- differenceX - (dragMargin / 0.6);
-
- reorderedCard.style.MozTransform =
- 'scale(0.6) translate(' + moveOffset + 'px, 0)';
-
- if (Math.abs(differenceX) > threshold) {
- // We don't want to jump to the next page immediately,
- // We are waiting half a second for user to decide if
- // he wants to leave the Card here or scroll further
- if (allowScrollingWhileSorting) {
- allowScrollingWhileSorting = false;
-
- scrollWhileSortingTimer = setTimeout(function() {
- allowScrollingWhileSorting = true;
- }, 500);
-
- if (differenceX > 0 &&
- currentDisplayed <= cardsList.children.length) {
- currentDisplayed++;
- sortingDirection = 'right';
- alignCard(currentDisplayed);
- } else if (differenceX < 0 && currentDisplayed > 0) {
- currentDisplayed--;
- sortingDirection = 'left';
- alignCard(currentDisplayed);
- }
- }
- }
- }
- }
-
- function onEndEvent(evt) {
- evt.stopPropagation();
- var element = evt.target;
- var eventDetail = evt.detail;
- var direction = eventDetail.direction;
-
- document.releaseCapture();
- cardsView.removeEventListener('mousemove', CardsView);
- cardsView.removeEventListener('swipe', CardsView);
-
- var touchPosition = {
- x: eventDetail.end.pageX,
- y: eventDetail.end.pageY
- };
-
- if (SNAPPING_SCROLLING && !draggingCardUp && reorderedCard === null) {
- if (Math.abs(eventDetail.dx) > threshold) {
- if (
- direction === 'left' &&
- currentDisplayed < cardsList.children.length - 1
- ) {
- currentDisplayed++;
- alignCard(currentDisplayed);
- } else if (direction === 'right' && currentDisplayed > 0) {
- currentDisplayed--;
- alignCard(currentDisplayed);
- }
- } else {
- alignCard(currentDisplayed);
- }
- }
-
- // if the element we start dragging on
- // is a card and we are not in reordering mode
- if (
- element.classList.contains('card') &&
- MANUAL_CLOSING &&
- reorderedCard === null
- ) {
-
- draggingCardUp = false;
- // Prevent user from closing the app with a attention screen
- if (-eventDetail.dy > removeCardThreshold &&
- attentionScreenApps.indexOf(element.dataset.origin) == -1
- ) {
-
- // remove the app also from the ordering list
- if (
- userSortedApps.indexOf(element.dataset.origin) !== -1 &&
- USER_DEFINED_ORDERING
- ) {
- userSortedApps.splice(
- userSortedApps.indexOf(element.dataset.origin),
- 1
- );
- }
-
- // Without removing the listener before closing card
- // sometimes the 'click' event fires, even if 'mouseup'
- // uses stopPropagation()
- element.removeEventListener('tap', runApp);
-
- // Remove the icon from the task list
- cardsList.removeChild(element);
-
- closeApp(element);
-
- return;
- } else {
- element.style.MozTransform = '';
- }
- }
-
- if (USER_DEFINED_ORDERING && reorderedCard !== null) {
- // Position of the card depends on direction of scrolling
- if (sortingDirection === 'right') {
- if (currentDisplayed <= cardsList.children.length) {
- cardsList.insertBefore(
- reorderedCard,
- cardsList.children[currentDisplayed + 1]
- );
- } else {
- cardsList.appendChild(reorderedCard);
- }
- } else if (sortingDirection === 'left') {
- cardsList.insertBefore(
- reorderedCard,
- cardsList.children[currentDisplayed]
- );
- }
- reorderedCard.style.MozTransform = '';
- reorderedCard.dataset['edit'] = 'false';
- reorderedCard = null;
-
- alignCard(currentDisplayed);
-
- // remove the app origin from ordering array
- userSortedApps.splice(
- userSortedApps.indexOf(element.dataset.origin),
- 1
- );
- // and put in on the new position
- userSortedApps.splice(currentDisplayed, 0, element.dataset.origin);
- }
- }
-
- function manualOrderStart(evt) {
- evt.preventDefault();
- reorderedCard = evt.target;
- allowScrollingWhileSorting = true;
- if (reorderedCard.classList.contains('card')) {
- dragMargin = reorderedCard.offsetLeft;
- reorderedCard.dataset['edit'] = true;
- sortingDirection = 'left';
- }
- }
-
- window.addEventListener('applicationuninstall',
- function removeUninstaledApp(evt) {
- var origin = evt.detail.application.origin;
- if (userSortedApps.indexOf(origin) !== -1) {
- userSortedApps.splice(userSortedApps.indexOf(origin), 1);
- }
- },
- false);
-
- function cv_handleEvent(evt) {
- switch (evt.type) {
- case 'mousedown':
- onStartEvent(evt);
- break;
-
- case 'mousemove':
- onMoveEvent(evt);
- break;
-
- case 'swipe':
- onEndEvent(evt);
- break;
-
- case 'contextmenu':
- manualOrderStart(evt);
- break;
-
- case 'home':
- if (!cardSwitcherIsShown())
- return;
-
- evt.stopImmediatePropagation();
- hideCardSwitcher();
- break;
-
- case 'lock':
- case 'attentionscreenshow':
- attentionScreenApps = AttentionScreen.getAttentionScreenOrigins();
- hideCardSwitcher();
- break;
-
- case 'attentionscreenhide':
- attentionScreenApps = AttentionScreen.getAttentionScreenOrigins();
- break;
-
- case 'holdhome':
- if (LockScreen.locked)
- return;
-
- SleepMenu.hide();
- showCardSwitcher();
- break;
-
- case 'appwillopen':
- hideCardSwitcher();
- break;
- }
- }
-
- // Public API of CardsView
- return {
- showCardSwitcher: showCardSwitcher,
- hideCardSwitcher: hideCardSwitcher,
- cardSwitcherIsShown: cardSwitcherIsShown,
- handleEvent: cv_handleEvent
- };
-})();
-
-window.addEventListener('attentionscreenshow', CardsView);
-window.addEventListener('attentionscreenhide', CardsView);
-window.addEventListener('holdhome', CardsView);
-window.addEventListener('home', CardsView);
-window.addEventListener('appwillopen', CardsView);
-