Skip to content

Commit

Permalink
Bug 938045 - [Window Management] Implement AppSelection for Copy&Past…
Browse files Browse the repository at this point in the history
…e on Firefox OS
  • Loading branch information
cctuan committed Jun 3, 2014
1 parent 24ad1e2 commit c041556
Show file tree
Hide file tree
Showing 23 changed files with 551 additions and 2 deletions.
6 changes: 6 additions & 0 deletions apps/system/index.html
Expand Up @@ -162,12 +162,15 @@

<!-- Airplane Mode -->
<script defer src="js/airplane_mode.js"></script>
<link rel="stylesheet" type="text/css" href="style/textselection_dialog/textselection_dialog.css">

<!-- Modal Dialog -->
<link rel="stylesheet" type="text/css" href="style/modal_dialog/prompt.css">
<link rel="stylesheet" type="text/css" href="style/modal_dialog/modal_dialog.css">
<script defer src="js/modal_dialog.js"></script>

<!-- TextSelection Dialog -->

<!-- Carrier info notifier, shared by CDMA and Cell Broadcast -->
<script defer src="js/carrier_info_notifier.js"></script>

Expand Down Expand Up @@ -300,6 +303,7 @@
<script defer src="js/app_chrome.js"></script>
<script defer src="js/app_transition_controller.js"></script>
<script defer src="js/app_authentication_dialog.js"></script>
<script defer src="js/text_selection_dialog.js"></script>
<script defer src="js/app_window.js"></script>
<script defer src="js/popup_window.js"></script>
<script defer src="js/shrinking_ui.js"></script>
Expand Down Expand Up @@ -619,6 +623,8 @@

<div id="windows" data-z-index-level="app">
<!-- application windows are added here -->
<div id="TextSelectionDialogRoot">
</div>
</div>

<div id="dialog-overlay" data-z-index-level="dialog-overlay">
Expand Down
3 changes: 2 additions & 1 deletion apps/system/js/app_window.js
Expand Up @@ -630,7 +630,8 @@
'modalDialog': window.AppModalDialog,
'authDialog': window.AppAuthenticationDialog,
'contextmenu': window.BrowserContextMenu,
'childWindowFactory': window.ChildWindowFactory
'childWindowFactory': window.ChildWindowFactory,
'textSelectionDialog': window.TextSelectionDialog
};

/**
Expand Down
5 changes: 4 additions & 1 deletion apps/system/js/bootstrap.js
Expand Up @@ -10,7 +10,7 @@
MediaRecording, AppWindowFactory, SystemDialogManager,
applications, Rocketbar, LayoutManager, PermissionManager,
HomeSearchbar, SoftwareButtonManager, Accessibility,
InternetSharing, TaskManager */
InternetSharing, TaskManager, TextSelectionDialog */

'use strict';

Expand Down Expand Up @@ -57,6 +57,9 @@ window.addEventListener('load', function startup() {

/** @global */
window.lockScreenWindowManager = new window.LockScreenWindowManager();

/** @global */
window.textSelectionDialog = new TextSelectionDialog();
}

function safelyLaunchFTU() {
Expand Down
273 changes: 273 additions & 0 deletions apps/system/js/text_selection_dialog.js
@@ -0,0 +1,273 @@
/* global layoutManager */
(function(window) {
'use strict';

// var _ = navigator.mozL10n.get;
var _id = 0;

/**
* Text Selection Dialog of the AppWindow
*/

var TextSelectionDialog = function (app) {
if (app) {
this.app = app;
this.containerElement = app.element;
} else {
this.containerElement =
document.getElementById('TextSelectionDialogRoot');
}
this.event = null;
// One to one mapping
this.instanceID = _id++;
this._injected = false;
try {
if (app) {
app.element.addEventListener('mozbrowsertextualmenu', this, false);
} else {
window.addEventListener('mozChromeEvent', this);
}
} catch (e) {
if (app) {
app._dump();
}
}
this.render();
return this;
};

TextSelectionDialog.prototype.__proto__ = window.BaseUI.prototype;

TextSelectionDialog.prototype.CLASS_NAME = 'TextSelectionDialog';

TextSelectionDialog.prototype.ELEMENT_PREFIX = 'textselection-dialog-';

TextSelectionDialog.prototype.customID = function tsd_customID() {
if (this.app) {
return '[' + this.app.origin + ']';
} else {
return '';
}
};

TextSelectionDialog.prototype.handleEvent = function tsd_handleEvent(evt) {
if (evt.type === 'mozChromeEvent' && evt.detail.type != 'textualmenu') {
return;
}
// console.log(evt);
// dump("Morris event");
this.event = evt;
evt.preventDefault();
evt.stopPropagation();
if (this.app) {
this.textualmenuDetail = this.event.detail;
} else {
this.textualmenuDetail = this.event.detail.detail;
}
if (!this._injected) {
this.render();
}
this.show();
this._injected = true;
};

TextSelectionDialog.prototype._fetchElements = function tsd__fetchElements() {
this.element = document.getElementById(this.CLASS_NAME + this.instanceID);
this.elements = {};

var toCamelCase = function toCamelCase(str) {
return str.replace(/\-(.)/g, function replacer(str, p1) {
return p1.toUpperCase();
});
};

this.elementClasses = ['copy', 'cut', 'paste', 'selectall'];

// Loop and add element with camel style name to Modal Dialog attribute.
this.elementClasses.forEach(function createElementRef(name) {
this.elements[toCamelCase(name)] =
this.element.querySelector('.' + this.ELEMENT_PREFIX + name);
}, this);
};

TextSelectionDialog.prototype._registerEvents =
function tsd__registerEvents() {
var elements = this.elements;
elements.copy.addEventListener('mousedown', this.copyHandler.bind(this));
elements.cut.addEventListener('mousedown', this.cutHandler.bind(this));
elements.paste.addEventListener('mousedown',
this.pasteHandler.bind(this));
elements.selectall.addEventListener('mousedown',
this.selectallHandler.bind(this));
};

TextSelectionDialog.prototype.copyHandler =
function tsd_copyHandler(evt) {
this.textualmenuDetail.copyToClipboard();
this.hide();
evt.preventDefault();
};

TextSelectionDialog.prototype.cutHandler =
function tsd_cutHandler(evt) {
this.textualmenuDetail.cutToClipboard();
this.hide();
evt.preventDefault();
};

TextSelectionDialog.prototype.pasteHandler =
function tsd_pasteHandler(evt) {
this.textualmenuDetail.pasteFromClipboard();
this.hide();
evt.preventDefault();
};

TextSelectionDialog.prototype.selectallHandler =
function tsd_selectallHandler(evt) {
this.textualmenuDetail.selectall();
this.hide();
evt.preventDefault();
};

TextSelectionDialog.prototype.view = function tsd_view() {
var temp = '<div class="textselection-dialog"' +
' id="' + this.CLASS_NAME + this.instanceID + '">' +
'<div class="textselection-dialog-copy"></div>' +
'<div class="textselection-dialog-cut"></div>' +
'<div class="textselection-dialog-paste"></div>' +
'<div class="textselection-dialog-selectall"></div>' +
'</div>';
return temp;
};

TextSelectionDialog.prototype.kill = function tsd_kill() {
this.containerElement.removeChild(this.element);
};

TextSelectionDialog.prototype.show = function tsd_show() {
if (!this.event) {
return;
}
var evt = this.event;
var detail = this.textualmenuDetail;

// console.log(detail);
if (!detail.show) {
this.hide();
return;
}

var numOfSelectOptions = 0;
var options = ['SelectAll' , 'Paste', 'Cut', 'Copy'];
options.forEach(function(option) {
console.log(detail['can' + option]);
if (detail['can' + option]) {
numOfSelectOptions++;
this.elements[option.toLowerCase()].style.display = '';
} else {
this.elements[option.toLowerCase()].style.display = 'none';
}
}, this);

if (numOfSelectOptions === 0) {
return;
}

var pos = this.calculateDialogPostion(detail, numOfSelectOptions);

this.element.style.top = pos.top + 'px';
this.element.style.left = pos.left + 'px';

this.element.classList.add('visible');
evt.preventDefault();
};

TextSelectionDialog.prototype.calculateDialogPostion =
function tsd_calculateDialogPostion(detail, numOfSelectOptions) {
var selectOptionWidth = 52;
var selectOptionHeight = 52;
var selectDialogTop = detail.top * detail.zoomFactor;
var selectDialogBottom = detail.bottom * detail.zoomFactor;
var selectDialogLeft = detail.left * detail.zoomFactor;
var selectDialogRight = detail.right * detail.zoomFactor;
var distanceFromBottom = 40;
var distanceFromTop = 12;

var frameHeight = layoutManager.height;
var frameWidth = layoutManager.width;
var posTop = selectDialogTop - selectOptionHeight - distanceFromTop;
// Dialog position align to the center of selected area.
var posLeft = (selectDialogLeft + selectDialogRight -
numOfSelectOptions * selectOptionWidth)/ 2;

console.log('dialog top is ' + selectDialogTop);
console.log('dialog bottom is ' + selectDialogBottom);
console.log('dialog left is ' + selectDialogLeft);

if (!this.app) {
posTop = detail.zoomFactor * posTop + detail.frameOffsetY;
posLeft = detail.zoomFactor * posLeft + detail.frameOffsetX;
}
console.log('frameOffsetY is ' + detail.frameOffsetY);
console.log('frameOffsetX is ' + detail.frameOffsetX);
console.log('zoomFactor is ' + detail.zoomFactor);

if ((selectDialogTop <= 0 && selectDialogBottom >= frameHeight) ||
(selectDialogLeft <= 0 && detail.right >= frameWidth)) {
return {
top: (frameHeight - selectOptionHeight) / 2 + detail.frameOffsetY,
left: (frameWidth - selectOptionWidth) / 2 + detail.frameOffsetX
};
}

// Put dialog under selected area if it overlap statusbar.
if (posTop < 0) {
console.log('pos top is top');
posTop = selectDialogBottom + distanceFromBottom;
}

// Put dialog in the center of selected area if it overlap keyboard.
if (posTop >= frameHeight - distanceFromBottom - selectOptionHeight) {
console.log('pos top is bottom');
posTop = (selectDialogTop + selectDialogBottom -
selectOptionHeight) / 2;
}

if (posTop < 0) {
console.log('pos top is till on the top');
posTop = (selectDialogBottom - selectOptionHeight) / 2;
} else if (posTop >=
frameHeight - distanceFromBottom - selectOptionHeight) {
console.log('pos top is still on the bottom');
posTop = (selectDialogTop + frameHeight - selectOptionHeight) / 2;
}

if (posLeft < 0) {
posLeft = 0;
}

if (posLeft + numOfSelectOptions * selectOptionWidth > frameWidth) {
posLeft = frameWidth - numOfSelectOptions * selectOptionWidth;
}

console.log('frame width is ' + frameWidth);
console.log('frame height is ' + frameHeight);
console.log('pos left is ' + posLeft);
console.log('pos top is ' + posTop);
console.log('num of options is opened: ' + numOfSelectOptions);
return {
top: posTop + detail.frameOffsetY,
left: posLeft + detail.frameOffsetX
};
};

TextSelectionDialog.prototype.hide = function tsd_hide() {
this.element.blur();
this.element.classList.remove('visible');
if (this.app) {
this.app.focus();
}
};

window.TextSelectionDialog = TextSelectionDialog;
}(this));
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit c041556

Please sign in to comment.