8 Commits
Author SHA1 Message Date
Suresh Arumugam ce42a473c1 Fix the clock app radio button alignment
Open-webOS-DCO-1.0-Signed-off-by: Suresh Arumugam <suresh.arumugam@palm.com>

Change-Id: I01b1de7ae531fa6e818dceafe3342d6a31426e07
2012-09-27 15:38:22 -07:00
Suresh Arumugam 0cc7a767e3 Disable EAS option from Email Account setup wizard.
Open-webos-DCO-1.0-Signed-off-by: Suresh Arumugam <suresh.arumugam@palm.com>

Change-Id: Ia0449574c8bfea71889c4295db3e857de324cbbe
2012-09-22 19:25:46 -07:00
Nitika Korla e90e394325 Fixed the enyo path
Open-webOS-DCO-1.0-Signed-off-by: Nitika Korla <nitika.korla@palm.com>

Change-Id: Iba678ffe6f643d8979c475b4d77fc7b972e3b3d3
2012-09-21 12:11:36 -07:00
Nitika Korla a631d8be28 Fixed the blank card for compose email
Change-Id: I68ceafe130bf6882ae5cb5a9a5b53a5cca5ea644
2012-08-30 10:54:01 -07:00
suresh arumugam 2cefb5354e Fixed JS error in HtmlView
Change-Id: I87ac877bc21961c1e60852c939614ba4f7c89c43
2012-08-29 12:59:56 -07:00
suresh arumugam 98d8f93174 Modified Calculator App Id.
Change-Id: I96bf5d8b2b801ab778a7390bece2a9d491c18ad4
2012-08-28 09:27:06 -07:00
suresh arumugam 3402e84419 Modified Readme file. Added Html Sanitizer function. Added HtmlView to replace webview widget
Change-Id: Ie2b4b84cef796dac4cfb01d434360823eea1cb4b
2012-08-28 09:13:42 -07:00
Nitika Korla 77734cfbe8 Modified enyo framework path for index.html files
Change-Id: I0c8838d9bc1d8c70708814d67e5ea427ffb065b6
2012-08-27 11:37:44 -07:00
16 changed files with 587 additions and 26 deletions

No files matched your search

+2
View File
@@ -1 +1,3 @@
BuildResults
.project
.settings
+2 -2
View File
@@ -1,5 +1,5 @@
{
"id": "com.palm.calculator",
"id": "com.palm.app.calculator",
"version": "3.0.1300",
"vendor": "HP",
"type": "web",
@@ -9,4 +9,4 @@
"splashicon": "icon-256x256.png",
"uiRevision": "2",
"removable": false
}
}
+1 -1
View File
@@ -28,7 +28,7 @@ limitations under the License.
<link rel="icon" type="image/png" href="images/icon.png">
<link rel="shortcut icon" type="image/png" href="images/icon.png">
<script type="text/javascript" src="../../../enyo/0.10/framework/enyo.js" launch="nobridge&nodebug"></script>
<script type="text/javascript" src="/usr/palm/frameworks/enyo/0.10/framework/enyo.js" launch="nobridge&nodebug"></script>
</head>
<body>
<script type="text/javascript" src="../libs/hacks.js"></script>
@@ -24,7 +24,7 @@ limitations under the License.
</script>
<title>Reminder</title>
<script type="text/javascript" src="../../../../enyo/0.10/framework/enyo.js" launch="nobridge"></script>
<script type="text/javascript" src="/usr/palm/frameworks/enyo/0.10/framework/enyo.js" launch="nobridge"></script>
</head>
<body>
<script type="text/javascript" src="Reminder.js"></script>
+2 -2
View File
@@ -32,11 +32,11 @@ limitations under the License.
<link rel="shortcut icon" type="image/png" href="images/icon.png">
<script type="text/javascript" src="/usr/palm/frameworks/mojoloader.js"></script>
<script type="text/javascript" src="../../enyo/0.10/framework/enyo.js" launch="nobridge&nodebug"></script>
<script type="text/javascript" src="/usr/palm/frameworks/enyo/0.10/framework/enyo.js" launch="nobridge&nodebug"></script>
</head>
<body>
<script type="text/javascript" src="libs/mock.js"></script>
<script type="text/javascript" src="index.js"></script>
</body>
</html>
end
end
+3 -3
View File
@@ -37,8 +37,8 @@ enyo.kind({
{kind: "Toolbar", components: [
{kind: "Spacer"},
{name: "radSelectView", kind: "RadioGroup", onChange: "onChange_radSelectView", components: [
{icon: "images/menu-icon-clock.png"},
{icon: "images/menu-icon-alarm.png"}
{icon: "images/menu-icon-clock.png", style:"width:100%;"},
{icon: "images/menu-icon-alarm.png", style:"width:100%;"}
]},
{kind: "Spacer"}
]}
@@ -307,4 +307,4 @@ enyo.kind({
});
});
+1 -1
View File
@@ -19,7 +19,7 @@ limitations under the License.
<html>
<head>
<title>Contacts</title>
<script src="../../enyo/0.10/framework/enyo.js" type="text/javascript"></script>
<script src="/usr/palm/frameworks/enyo/0.10/framework/enyo.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
+1 -1
View File
@@ -21,7 +21,7 @@ limitations under the License.
<title>Jasmine Test Runner</title>
<!-- MODIFY ACCORDINGLY TO *LOCAL* ENYO SOURCE FILE -->
<script src="../../enyo/0.10/framework/enyo.js" type="text/javascript"></script>
<script src="/usr/palm/frameworks/enyo/0.10/framework/enyo.js" type="text/javascript"></script>
<!-- MODIFY ACCORDINGLY TO *LOCAL* JASMINE SOURCE FILES -->
<link rel="stylesheet" type="text/css" href="../../frameworks/jasmine/jasmine.css">
+7
View File
@@ -2,6 +2,13 @@
Email application for webOS. Written using enyo 1.0.
# Limitations and Known Issues
## User Credentials will be stored in clear format in the db8. Secure storing support will be added later.
## HTML Sanitizer function used in the Email display message view, is limited to remove only certain tags such as Script, iframe, object, embed. More generic solution is planned for post beta release.
# App launch lifecycle
The email app is launched automatically at boot. There is a headless window,
@@ -55,8 +55,8 @@ enyo.kind({
onChange: "accountTypeChanged",
items: [
{caption: $L("IMAP"), value: AccountWizard.IMAP},
{caption: $L("POP"), value: AccountWizard.POP},
{caption: $L("EAS"), value: AccountWizard.EAS} /* , showing: false */
{caption: $L("POP"), value: AccountWizard.POP}
/* {caption: $L("EAS"), value: AccountWizard.EAS} /* , showing: false */
]
}
]},
+1 -2
View File
@@ -27,6 +27,5 @@ enyo.depends(
"source/Composition.js",
"source/EmailRecipient.js",
"../controls/",
"../css/compose.css",
"/usr/palm/frameworks/caja/html-sanitizer-minified.js"
"../css/compose.css"
);
+8 -2
View File
@@ -312,11 +312,12 @@ enyo.kind({
if (this.composition.originalText) {
this.$.originalMessageBody.show();
var sanitized = html_sanitize(this.composition.sanitizeOriginalText(), function (url) {
/* var sanitized = html_sanitize(this.composition.sanitizeOriginalText(), function (url) {
return url;
}, function (id) {
return id;
});
});*/
var sanitized = this.sanitizeHtml(this.composition.sanitizeOriginalText());
this.$.originalMessageBody.setValue(sanitized);
}
@@ -916,5 +917,10 @@ enyo.kind({
this.$.missingRecipientsAlert.close();
this.$.badRecipientsAlert.close();
this.$.toInput.forceFocus();
},
sanitizeHtml: function (unsafeHtml) {
var rEx = new RegExp("<(script|object|embed|iframe)[^>]*>([\\S\\s]*?)<\/(script|object|embed|iframe)>", "gim");
return unsafeHtml.replace(rEx,"");
}
});
+1
View File
@@ -33,6 +33,7 @@ enyo.depends(
"source/Folders.js",
"source/Mail.js",
"source/MessagePane.js",
"source/HtmlView.js",
"source/MessageDisplay.js",
"source/MessageLoader.js",
"source/DarkSwipeable.js",
+529
View File
@@ -0,0 +1,529 @@
// @@@LICENSE
//
// Copyright (c) 2010-2012 Hewlett-Packard Development Company, L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// LICENSE@@@
enyo.kind({
name: "AbstractHtmlView",
kind: "Control",
events: {
onViewReady: "",
onLoadFailed: "",
onLinkClick: "",
onInspectElement: ""
},
published: {
cidMap: {},
allowRemoteContent: true
},
create: function () {
this.inherited(arguments);
},
// Returns true if the HtmlView is more or less ready and has content displayed
// The accuracy of this method may depend on the implementation.
isReady: function () {
return false;
},
activate: function () {
},
deactivate: function () {
},
});
enyo.kind({
name: "WebviewHtmlView",
kind: "AbstractHtmlView",
create: function () {
this.inherited(arguments);
this.webviewBodyLoaded = false;
},
destroy: function () {
// FIXME workaround for bug in webview
try {
this.inherited(arguments);
} catch (e) {
this.error(e);
}
},
createWebview: function () {
this.createComponent({
name: "webview",
kind: "WebView",
fitRender: false,
acceptCookies: false,
enableJavascript: false,
ignoreMetaTags: true,
onSingleTap: "webviewTap",
onUrlRedirected: "doLinkClick",
onLoadStarted: "webviewLoadStarted",
onLoadComplete: "webviewLoadComplete",
onLoadStopped: "webviewLoadStopped"
});
this.$.webview.render();
},
initWebview: function () {
if (!this.$.webview) {
this.createWebview();
this.setupWebview();
}
},
setupWebview: function () {
if (this._webviewReady) {
return;
}
this.$.webview.setRedirects([
{regex: "^file:.*", cookie: "", enable: false},
{regex: ".*", cookie: "", enable: true}
]);
// Hack to prevent double url loads
var origUrlChanged = viewControl.urlChanged.bind(viewControl);
viewControl.urlChanged = function (old) {
if (viewControl.url !== viewControl._pendingUrl) {
console.log("calling orig");
viewControl._pendingUrl = viewControl.url;
origUrlChanged(old);
}
};
var origLoadStarted = viewControl.loadStarted.bind(viewControl);
viewControl.loadStarted = function () {
viewControl._pendingUrl = undefined;
origLoadStarted();
}
this._webviewReady = true;
},
// [public]
loadUrl: function (url) {
this.initWebview();
this.$.webview.setUrl(url);
},
// [public]
activate: function () {
this.initWebview();
this.log("activating webview");
this.$.webview.activate();
},
// [public]
deactivate: function () {
if (this.$.webview) {
this.$.webview.activate();
}
},
webviewLoadStarted: function () {
console.log("load started");
this.webviewBodyLoaded = false;
},
webviewLoadComplete: function () {
this.loadTimer = window.setTimeout(this.webviewReady.bind(this), 1000);
},
webviewLoadStopped: function () {
console.log("load stopped");
this.webviewBodyLoaded = true;
this.webviewReady();
},
webviewReady: function () {
if (this.loadTimer) {
window.clearTimeout(this.loadTimer);
}
this.doViewReady();
},
webviewTap: function () {
// TODO
return true;
},
});
enyo.kind({
name: "InlineHtmlView",
kind: "AbstractHtmlView",
CID_REGEX: /^cid:/i,
CSS_RULE_REGEX: /\s*([-\w]+)\s*:\s*([^:;]*)?(;|$)/g,
CSS_UNSAFE_PROPERTY_REGEX: /(^-\w+)|behavior$/i,
CSS_URL_NOTATION_REGEX: /url\s*\(((?:\\.|.)*?)\)/i,
VALID_RESOURCE_URL_REGEX: /^https?:/i,
VALID_LINK_URL_REGEX: /^(https?|mailto):/i,
create: function () {
this.inherited(arguments);
},
// TODO: make this take a callback since both loading and sanitizing may be asynchronous later
loadAndSanitize: function (url, contentType) {
url = url.replace("file://", "");
var unsafeData = palmGetResource(url);
return this.loadedAndSanitize(unsafeData, contentType);
},
loadedAndSanitize: function(unsafeData, contentType) {
// This will get set to true if checkAllowExternalResource blocks a url
this.remoteContentWasBlocked = false;
var isHtml = (contentType.toLowerCase() == "text/html");
// FIXME currently very slow for some emails
var cleanHtml = isHtml ? this.sanitizeHtml(unsafeData) : this.sanitizeText(unsafeData);
return cleanHtml;
},
// Returns true if a remote content url (e.g. external image) was blocked from being displayed
wasRemoteContentBlocked: function () {
return this.remoteContentWasBlocked;
},
// Check whether a url can be loaded in an image tag or css style
checkAllowExternalResource: function (url) {
if (!this.allowRemoteContent) {
this.remoteContentWasBlocked = true;
return false;
}
return this.VALID_RESOURCE_URL_REGEX.test(url);
},
// Check whether a link can be referenced
checkAllowLink: function (url) {
return this.VALID_LINK_URL_REGEX.test(url);
},
// Check if this external url is allowed
mapUrl: function (url, tagName, attribName) {
if (this.CID_REGEX.test(url)) {
// replace cid: reference with local file path
return this.cidMap[url.substr(4)] || "";
}
if (tagName === "a" && attribName === "href") {
return this.checkAllowLink(url) ? url : null;
} else if (tagName === "img" && attribName === "src") {
return this.checkAllowExternalResource(url) ? url : null;
} else {
return null;
}
},
// Checks and possibly removes external urls in inline css styles
// TODO: TEST
mapInlineStyle: function (style) {
var self = this;
var cleanStyle = "";
// Extract css rules one-by-one to make sure there's nothing tricky
var rule = new RegExp(this.CSS_RULE_REGEX); // copy for repeated matches
var m;
while (!!(m = rule.exec(style))) {
var name = m[1];
var value = m[2];
if (!name || !value || this.CSS_UNSAFE_PROPERTY_REGEX.exec(name)) {
// unsafe css property
continue;
}
// Cleanup urls
value = value.replace(self.CSS_URL_NOTATION_REGEX, function (s, match1) {
return self.checkAllowExternalResource(match1) ? s : "url()";
});
// Append normalized css
cleanStyle += name + ":" + value + ";";
}
return cleanStyle;
},
/*sanitizeHtml: function (unsafeHtml) {
var cidMap = this.cidMap;
return HtmlSanitizer.sanitize(unsafeHtml,
this.mapUrl.bind(this),
this.mapInlineStyle.bind(this)
);
},*/
sanitizeHtml: function (unsafeHtml) {
var rEx = new RegExp("<(script|object|embed|iframe)[^>]*>([\\S\\s]*?)<\/(script|object|embed|iframe)>", "gim");
return unsafeHtml.replace(rEx,"");
},
sanitizeText: function (unsafeText) {
var text = enyo.string.escapeHtml(unsafeText);
text = text.replace(/\r\n|\n|\r/g, "<br>");
// TODO: more sophisticated text formatting
return text;
}
});
enyo.kind({
name: "DivHtmlView",
kind: "InlineHtmlView",
className: "divhtmlview",
components: [
/* clipbox lets us explicitly size the content (based on scaling calculations) */
{name: "clipbox", className: "divhtmlview-clipbox", components: [
/* contents of the HTML area */
{name: "wrapper", allowHtml: true /* must sanitize */, onclick: "wrapperClick", onmouseup: "wrapperMouseup", requiresDomClick: true, className: "divhtmlview-wrapper selectable"}
]}
],
mixins: [
enyo.sizeableMixin
],
published: {
zoom: 1.0,
url: null
},
create: function () {
this.inherited(arguments);
this.viewReady = false;
},
rendered: function () {
this.inherited(arguments);
this.clipboxNode = this.$.clipbox.hasNode();
this.wrapperNode = this.$.wrapper.hasNode();
},
isReady: function () {
return this.viewReady;
},
// [public]
loadUrl: function (url, contentType) {
if (!url) {
this.log("no url provided");
return;
}
this.url = url;
this.contentType = contentType || "text/plain";
if(window.PalmSystem) {
enyo.asyncMethod(this, enyo.bind(this, "loadPage"));
}
else {
enyo.xhr.request({
url: url,
method: "GET",
callback: enyo.bind(this, "loadPage")
});
}
},
activate: function () {
},
deactivate: function () {
},
loadPage: function (inSender, inResponse) {
var cleanHtml;
if(window.PalmSystem) {
cleanHtml = this.loadAndSanitize(this.url, this.contentType);
}
else {
if(!inResponse || inResponse.responseText === '') {
cleanHtml = $L("Error opening email.");
}
else {
cleanHtml = this.loadedAndSanitize(inResponse.responseText, this.contentType);
}
}
this.$.wrapper.setContent(cleanHtml);
this.fitWidth();
this.viewReady = true;
this.doViewReady();
},
fitWidth: function () {
var viewWidth = this.hasNode().clientWidth;
var contentWidth = this.wrapperNode.scrollWidth;
if (contentWidth > viewWidth) {
this.setZoom(viewWidth / contentWidth);
}
},
// start pinch zoom
gesturestartHandler: function (sender, e) {
this.centeredZoomStart(e);
},
// pinch zoom
gesturechangeHandler: function (sender, e) {
var gi = this.centeredZoomChange(e);
// Change zoom if greater than some threshold to prevent jitter
var delta = Math.abs(gi.zoom - this.zoom);
if (delta >= 0.08) {
this.setZoom(gi.zoom);
//this.setScrollPositionDirect(gi.x, gi.y);
}
},
// end pinch zoom
gestureendHandler: function (sender, e) {
},
getMinZoom: function () {
// calculate every time in case the size changes
var viewWidth = this.hasNode().clientWidth;
var contentWidth = this.wrapperNode.scrollWidth;
return Math.max(0.3, viewWidth / contentWidth);
},
getMaxZoom: function () {
return 1.0;
},
// hacky support for old versions of enyo
calcZoomOffset: function() {
return {left: 0, top: 0};
},
getZoomRect: function () {
var contentHeight = this.wrapperNode.scrollHeight;
var contentWidth = this.wrapperNode.scrollWidth;
return {
left: 0,
top: 0,
width: contentHeight * this.zoom,
height: contentWidth * this.zoom
};
},
zoomChanged: function () {
var contentWidth = this.wrapperNode.scrollWidth;
var contentHeight = this.wrapperNode.scrollHeight;
this.zoom = Math.max(this.getMinZoom(), Math.min(this.zoom, this.getMaxZoom()));
//console.log("setting zoom to " + this.zoom);
this.$.wrapper.applyStyle("-webkit-transform", "scale(" + this.zoom + ")");
this.$.wrapper.applyStyle("-webkit-transform-origin", "0 0");
// Change the size of the container to match the scaled size
this.$.clipbox.applyStyle("width", Math.ceil(this.zoom * contentWidth) + "px");
this.$.clipbox.applyStyle("height", Math.ceil(this.zoom * contentHeight) + "px");
},
mouseholdHandler: function (sender, event) {
var props = this.findLinkOrImageProperties(event.target, this.hasNode());
if (props) {
//console.log("mouse hold on link or image: " + JSON.stringify(props));
this.doInspectElement(event, props);
return true;
}
},
wrapperMouseup: function(sender, event) {
// Need to record if there was a drag
this.didDrag = event.didDrag;
},
wrapperClick: function(sender, event) {
// Check if there was a drag
// NOTE: Can't use event.didDrag because it gets cleared during the mouseup
if (this.didDrag) {
this.didDrag = false;
// Don't click if there was a drag
event.preventDefault();
return true;
}
var props = this.findLinkOrImageProperties(event.target, this.wrapperNode);
var url = props && props.linkUrl;
if (url) {
this.doLinkClick(url, event);
event.preventDefault();
return true;
}
},
// find link and/or image (may be both)
findLinkOrImageProperties: function (inNode, inAncestor) {
var props = undefined;
var n = inNode;
while (n && n != inAncestor) {
var tagLower = n.tagName.toLowerCase();
if (tagLower === "a" && n.href) {
props = props || {};
props.linkUrl = n.href;
// exit when we see an anchor tag
break;
} else if (tagLower === "img" && n.src) {
props = props || {};
props.imageSrc = n.src;
// keep searching for an anchor tag
}
n = n.parentNode;
}
return props;
}
});
@@ -38,7 +38,7 @@ enyo.kind({
// Email Body Content starts here
// this sauce is weak. So weak.
((window.fauxMail || !window.PalmSystem) ?
/*((window.fauxMail || !window.PalmSystem) ?
// FAKE webview
{name: "body", kind: "Control", nodeTag: "pre", flex: 1, className: "mail-body", resize: function () {
},
@@ -51,8 +51,10 @@ enyo.kind({
onAlertDialog: "alertDialogHandler", onConfirmDialog: "confirmDialogHandler", onPromptDialog: "promptDialogHandler",
onSSLConfirmDialog: "SSLConfirmDialogHandler"
}
),
),*/
// This goes second, even though it is displayed first, in order to float over the webview
{kind:"Scroller", flex:1, style:"height:1000px;", components:[
{name: "mailHeaderUnit", components: [
{name: "header", className: "body-header", components: [
{name: "bodyStamp", className: "body-stamp", components: [
@@ -141,6 +143,7 @@ enyo.kind({
]}
]},
// end email header
{name: "body", kind: "DivHtmlView", showing: true, onViewReady: "viewReady", onLinkClick: "openLink"},
{name: "messageErrors", kind: "Pane", showing: false, flex: 1, components: [
{name: "downloadError", className: "body-placeholder", style: "text-align: center; background:white;", pack: "center", kind: "VFlexBox", components: [
{kind: "Image", src: "../images/list-error.png"},
@@ -157,6 +160,7 @@ enyo.kind({
]}
]}
]}, // end mail header unit
]},
{name: "appMgrOpen", method: "open", kind: "enyo.PalmService", service: enyo.palmServices.application},
{name: "pseudoDetails", kind: "com.palm.library.contactsui.detailsDialog", onCancelClicked: "closePseudoDetails"},
{name: "webviewContextMenu", kind: "PopupSelect", onSelect: "webviewContextMenuSelect"}
@@ -628,15 +632,19 @@ enyo.kind({
},
setBody: function (email, isQuoting) {
if (this.$.body.setHTML) { // i.e., a real WebView, which we use onDevice
/*if (this.$.body.setHTML) { // i.e., a real WebView, which we use onDevice
var body = email.getBodyPart();
var html = this._buildMessageHTML(body.path, body.mimeType, isQuoting);
this.$.body.setHTML("file:///email-local-content.html", html);
//this.$.body.setHTML("file:///email-local-content.html", html);
this.resize();
} else {
this.$.body.setContent(email.data.summary);
}
}*/
var body = email.getBodyPart();
this.$.body.loadUrl("file://" + body.path, body.mimeType);
},
_buildMessageHTML: function (path, mimeType, replyOrForward) {
@@ -841,7 +849,7 @@ enyo.kind({
}
},
mousedownHandler: function (sender, event) {
/* mousedownHandler: function (sender, event) {
return this.forwardMouseEventToBody(event);
},
@@ -862,7 +870,7 @@ enyo.kind({
// Hack to call flick handler in header on body
// FIXME should pass event instead?
return this.$.body.$.view.flickHandler(sender, event);
},
},*/
headerResized: function (sender, event) {
var view = this.$.body,
@@ -883,10 +891,11 @@ enyo.kind({
}
},
resize: function () {
this.headerResized();
/*this.headerResized();
if (this.$.body.resize) {
this.$.body.resize();
}
}*/
this.resized(); // provided by enyo. needed for vertical reflow
this._doingNestedScroll = undefined;
},
@@ -900,6 +909,14 @@ enyo.kind({
]);
}
},
openLink: function (sender, url) {
// TODO remove this logging
this.log("### Opening URL", url);
// Launch default app for handling this url
this.$.appMgrOpen.call({target: url, subscribe: false});
},
DEFAULT_SENDER_IMAGE: '../images/detail_avatar.png'
});