versioned resources for release
|
@ -0,0 +1,323 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||
- Version: MPL 1.1
|
||||
-
|
||||
- The contents of this file are subject to the Mozilla Public License Version
|
||||
- 1.1 (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.mozilla.org/MPL/
|
||||
-
|
||||
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
- for the specific language governing rights and limitations under the
|
||||
- License.
|
||||
-
|
||||
- The Original Code is Raindrop.
|
||||
-
|
||||
- The Initial Developer of the Original Code is
|
||||
- Mozilla Messaging, Inc..
|
||||
- Portions created by the Initial Developer are Copyright (C) 2009
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- -->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Firefox Share OAuthorization</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
|
||||
<script src="/0.3.4/scripts/requireplugins-jquery.js" charset="utf-8"></script>
|
||||
<style>
|
||||
html, body {
|
||||
background-color: #fff;
|
||||
height: 100%;
|
||||
color: #0A0A0A;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.connecting {
|
||||
margin-top: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.connecting img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#oauth {
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -150px;
|
||||
margin-top: -95px;
|
||||
width: 300px;
|
||||
background-image: url("/0.3.4/i/f1Logo.png");
|
||||
background-position: center top;
|
||||
background-repeat: no-repeat;
|
||||
padding: 100px 0 0 0;
|
||||
}
|
||||
|
||||
#oauth .text {
|
||||
display: block;
|
||||
margin: 0 0 7px 0;
|
||||
}
|
||||
|
||||
#oauth .subtext {
|
||||
margin-left: 7px;
|
||||
color: #666666;
|
||||
font-family: "Lucida Grande", Verdana, sans-serif;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.controls {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 30px;
|
||||
border-width: 1px 1px 1px 0;
|
||||
border-style: solid;
|
||||
border-color: #888;
|
||||
cursor: pointer;
|
||||
padding: 0 10px;
|
||||
|
||||
-moz-border-radius: 0 2px 2px 0;
|
||||
-webkit-border-radius: 0 2px 2px 0;
|
||||
border-radius: 0 2px 2px 0;
|
||||
|
||||
background-image: -moz-linear-gradient(center top , #fafafa 0%, #ddd 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fafafa), color-stop(100%, #ddd));
|
||||
}
|
||||
|
||||
button:active {
|
||||
-moz-box-shadow: 0 0 1px #666666 inset;
|
||||
-webkit-box-shadow: 0 0 1px #666666 inset;
|
||||
box-shadow: 0 0 1px #666666 inset;
|
||||
|
||||
background-image: -moz-linear-gradient(center top , #eee 0%, #ccc 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #eee), color-stop(100%, #ccc));
|
||||
}
|
||||
|
||||
input {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #888;
|
||||
font-family: "Lucida Grande", Verdana, sans-serif;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
|
||||
-moz-border-radius: 2px 0 0 2px;
|
||||
-moz-box-shadow:0 3px 3px -3px rgba(0, 0, 0, 0.25) inset, 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
-moz-box-shadow: 0 0 0 3px rgba(0, 162, 255, 0.25) inset, 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
input.google {
|
||||
background-image: url("/0.3.4/i/sprite.png");
|
||||
background-position: 5px -159px;
|
||||
background-repeat: no-repeat;
|
||||
padding: 0 0 0 26px;
|
||||
}
|
||||
|
||||
.hbox {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-align: stretch;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: horizontal;
|
||||
-moz-box-align: stretch;
|
||||
|
||||
display: box;
|
||||
box-orient: horizontal;
|
||||
box-align: stretch;
|
||||
}
|
||||
|
||||
.hbox > * {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.vbox {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-align: stretch;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
-moz-box-align: stretch;
|
||||
|
||||
display: box;
|
||||
box-orient: vertical;
|
||||
box-align: stretch;
|
||||
}
|
||||
|
||||
.vbox > * {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
box-flex: 1;
|
||||
}
|
||||
|
||||
.reverse {
|
||||
-webkit-box-direction: reverse;
|
||||
-moz-box-direction: reverse;
|
||||
box-direction: reverse;
|
||||
}
|
||||
|
||||
.boxFlex0 {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
}
|
||||
|
||||
.boxFlex1, .boxFlex {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
box-flex: 1;
|
||||
}
|
||||
|
||||
.boxFlex2 {
|
||||
-webkit-box-flex: 2;
|
||||
-moz-box-flex: 2;
|
||||
box-flex: 2;
|
||||
}
|
||||
|
||||
.boxGroup1 {
|
||||
-webkit-box-flex-group: 1;
|
||||
-moz-box-flex-group: 1;
|
||||
box-flex-group: 1;
|
||||
}
|
||||
|
||||
.boxGroup2 {
|
||||
-webkit-box-flex-group: 2;
|
||||
-moz-box-flex-group: 2;
|
||||
box-flex-group: 2;
|
||||
}
|
||||
|
||||
.start {
|
||||
-webkit-box-pack: start;
|
||||
-moz-box-pack: start;
|
||||
box-pack: start;
|
||||
}
|
||||
|
||||
.end {
|
||||
-webkit-box-pack: end;
|
||||
-moz-box-pack: end;
|
||||
box-pack: end;
|
||||
}
|
||||
|
||||
.center {
|
||||
-webkit-box-pack: center;
|
||||
-moz-box-pack: center;
|
||||
box-pack: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
<script>
|
||||
require(["require", "jquery", "blade/url", "services", "jquery.cookie"],
|
||||
function (require, $, url, services) {
|
||||
var target = window.location.href.split('#')[1];
|
||||
if (target && (target === 'oauth_success' || target === 'oauth_failure')) {
|
||||
|
||||
//TODO: ideally lock down the domain be location.hostname, but
|
||||
//a problem for 127 addresses?
|
||||
// XXX hacky way to handle fennec, since we didn't open a window,
|
||||
// catch the exception when using window.opener and redirect
|
||||
var data = {
|
||||
target: target,
|
||||
account: JSON.parse($.cookie("account_tokens"))
|
||||
};
|
||||
window.opener.postMessage(JSON.stringify(data), '*');
|
||||
// clear the cookie, we no longer want it around
|
||||
$.cookie("account_tokens", "", {"path": "/"});
|
||||
window.close();
|
||||
}
|
||||
|
||||
var search = window.location.href.split('?')[1];
|
||||
if (search) {
|
||||
search = search.split('#')[0];
|
||||
|
||||
var args = url.queryToObject(search),
|
||||
domain = args.domain;
|
||||
|
||||
$(function () {
|
||||
if (domain) {
|
||||
// add a force login param to the form if asked.
|
||||
if (args.forceLogin) {
|
||||
var forceLogin = services.domains[domain].forceLogin;
|
||||
if (forceLogin) {
|
||||
$('<input type="hidden" name="' +
|
||||
forceLogin.name +
|
||||
'" value="' + forceLogin.value + '">').appendTo('[name="authForm"]');
|
||||
}
|
||||
}
|
||||
|
||||
$("#domain").attr("value", args['domain']);
|
||||
|
||||
if (args['domain'] == 'googleapps.com') {
|
||||
// show UI for googleapp
|
||||
$('#oauth').removeClass('hidden');
|
||||
$('#message').addClass('hidden');
|
||||
$('#submitbtn').click(function (evt) {
|
||||
$('#oauth').addClass('hidden');
|
||||
$('#message').removeClass('hidden');
|
||||
document.authForm.submit();
|
||||
});
|
||||
} else {
|
||||
document.authForm.submit();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body class="settings">
|
||||
|
||||
<div id="oauth" class="authorize hidden">
|
||||
<form name="authForm" action="/api/account/authorize" method="POST">
|
||||
<input type="hidden" name="domain" id="domain" value="">
|
||||
<span class="text">Enter your Google Apps domain</span>
|
||||
<div class="controls hbox">
|
||||
<input class="boxFlex google" name="openid_identifier" id="openid_identifier" value="">
|
||||
<input class="boxFlex google" type="hidden" name="end_point_success" value="/0.3.4/auth.html#oauth_success">
|
||||
<input class="boxFlex google" type="hidden" name="end_point_auth_failure" value="/0.3.4/auth.html#oauth_failure">
|
||||
<button id='submitbtn' type="submit">submit</button>
|
||||
</div>
|
||||
<span class="subtext">ex: yourappdomain.com</span>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div style="clear: both"/>
|
||||
</div>
|
||||
|
||||
<div id='message' class="connecting"><img src="i/loader-w.gif"> connecting...</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
({
|
||||
baseUrl: "scripts/",
|
||||
paths: {
|
||||
"index": "../index",
|
||||
"jquery": "requireplugins-jquery"
|
||||
},
|
||||
name: "index",
|
||||
exclude: ['jquery'],
|
||||
out: './index.js'
|
||||
})
|
После Ширина: | Высота: | Размер: 1.1 KiB |
После Ширина: | Высота: | Размер: 469 B |
После Ширина: | Высота: | Размер: 716 B |
После Ширина: | Высота: | Размер: 494 B |
После Ширина: | Высота: | Размер: 142 B |
После Ширина: | Высота: | Размер: 139 B |
После Ширина: | Высота: | Размер: 136 B |
После Ширина: | Высота: | Размер: 139 B |
После Ширина: | Высота: | Размер: 389 B |
После Ширина: | Высота: | Размер: 4.7 KiB |
После Ширина: | Высота: | Размер: 4.4 KiB |
После Ширина: | Высота: | Размер: 448 B |
После Ширина: | Высота: | Размер: 43 B |
После Ширина: | Высота: | Размер: 1.5 KiB |
После Ширина: | Высота: | Размер: 10 KiB |
После Ширина: | Высота: | Размер: 1.4 KiB |
После Ширина: | Высота: | Размер: 1.4 KiB |
После Ширина: | Высота: | Размер: 107 B |
После Ширина: | Высота: | Размер: 106 B |
После Ширина: | Высота: | Размер: 347 B |
После Ширина: | Высота: | Размер: 324 B |
После Ширина: | Высота: | Размер: 111 B |
После Ширина: | Высота: | Размер: 352 B |
После Ширина: | Высота: | Размер: 340 B |
После Ширина: | Высота: | Размер: 103 B |
После Ширина: | Высота: | Размер: 503 B |
После Ширина: | Высота: | Размер: 96 B |
После Ширина: | Высота: | Размер: 70 B |
После Ширина: | Высота: | Размер: 506 B |
После Ширина: | Высота: | Размер: 203 B |
После Ширина: | Высота: | Размер: 176 B |
После Ширина: | Высота: | Размер: 15 KiB |
После Ширина: | Высота: | Размер: 468 B |
После Ширина: | Высота: | Размер: 2.7 KiB |
После Ширина: | Высота: | Размер: 67 KiB |
После Ширина: | Высота: | Размер: 62 KiB |
После Ширина: | Высота: | Размер: 3.4 KiB |
После Ширина: | Высота: | Размер: 27 KiB |
После Ширина: | Высота: | Размер: 23 KiB |
После Ширина: | Высота: | Размер: 5.2 KiB |
После Ширина: | Высота: | Размер: 27 KiB |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 4.1 KiB |
После Ширина: | Высота: | Размер: 4.1 KiB |
После Ширина: | Высота: | Размер: 4.2 KiB |
После Ширина: | Высота: | Размер: 3.4 KiB |
После Ширина: | Высота: | Размер: 390 B |
После Ширина: | Высота: | Размер: 494 B |
|
@ -0,0 +1,172 @@
|
|||
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||
- Version: MPL 1.1
|
||||
-
|
||||
- The contents of this file are subject to the Mozilla Public License Version
|
||||
- 1.1 (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.mozilla.org/MPL/
|
||||
-
|
||||
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
- for the specific language governing rights and limitations under the
|
||||
- License.
|
||||
-
|
||||
- The Original Code is Raindrop.
|
||||
-
|
||||
- The Initial Developer of the Original Code is
|
||||
- Mozilla Messaging, Inc..
|
||||
- Portions created by the Initial Developer are Copyright (C) 2009
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- -->
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:og="http://opengraphprotocol.org/schema/"
|
||||
xmlns:fb="http://www.facebook.com/2008/fbml">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/0.3.4/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="/0.3.4/jquery.fancybox-1.3.4.css">
|
||||
<link rel="stylesheet" type="text/css" href="resource://ffshare/chrome/skin/web/installed.css">
|
||||
|
||||
<title>Mozilla F1</title>
|
||||
<script type="text/javascript" data-main="/0.3.4/index.js" src="/0.3.4/scripts/requireplugins-jquery.js"></script>
|
||||
<link rel="icon" type="image/x-icon" href="/0.3.4/favicon.png" />
|
||||
|
||||
<!-- https://github.com/mozilla/f1/wiki/Page-Meta-Properties -->
|
||||
|
||||
<link rel="shortlink" href="http://bit.ly/mozillaF1"/>
|
||||
<link rel="canonical" href="http://f1.mozillamessaging.com/"/>
|
||||
|
||||
<meta property="og:title" content="Mozilla F1"/>
|
||||
<meta property="og:type" content="website"/>
|
||||
<meta property="og:url" content="http://f1.mozillamessaging.com/"/>
|
||||
<meta property="og:image" content="http://f1.mozillamessaging.com/i/f1LogoVert.png"/>
|
||||
<meta property="og:site_name" content="Mozilla F1"/>
|
||||
<meta property="og:description"
|
||||
content="F1 is a browser extension that allows you to share links in a
|
||||
fast and fun way. Share links from within the browser, from any
|
||||
webpage, using the same services you already know and love."/>
|
||||
|
||||
<meta property="fb:app_id" content="173375079345318,146290642084944"/>
|
||||
|
||||
<meta name="title" content="Mozilla F1"/>
|
||||
<meta name="description"
|
||||
content="F1 is a browser extension that allows you to share links in a
|
||||
fast and fun way. Share links from within the browser, from any
|
||||
webpage, using the same services you already know and love."/>
|
||||
|
||||
<meta name="application-url" content="http://f1.mozillamessaging.com/"/>
|
||||
|
||||
<link rel="image_src" href="http://f1.mozillamessaging.com/i/f1LogoVert.png"/>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<div id="header" class="row">
|
||||
<div class="c2 logo">
|
||||
/ <a href="http://mozillalabs.com/messaging/">F1 Blog »</a>
|
||||
</div>
|
||||
<div class="c1 dl">
|
||||
<button id="downloadFF4" class="download downloadXpi">
|
||||
Install Mozilla F1
|
||||
<span class="meta">available for Firefox 4 beta</span>
|
||||
</button>
|
||||
<button id="firefox" class="download">
|
||||
Get Firefox 4 beta to use <br>this add-on
|
||||
</button>
|
||||
<a id="no36" href="#info36">*Firefox 3.6 is no longer supported</a>
|
||||
<div id="noButtonFF4">
|
||||
<img src="/0.3.4/i/check.png"> status: installed
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row headline">
|
||||
<div class="c1 description">
|
||||
<h1>Share links fast.</h1>
|
||||
<h2>So, what’s F1?</h2>
|
||||
F1 is a browser extension that allows you to share links in a fast and fun way. Share links from within the browser, from any webpage, using the same services you already know and love. Mozilla F1 is made by Mozilla Messaging.
|
||||
<button class="fancybox">watch demo</button>
|
||||
</div>
|
||||
<div class="c2">
|
||||
<img src="/i/panel/f1panel.png">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<hr>
|
||||
<div class="c2 description">
|
||||
<img src="/i/panel/f1accounts.png">
|
||||
</div>
|
||||
<div class="c1 description">
|
||||
<h2>Share with your<br> favorite services</h2>
|
||||
With support for Facebook, Twitter, Gmail, Google Apps, Yahoo Mail and LinkedIn, we have your favorite services covered—and we're adding more services with every release.
|
||||
</div>
|
||||
</div>
|
||||
<div class="row about">
|
||||
<hr>
|
||||
<div class="c3 description">
|
||||
<h2>Once you've installed F1 sharing is as easy as...</h2>
|
||||
</div>
|
||||
<div class="c1 description steps">
|
||||
<span class="step">1</span> Hit the F1 icon in the URL bar
|
||||
<img src="i/panel/step-01.png">
|
||||
</div>
|
||||
<div class="c1 description steps">
|
||||
<span class="step">2</span> Choose your service in the menu
|
||||
<img src="i/panel/step-022.png">
|
||||
</div>
|
||||
<div class="c1 description steps">
|
||||
<span class="step">3</span> Express yourself and hit share!
|
||||
<img src="i/panel/step-03.png">
|
||||
</div>
|
||||
</div>
|
||||
<div id="info36" class="row">
|
||||
<div class="c3">
|
||||
<strong>*Firefox 3.6 support</strong>: F1 uses some advanced technology
|
||||
and UI capabilities that are not possible in Firefox 3.6 and earlier.
|
||||
If you installed the previous version of F1 that works with Firefox 3.6,
|
||||
it will continue to work while Firefox 4 is in beta. Once Firefox 4 is
|
||||
released, the older 3.6 compatible extension will be phased out.
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer" class="row">
|
||||
<div class="c3">
|
||||
<a href="http://mozillamessaging.com">Mozilla Messaging 2011</a> | <a href="/0.3.4/service/privacy.html">Privacy Policy</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<iframe id="installFrame" src="/0.3.4/blank.html"></iframe>
|
||||
|
||||
<!-- START OF SmartSource Data Collector TAG -->
|
||||
<!-- Copyright (c) 1996-2011 WebTrends Inc. All rights reserved. -->
|
||||
<!-- Version: 9.3.0 -->
|
||||
<!-- Tag Builder Version: 3.1 -->
|
||||
<!-- Created: 3/15/2011 5:10:56 PM -->
|
||||
<script src="/0.3.4/scripts/webtrends.js" type="text/javascript"></script>
|
||||
<!-- ----------------------------------------------------------------------------------- -->
|
||||
<!-- Warning: The two script blocks below must remain inline. Moving them to an external -->
|
||||
<!-- JavaScript include file can cause serious problems with cross-domain tracking. -->
|
||||
<!-- ----------------------------------------------------------------------------------- -->
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var _tag=new WebTrends();
|
||||
_tag.dcsGetId();
|
||||
//]]>
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
_tag.dcsCustom=function(){
|
||||
// Add custom parameters here.
|
||||
//_tag.DCSext.param_name=param_value;
|
||||
}
|
||||
_tag.dcsCollect();
|
||||
//]]>
|
||||
</script>
|
||||
<noscript>
|
||||
<div><img alt="DCSIMG" id="DCSIMG" width="1" height="1" src="http://statse.webtrendslive.com/dcsjd66bq10000k73ngwoin8k_7d1l/njs.gif?dcsuri=/nojavascript&WT.js=No&WT.tv=9.3.0&WT.dcssip=www.mozillamessaging.com"/></div>
|
||||
</noscript>
|
||||
<!-- END OF SmartSource Data Collector TAG -->
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,32 @@
|
|||
define("hashDispatch",[],function(){return function(b){function g(){var i=location.href.split("#")[1]||"_default",l,f;f=i.indexOf(":");if(f!==-1){l=i.substring(f+1,i.length);i=i.substring(0,f)}if(i in b)b[i](l);else b._catchAll&&b._catchAll(i,l)}g();window.addEventListener("hashchange",g,false)}});
|
||||
(function(b){var g,i,l,f,x,m,D,o,A,B,r=0,e={},p=[],q=0,d={},n=[],F=null,u=new Image,J=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\.]\.(swf)\s*$/i,K,L=1,z=0,v="",s,k,j=false,C=b.extend(b("<div/>")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){i.hide();u.onerror=u.onload=null;F&&F.abort();g.empty()},O=function(){if(false===e.onError(p,r,e)){i.hide();j=false}else{e.titleShow=false;e.width="auto";e.height="auto";g.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');
|
||||
E()}},I=function(){var a=p[r],c,h,t,G,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));w=e.onStart(p,r,e);if(w===false)j=false;else{if(typeof w=="object")e=b.extend(e,w);t=e.title||(a.nodeName?b(a).attr("title"):a.title)||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(t===""&&e.orig&&e.titleFromAlt)t=e.orig.attr("alt");c=e.href||(a.nodeName?b(a).attr("href"):a.href)||null;if(/^(?:javascript)/i.test(c)||
|
||||
c=="#")c=null;if(e.type){h=e.type;if(!c)c=e.content}else if(e.content)h="html";else if(c)h=c.match(J)?"image":c.match(W)?"swf":b(a).hasClass("iframe")?"iframe":c.indexOf("#")===0?"inline":"ajax";if(h){if(h=="inline"){a=c.substr(c.indexOf("#"));h=b(a).length>0?"inline":"ajax"}e.type=h;e.href=c;e.title=t;if(e.autoDimensions)if(e.type=="html"||e.type=="inline"||e.type=="ajax"){e.width="auto";e.height="auto"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=
|
||||
false;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);g.css("padding",e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(m.children())});switch(h){case "html":g.html(e.content);E();break;case "inline":if(b(a).parent().is("#fancybox-content")===true){j=false;return}b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(m.children())}).bind("fancybox-cancel",
|
||||
function(){b(this).replaceWith(g.children())});b(a).appendTo(g);E();break;case "image":j=false;b.fancybox.showActivity();u=new Image;u.onerror=function(){O()};u.onload=function(){j=true;u.onerror=u.onload=null;X()};u.src=c;break;case "swf":e.scrolling="no";G='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+c+'"></param>';P="";b.each(e.swf,function(y,H){G+='<param name="'+y+'" value="'+H+'"></param>';P+=" "+y+'="'+
|
||||
H+'"'});G+='<embed src="'+c+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+P+"></embed></object>";g.html(G);E();break;case "ajax":j=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;F=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(y){y.status>0&&O()},success:function(y,H,Q){if((typeof Q=="object"?Q:F).status==200){if(typeof e.ajax.win=="function"){w=e.ajax.win(c,y,H,Q);if(w===false){i.hide();return}else if(typeof w=="string"||typeof w==
|
||||
"object")y=w}g.html(y);E()}}}));break;case "iframe":R();break}}else O()}},E=function(){var a=e.width,c=e.height;a=a.toString().indexOf("%")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+"px":a=="auto"?"auto":a+"px";c=c.toString().indexOf("%")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+"px":c=="auto"?"auto":c+"px";g.wrapInner('<div style="width:'+a+";height:"+c+";overflow: "+(e.scrolling=="auto"?"auto":e.scrolling=="yes"?"scroll":"hidden")+';position:relative;"></div>');
|
||||
e.width=g.width();e.height=g.height();R()},X=function(){e.width=u.width;e.height=u.height;b("<img />").attr({id:"fancybox-img",src:u.src,alt:e.title}).appendTo(g);R()},R=function(){var a,c;i.hide();if(f.is(":visible")&&false===d.onCleanup(n,q,d)){b.event.trigger("fancybox-cancel");j=false}else{j=true;b(m.add(l)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");f.is(":visible")&&d.titlePosition!=="outside"&&f.css("height",f.height());n=p;q=r;d=e;if(d.overlayShow){l.css({"background-color":d.overlayColor,
|
||||
opacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?"pointer":"auto",height:b(document).height()});if(!l.is(":visible")){M&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});l.show()}}else l.hide();k=Y();Z();if(f.is(":visible")){b(D.add(A).add(B)).hide();a=f.position();s={top:a.top,left:a.left,width:f.width(),height:f.height()};c=s.width==k.width&&s.height==
|
||||
k.height;m.fadeTo(d.changeFade,0.3,function(){var h=function(){m.html(g.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");m.empty().removeAttr("filter").css({"border-width":d.padding,width:k.width-d.padding*2,height:e.autoDimensions?"auto":k.height-z-d.padding*2});if(c)h();else{C.prop=0;b(C).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:h})}})}else{f.removeAttr("style");m.css("border-width",d.padding);if(d.transitionIn=="elastic"){s=V();m.html(g.contents());
|
||||
f.show();if(d.opacity)k.opacity=0;C.prop=0;b(C).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&z>0&&o.show();m.css({width:k.width-d.padding*2,height:e.autoDimensions?"auto":k.height-z-d.padding*2}).html(g.contents());f.css(k).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},$=function(a){if(a&&a.length){if(d.titlePosition=="float")return'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+
|
||||
a+'</td><td id="fancybox-title-float-right"></td></tr></table>';return'<div id="fancybox-title-'+d.titlePosition+'">'+a+"</div>"}return false},Z=function(){v=d.title||"";z=0;o.empty().removeAttr("style").removeClass();if(d.titleShow!==false){v=b.isFunction(d.titleFormat)?d.titleFormat(v,n,q,d):$(v);if(!(!v||v==="")){o.addClass("fancybox-title-"+d.titlePosition).html(v).appendTo("body").show();switch(d.titlePosition){case "inside":o.css({width:k.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding});
|
||||
z=o.outerHeight(true);o.appendTo(x);k.height+=z;break;case "over":o.css({marginLeft:d.padding,width:k.width-d.padding*2,bottom:d.padding}).appendTo(x);break;case "float":o.css("left",parseInt((o.width()-k.width-40)/2,10)*-1).appendTo(f);break;default:o.css({width:k.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f);break}}}o.hide()},aa=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();
|
||||
b.fancybox.close()}else if((a.keyCode==37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&n.length>1||q!==0)A.show();if(d.cyclic&&n.length>1||q!=n.length-1)B.show()}else{A.hide();B.hide()}},S=function(){if(!b.support.opacity){m.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&
|
||||
m.css("height","auto");f.css("height","auto");v&&v.length&&o.show();d.showCloseButton&&D.show();aa();d.hideOnContentClick&&m.bind("click",b.fancybox.close);d.hideOnOverlayClick&&l.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" '+(b.browser.msie?'allowtransparency="true""':"")+' scrolling="'+
|
||||
e.scrolling+'" src="'+d.href+'"></iframe>').appendTo(m);f.show();j=false;b.fancybox.center();d.onComplete(n,q,d);ba()},ba=function(){var a,c;if(n.length-1>q){a=n[q+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(q>0){a=n[q-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(s.width+(k.width-s.width)*a,10),height:parseInt(s.height+(k.height-s.height)*a,10),top:parseInt(s.top+(k.top-s.top)*a,10),left:parseInt(s.left+(k.left-
|
||||
s.left)*a,10)};if(typeof k.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c);m.css({width:c.width-d.padding*2,height:c.height-z*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},Y=function(){var a=U(),c={},h=d.autoScale,t=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+t;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*
|
||||
parseFloat(d.height)/100,10):d.height+t;if(h&&(c.width>a[0]||c.height>a[1]))if(e.type=="image"||e.type=="swf"){h=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-t)/h+t,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-t)*h+t,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},ca=function(a){var c=a.offset();
|
||||
c.top+=parseInt(a.css("paddingTop"),10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){a=ca(a);c={width:a.width+d.padding*2,height:a.height+d.padding*2,top:a.top-d.padding-20,left:a.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+
|
||||
a[0]*0.5,10)}}return c},da=function(){if(i.is(":visible")){b("div",i).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)};b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!j){j=true;b(this).blur();p=[];r=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")p.push(this);else{p=b("a[rel="+c+"], area[rel="+c+"]");r=p.index(this)}I()}});return this};
|
||||
b.fancybox=function(a,c){if(!j){j=true;c=typeof c!=="undefined"?c:{};p=[];r=parseInt(c.index,10)||0;if(b.isArray(a)){for(var h=0,t=a.length;h<t;h++)if(typeof a[h]=="object")b(a[h]).data("fancybox",b.extend({},c,a[h]));else a[h]=b({}).data("fancybox",b.extend({content:a[h]},c));p=jQuery.merge(p,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},c,a));else a=b({}).data("fancybox",b.extend({content:a},c));p.push(a)}if(r>p.length||r<0)r=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);
|
||||
i.show();K=setInterval(da,66)};b.fancybox.hideActivity=function(){i.hide()};b.fancybox.next=function(){return b.fancybox.pos(q+1)};b.fancybox.prev=function(){return b.fancybox.pos(q-1)};b.fancybox.pos=function(a){if(!j){a=parseInt(a);p=n;if(a>-1&&a<n.length){r=a;I()}else if(d.cyclic&&n.length>1){r=a>=n.length?0:n.length-1;I()}}};b.fancybox.cancel=function(){if(!j){j=true;b.event.trigger("fancybox-cancel");N();e.onCancel(p,r,e);j=false}};b.fancybox.close=function(){function a(){l.fadeOut("fast");o.empty().hide();
|
||||
f.hide();b.event.trigger("fancybox-cleanup");m.empty();d.onClosed(n,q,d);n=e=[];q=r=0;d=e={};j=false}if(!(j||f.is(":hidden"))){j=true;if(d&&false===d.onCleanup(n,q,d))j=false;else{N();b(D.add(A).add(B)).hide();b(m.add(l)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");m.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&o.empty();f.stop();if(d.transitionOut=="elastic"){s=V();var c=
|
||||
f.position();k={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)k.opacity=1;o.empty().hide();C.prop=1;b(C).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){l.is(":visible")&&l.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,h;if(!j){h=a===true?1:0;c=U();!h&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-
|
||||
20,c[3]+(c[1]-m.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-m.width()-40)*0.5-d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(g=b('<div id="fancybox-tmp"></div>'),i=b('<div id="fancybox-loading"><div></div></div>'),l=b('<div id="fancybox-overlay"></div>'),f=b('<div id="fancybox-wrap"></div>'));x=b('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(f);
|
||||
x.append(m=b('<div id="fancybox-content"></div>'),D=b('<a id="fancybox-close"></a>'),o=b('<div id="fancybox-title"></div>'),A=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),B=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));D.click(b.fancybox.close);i.click(b.fancybox.cancel);A.click(function(a){a.preventDefault();b.fancybox.prev()});B.click(function(a){a.preventDefault();b.fancybox.next()});
|
||||
b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(j)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){i.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(x)}}};
|
||||
b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",
|
||||
easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery);define("jquery.fancybox-1.3.4",function(){});
|
||||
define("index",["require","jquery","hashDispatch","jquery.fancybox-1.3.4"],function(b,g){g(function(){var i=!!navigator.buildID,l=i&&navigator.userAgent.match(/Firefox\/([^\s]+)/);if(i&&l){l=parseFloat(l[1]);i=l>3.99}if(!i){g("#downloadFF4").hide();g("#no36").show();g("#info36").show();g("#firefox").show()}g(".fancybox").fancybox({type:"iframe",href:"http://player.vimeo.com/video/21374067?title=0&byline=0&portrait=0&autoplay=true",width:700,height:468,autoScale:false,autoDimensions:false});
|
||||
g("body").delegate("#firefox","click",function(){location="http://www.mozilla.com/en-US/firefox/beta/"}).delegate(".downloadXpi","click",function(f){var x=location.href;location=x.indexOf("staging")!==-1||x.indexOf("linkdrop")!==-1?"/ffshare.xpi":"https://addons.mozilla.org/services/install.php?addon_id=252539&addon_name=F1%20by%20Mozilla%20Labs&src=external-f1home";f.preventDefault()})})});
|
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
* FancyBox - jQuery Plugin
|
||||
* Simple and fancy lightbox alternative
|
||||
*
|
||||
* Examples and documentation at: http://fancybox.net
|
||||
*
|
||||
* Copyright (c) 2008 - 2010 Janis Skarnelis
|
||||
* That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
|
||||
*
|
||||
* Version: 1.3.4 (11/11/2010)
|
||||
* Requires: jQuery v1.3+
|
||||
*
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
#fancybox-loading {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-top: -20px;
|
||||
margin-left: -20px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
z-index: 1104;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-loading div {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 40px;
|
||||
height: 480px;
|
||||
background-image: url('i/fancybox/fancybox.png');
|
||||
}
|
||||
|
||||
#fancybox-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 1100;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-tmp {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
overflow: auto;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-wrap {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: 20px 10px 10px 20px;
|
||||
z-index: 1101;
|
||||
outline: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-outer {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#fancybox-content {
|
||||
width: 0;
|
||||
height: 0;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
z-index: 1102;
|
||||
border: 0px solid #fff;
|
||||
}
|
||||
|
||||
#fancybox-hide-sel-frame {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: transparent;
|
||||
z-index: 1101;
|
||||
}
|
||||
|
||||
#fancybox-close {
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
right: -25px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background: transparent url('i/fancybox/fancybox.png') -40px 0px;
|
||||
cursor: pointer;
|
||||
z-index: 1103;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-error {
|
||||
color: #444;
|
||||
font: normal 12px/20px Arial;
|
||||
padding: 14px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#fancybox-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
line-height: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#fancybox-frame {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#fancybox-left, #fancybox-right {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
height: 100%;
|
||||
width: 35%;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
background: transparent url('i/fancybox/blank.gif');
|
||||
z-index: 1102;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fancybox-left {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
#fancybox-right {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
#fancybox-left-ico, #fancybox-right-ico {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: -9999px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-top: -15px;
|
||||
cursor: pointer;
|
||||
z-index: 1102;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#fancybox-left-ico {
|
||||
background-image: url('i/fancybox/fancybox.png');
|
||||
background-position: -40px -30px;
|
||||
}
|
||||
|
||||
#fancybox-right-ico {
|
||||
background-image: url('i/fancybox/fancybox.png');
|
||||
background-position: -40px -60px;
|
||||
}
|
||||
|
||||
#fancybox-left:hover, #fancybox-right:hover {
|
||||
visibility: visible; /* IE6 */
|
||||
}
|
||||
|
||||
#fancybox-left:hover span {
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
#fancybox-right:hover span {
|
||||
left: auto;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.fancybox-bg {
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
#fancybox-bg-n {
|
||||
top: -20px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-image: url('i/fancybox/fancybox-x.png');
|
||||
}
|
||||
|
||||
#fancybox-bg-ne {
|
||||
top: -20px;
|
||||
right: -20px;
|
||||
background-image: url('i/fancybox/fancybox.png');
|
||||
background-position: -40px -162px;
|
||||
}
|
||||
|
||||
#fancybox-bg-e {
|
||||
top: 0;
|
||||
right: -20px;
|
||||
height: 100%;
|
||||
background-image: url('i/fancybox/fancybox-y.png');
|
||||
background-position: -20px 0px;
|
||||
}
|
||||
|
||||
#fancybox-bg-se {
|
||||
bottom: -20px;
|
||||
right: -20px;
|
||||
background-image: url('i/fancybox/fancybox.png');
|
||||
background-position: -40px -182px;
|
||||
}
|
||||
|
||||
#fancybox-bg-s {
|
||||
bottom: -20px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-image: url('i/fancybox/fancybox-x.png');
|
||||
background-position: 0px -20px;
|
||||
}
|
||||
|
||||
#fancybox-bg-sw {
|
||||
bottom: -20px;
|
||||
left: -20px;
|
||||
background-image: url('i/fancybox/fancybox.png');
|
||||
background-position: -40px -142px;
|
||||
}
|
||||
|
||||
#fancybox-bg-w {
|
||||
top: 0;
|
||||
left: -20px;
|
||||
height: 100%;
|
||||
background-image: url('i/fancybox/fancybox-y.png');
|
||||
}
|
||||
|
||||
#fancybox-bg-nw {
|
||||
top: -20px;
|
||||
left: -20px;
|
||||
background-image: url('i/fancybox/fancybox.png');
|
||||
background-position: -40px -122px;
|
||||
}
|
||||
|
||||
#fancybox-title {
|
||||
font-family: Helvetica;
|
||||
font-size: 12px;
|
||||
z-index: 1102;
|
||||
}
|
||||
|
||||
.fancybox-title-inside {
|
||||
padding-bottom: 10px;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.fancybox-title-outside {
|
||||
padding-top: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.fancybox-title-over {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
color: #FFF;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#fancybox-title-over {
|
||||
padding: 10px;
|
||||
background-image: url('i/fancybox/fancy_title_over.png');
|
||||
display: block;
|
||||
}
|
||||
|
||||
.fancybox-title-float {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -20px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
#fancybox-title-float-wrap {
|
||||
border: none;
|
||||
border-collapse: collapse;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#fancybox-title-float-wrap td {
|
||||
border: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#fancybox-title-float-left {
|
||||
padding: 0 0 0 15px;
|
||||
background: url('i/fancybox/fancybox.png') -40px -90px no-repeat;
|
||||
}
|
||||
|
||||
#fancybox-title-float-main {
|
||||
color: #FFF;
|
||||
line-height: 29px;
|
||||
font-weight: bold;
|
||||
padding: 0 0 3px 0;
|
||||
background: url('i/fancybox/fancybox-x.png') 0px -40px;
|
||||
}
|
||||
|
||||
#fancybox-title-float-right {
|
||||
padding: 0 0 0 15px;
|
||||
background: url('i/fancybox/fancybox.png') -55px -90px no-repeat;
|
||||
}
|
||||
|
||||
/* IE6 */
|
||||
|
||||
.fancybox-ie6 #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_close.png', sizingMethod='scale'); }
|
||||
|
||||
.fancybox-ie6 #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_nav_left.png', sizingMethod='scale'); }
|
||||
.fancybox-ie6 #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_nav_right.png', sizingMethod='scale'); }
|
||||
|
||||
.fancybox-ie6 #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
|
||||
.fancybox-ie6 #fancybox-title-float-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_title_left.png', sizingMethod='scale'); }
|
||||
.fancybox-ie6 #fancybox-title-float-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_title_main.png', sizingMethod='scale'); }
|
||||
.fancybox-ie6 #fancybox-title-float-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_title_right.png', sizingMethod='scale'); }
|
||||
|
||||
.fancybox-ie6 #fancybox-bg-w, .fancybox-ie6 #fancybox-bg-e, .fancybox-ie6 #fancybox-left, .fancybox-ie6 #fancybox-right, #fancybox-hide-sel-frame {
|
||||
height: expression(this.parentNode.clientHeight + "px");
|
||||
}
|
||||
|
||||
#fancybox-loading.fancybox-ie6 {
|
||||
position: absolute; margin-top: 0;
|
||||
top: expression( (-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px');
|
||||
}
|
||||
|
||||
#fancybox-loading.fancybox-ie6 div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_loading.png', sizingMethod='scale'); }
|
||||
|
||||
/* IE6, IE7, IE8 */
|
||||
|
||||
.fancybox-ie .fancybox-bg { background: transparent !important; }
|
||||
|
||||
.fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
|
||||
.fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='i/fancybox/fancy_shadow_nw.png', sizingMethod='scale'); }
|
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Autocomplete test</title>
|
||||
<script src="../scripts/requireplugins-jquery.js"></script>
|
||||
<script src="../scripts/jquery-ui-1.8.7.min.js"></script>
|
||||
<script>
|
||||
var options = {
|
||||
a: [
|
||||
'alpha',
|
||||
'amature'
|
||||
],
|
||||
b: [
|
||||
'bass',
|
||||
'bicycle'
|
||||
]
|
||||
},
|
||||
options2 = [
|
||||
'alpha',
|
||||
'amature',
|
||||
'bass',
|
||||
'bicycle'
|
||||
];
|
||||
|
||||
//HTML5-style autocomplete, does not do want is desired though.
|
||||
$(function () {
|
||||
var ac = $('.ac')[0],
|
||||
dynamic = $('#dynamic')[0];
|
||||
|
||||
$('body').delegate('.ac', 'input', function (evt) {
|
||||
var value = ac.value,
|
||||
args = value.split(','),
|
||||
others = args.slice(0, args.length - 1).join(',') || '',
|
||||
last = args[args.length - 1],
|
||||
list = options[last.charAt(0)],
|
||||
html = '';
|
||||
|
||||
if (list) {
|
||||
list.forEach(function (item) {
|
||||
html += '<option value="' + (others ? others + ',' : '') + item + '">' + (others ? others + ',' : '') + item + '</option>';
|
||||
})
|
||||
dynamic.innerHTML = html;
|
||||
}
|
||||
|
||||
console.log("INPUT: ", evt);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<form>
|
||||
<input class="ac" list="dynamic" name="dynamicAc">
|
||||
<datalist id="dynamic">
|
||||
</datalist>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
После Ширина: | Высота: | Размер: 17 KiB |
После Ширина: | Высота: | Размер: 607 B |
После Ширина: | Высота: | Размер: 302 B |
После Ширина: | Высота: | Размер: 235 B |
|
@ -0,0 +1,581 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-collapse: collapse;
|
||||
position: relative;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
font-style: inherit;
|
||||
font-size: 100%;
|
||||
vertical-align: top;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 11px;
|
||||
font-family: "lucida grande";
|
||||
max-height: 128px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
background-position: bottom center;
|
||||
background-repeat: no-repeat;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid #515151;
|
||||
}
|
||||
|
||||
#twitter, #facebook, #gmail, #settings {
|
||||
/* background-image: -moz-linear-gradient(top, #d0d0d0 0%, #a8a8a8 100%); */
|
||||
background-color: #a7a7a7;
|
||||
/*
|
||||
border-top: 1px solid #515151;
|
||||
-moz-box-shadow: 0 2px 0 -1px #e3e3e3 inset;
|
||||
*/
|
||||
}
|
||||
|
||||
ul.nav {
|
||||
-moz-box-shadow:0 2px 0 -1px #CDCDCD inset;
|
||||
background-color:#A7A7A7;
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
ul.nav .username {
|
||||
font-size: 11px;
|
||||
line-height: 24px;
|
||||
padding: 0 10px;
|
||||
margin: 4px 10px;
|
||||
border-left: 1px dotted #888;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
ul.nav .username img {
|
||||
border: 1px solid #fff;
|
||||
-moz-box-shadow: 0 1px 1px rgba(0,0,0,0.25);
|
||||
width: 23px;
|
||||
height: 23px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
ul.nav .username .userId {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
text-shadow: 1px 1px 0 #bbb;
|
||||
}
|
||||
|
||||
ul.nav .navWrap {
|
||||
width: 960px;
|
||||
/*
|
||||
background-image: url("i/logo.gif");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right center;
|
||||
*/
|
||||
position: relative;
|
||||
left: 50%;
|
||||
margin-left: -480px;
|
||||
}
|
||||
|
||||
ul.nav li {
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
list-style-type: none;
|
||||
margin: 3px 0;
|
||||
font-size: 11px;
|
||||
line-height: 24px;
|
||||
background-image: -moz-linear-gradient(center top , #FDFDFD 0%, #AAAAAA 100%);
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #666;
|
||||
-moz-box-shadow: 0 1px 0 #CDCDCD;
|
||||
}
|
||||
|
||||
ul.nav li:hover {
|
||||
background-color: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected {
|
||||
background-image: -moz-linear-gradient(center top , #bbb 0%, #aaa 100%);
|
||||
-moz-box-shadow: 0 0 3px #666 inset,0 1px 0 #CDCDCD;
|
||||
}
|
||||
|
||||
ul.nav li:first-child {
|
||||
z-index: 1;
|
||||
-moz-border-radius: 3px 0 0 3px;
|
||||
}
|
||||
|
||||
ul.nav li:nth-child(2) {
|
||||
z-index: 2;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
ul.nav li:nth-child(3) {
|
||||
z-index: 1;
|
||||
-moz-border-radius: 0 3px 3px 0;
|
||||
}
|
||||
|
||||
ul.nav li a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul.nav li a.icon {
|
||||
width: 36px;
|
||||
height: 24px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
display: block;
|
||||
}
|
||||
|
||||
ul.nav li a.icon.twitter {
|
||||
background-image: url("../share/i/twitterIcon.png");
|
||||
}
|
||||
|
||||
ul.nav li a.icon.facebook {
|
||||
background-image: url("../share/i/facebookIcon.png");
|
||||
}
|
||||
|
||||
ul.nav li a.icon.gmail {
|
||||
background-image: url("../share/i/gmailIcon.png");
|
||||
}
|
||||
|
||||
ul.nav li a.icon.settings {
|
||||
background-image: url("../share/i/settingsIcon.png");
|
||||
}
|
||||
|
||||
ul.nav li.debug {
|
||||
position: absolute;
|
||||
right: 46px;
|
||||
top: 0;
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ul.nav li.debug span.name {
|
||||
display: block;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
font-weight: normal;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul.nav li.debug a.icon {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
ul.nav li span.name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected span.name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
ul.nav li.settings,
|
||||
ul.nav li.settings.ui-tabs-selected {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
text-align: center;
|
||||
-moz-border-radius: 3px;
|
||||
}
|
||||
|
||||
ul.nav li.settings:hover span.name,
|
||||
ul.nav li.settings.ui-tabs-selected span.name {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ul.nav li.settings span.name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected {
|
||||
|
||||
}
|
||||
|
||||
ul.nav li span.name {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a.icon,
|
||||
ul.nav li.ui-tabs-selected span.name {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ul.nav li span.name {
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected span.name {
|
||||
color: #0a0a0a;
|
||||
}
|
||||
|
||||
ul.nav span.name {
|
||||
display: block;
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected.settings span.name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a.twitter,
|
||||
ul.nav li:hover a.twitter {
|
||||
background-image: url("../share/i/twitterIconColor.png");
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a.facebook,
|
||||
ul.nav li:hover a.facebook {
|
||||
background-image: url("../share/i/facebookIconColor.png");
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a.gmail,
|
||||
ul.nav li:hover a.gmail {
|
||||
background-image: url(".../share/i/gmailIconColor.png");
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a {
|
||||
color: #0a0a0a;
|
||||
}
|
||||
|
||||
div.user {
|
||||
font-size: small;
|
||||
width: 140px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.user.inactive {
|
||||
opacity: 0.5;
|
||||
background: -moz-repeating-linear-gradient(top left -45deg, #aaa, #aaa 5px, #fff 5px, #fff 10px) #aaa no-repeat fixed;
|
||||
-moz-border-radius: 1%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.user .username {
|
||||
color: #444;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td.image {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
height: 71px;
|
||||
padding: 4px;
|
||||
border: 1px solid #999;
|
||||
margin: 0 5px 0 0;
|
||||
-moz-border-radius: 3px;
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
div.thumb {
|
||||
border: 1px solid #aaa;
|
||||
background-color: #fff;
|
||||
height: 61px;
|
||||
width: 90px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
ul.info {
|
||||
display: inline-block;
|
||||
width: 150px;
|
||||
font-size: 11px;
|
||||
padding: 0 5px 0 10px;
|
||||
}
|
||||
|
||||
.info .description {
|
||||
color: #000;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.thumb .title {
|
||||
color: #3B5998;
|
||||
text-decoration: underline;
|
||||
font-size: small;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.thumb .description {
|
||||
color: #808080;
|
||||
font-size: x-small;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 2px 15px;
|
||||
font-family: "helvetica neue", helvetica, arial, sans-serif;
|
||||
font-size: 11px;
|
||||
line-height:24px;
|
||||
background-image: -moz-linear-gradient(top,#fdfdfd 0%,#aaa 100%);
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #5C5C5C #888 #666;
|
||||
-moz-border-radius: 3px;
|
||||
margin-left: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.share {
|
||||
-moz-border-radius: 0 3px 3px 0;
|
||||
-moz-box-shadow: 0 1px 0 #cdcdcd;
|
||||
border-left: none;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
button:hover, button:active {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
*/
|
||||
|
||||
button:active {
|
||||
-moz-box-shadow: 0 0 0 1px rgba(255,255,255,0.35) inset, 0 0 3px rgba(0,0,0,0.75) inset;
|
||||
}
|
||||
|
||||
textarea, input[type="text"] {
|
||||
-moz-box-shadow: 0 2px 2px -2px #555 inset, 0 1px 0 #cdcdcd;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #5c5c5c #929292 #929292;
|
||||
font-family: "lucida grande"
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
-moz-border-radius: 3px;
|
||||
}
|
||||
|
||||
textarea.message {
|
||||
min-height: 71px;
|
||||
-moz-border-radius: 3px 0 0 3px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
textarea:focus, input[type="text"]:focus {
|
||||
|
||||
}
|
||||
|
||||
.inputs {
|
||||
margin: 0 5px 0 0;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
height: 26px;
|
||||
width: 238px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
input[type="text"]#to {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.entry {
|
||||
padding: 5px 0;
|
||||
width: 960px;
|
||||
left: 50%;
|
||||
margin-left: -480px;
|
||||
position: relative;
|
||||
min-height: 71px;
|
||||
}
|
||||
|
||||
.entry .urlConfirmation {
|
||||
padding: 1px 5px;
|
||||
-moz-border-radius: 10px;
|
||||
background-image: -moz-linear-gradient(top, #fafafa 0%, #e6e6e6 100%);
|
||||
border: 1px solid #bebebe;
|
||||
color: green;
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
bottom: 5px;
|
||||
z-index: 1;
|
||||
color: green;
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.entry .urlConfirmation span {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#settings .entry ul li {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#settings .entry ul li button {
|
||||
margin: 0 10px 0 0;
|
||||
width: 128px;
|
||||
}
|
||||
|
||||
.entry h1 {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
/* START hbox/vbox normalization from http://alex.dojotoolkit.org/2009/08/css-3-progress/ */
|
||||
/* hbox and vbox classes */
|
||||
|
||||
.hbox {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-align: stretch;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: horizontal;
|
||||
-moz-box-align: stretch;
|
||||
|
||||
display: box;
|
||||
box-orient: horizontal;
|
||||
box-align: stretch;
|
||||
}
|
||||
|
||||
.hbox > * {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.vbox {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-align: stretch;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
-moz-box-align: stretch;
|
||||
|
||||
display: box;
|
||||
box-orient: vertical;
|
||||
box-align: stretch;
|
||||
}
|
||||
|
||||
.vbox > * {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
box-flex: 1;
|
||||
}
|
||||
|
||||
.reverse {
|
||||
-webkit-box-direction: reverse;
|
||||
-moz-box-direction: reverse;
|
||||
box-direction: reverse;
|
||||
}
|
||||
|
||||
.boxFlex0 {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
}
|
||||
|
||||
.boxFlex1, .boxFlex {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
box-flex: 1;
|
||||
}
|
||||
|
||||
.boxFlex2 {
|
||||
-webkit-box-flex: 2;
|
||||
-moz-box-flex: 2;
|
||||
box-flex: 2;
|
||||
}
|
||||
|
||||
.boxGroup1 {
|
||||
-webkit-box-flex-group: 1;
|
||||
-moz-box-flex-group: 1;
|
||||
box-flex-group: 1;
|
||||
}
|
||||
|
||||
.boxGroup2 {
|
||||
-webkit-box-flex-group: 2;
|
||||
-moz-box-flex-group: 2;
|
||||
box-flex-group: 2;
|
||||
}
|
||||
|
||||
.start {
|
||||
-webkit-box-pack: start;
|
||||
-moz-box-pack: start;
|
||||
box-pack: start;
|
||||
}
|
||||
|
||||
.end {
|
||||
-webkit-box-pack: end;
|
||||
-moz-box-pack: end;
|
||||
box-pack: end;
|
||||
}
|
||||
|
||||
.center {
|
||||
-webkit-box-pack: center;
|
||||
-moz-box-pack: center;
|
||||
box-pack: center;
|
||||
}
|
||||
/* END hbox/vbox normalization from http://alex.dojotoolkit.org/2009/08/css-3-progress/ */
|
||||
|
||||
/* clearfix */
|
||||
|
||||
.clearfix:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
line-height: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
html[xmlns] .clearfix {
|
||||
display: block;
|
||||
}
|
||||
|
||||
* html .clearfix {
|
||||
height: 1%;
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||
- Version: MPL 1.1
|
||||
-
|
||||
- The contents of this file are subject to the Mozilla Public License Version
|
||||
- 1.1 (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.mozilla.org/MPL/
|
||||
-
|
||||
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
- for the specific language governing rights and limitations under the
|
||||
- License.
|
||||
-
|
||||
- The Original Code is Raindrop.
|
||||
-
|
||||
- The Initial Developer of the Original Code is
|
||||
- Mozilla Messaging, Inc..
|
||||
- Portions created by the Initial Developer are Copyright (C) 2009
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- -->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="nativeShare.css">
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$("#tabs").tabs(/* { fx: { opacity: 'toggle', duration: 0 } } */);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.ui-tabs .ui-tabs-hide { display: none; }
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="tabs" class="tabs-left">
|
||||
|
||||
<ul class="nav clearfix">
|
||||
<div class="navWrap clearfix">
|
||||
<li><a class="icon twitter" title="share on twitter" href="#twitter"><span class="name">Twitter</span></a></li>
|
||||
<li><a class="icon facebook" title="share on facebook" href="#facebook"><span class="name">Facebook</span></a></li>
|
||||
<li><a class="icon gmail" title="share on Gmail" href="#gmail"><span class="name">Gmail</span></a></li>
|
||||
<li class="settings"><a class="icon settings" href="#settings"><span class="name"><img src="i/settings.png"></span></a></li>
|
||||
<div class="username"><img src="i/bryanAvatar.jpg"><span class="userId">@clarkbw</span></div>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
<div id="twitter">
|
||||
<div class="entry hbox">
|
||||
<div class="boxFlex">
|
||||
<textarea class="message"></textarea>
|
||||
<span class="urlConfirmation"><span>re-insert link</span></span>
|
||||
</div>
|
||||
<button class="share">share</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="facebook">
|
||||
<div class="entry hbox">
|
||||
<div class="thumbnail">
|
||||
<div class="thumb"></div>
|
||||
<ul class="info">
|
||||
<li class="title">Title</li>
|
||||
<li class="description">Description</li>
|
||||
</ul>
|
||||
</div>
|
||||
<textarea class="message boxFlex"></textarea>
|
||||
<button class="share">share</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="gmail">
|
||||
<div class="entry hbox">
|
||||
<div class="inputs">
|
||||
<input id="to" type="text" value="to"/>
|
||||
<input id="subject" type="text" value="subject"/>
|
||||
</div>
|
||||
<div class="boxFlex">
|
||||
<textarea class="message"></textarea>
|
||||
<span class="urlConfirmation"><span>re-insert link</span></span>
|
||||
</div>
|
||||
<button class="share">share</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="settings">
|
||||
<div class="entry">
|
||||
<h1>Settings</h1>
|
||||
<ul>
|
||||
<li><button>Add Twitter</button></li>
|
||||
<li><button>Add Facebook</button></li>
|
||||
<li><button>Add GMail</button></li>
|
||||
<li><button>Add FFFFound</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,630 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-collapse: collapse;
|
||||
position: relative;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
font-style: inherit;
|
||||
font-size: 100%;
|
||||
vertical-align: top;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 11px;
|
||||
font-family: "lucida grande";
|
||||
max-height: 128px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
background-position: bottom center;
|
||||
background-repeat: no-repeat;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
color: #00A0FF;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #777;
|
||||
background-color: #ddd;
|
||||
-moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
|
||||
background-image:-moz-linear-gradient(center top , #EEEEEE 0%, #DDDDDD 100%);
|
||||
}
|
||||
|
||||
#twitter, #facebook, #gmail, #settings {
|
||||
}
|
||||
|
||||
ul.nav {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
ul.nav .username {
|
||||
font-size: 11px;
|
||||
line-height: 24px;
|
||||
padding: 0 10px;
|
||||
margin: 4px 10px;
|
||||
border-left: 1px dotted #888;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
ul.nav .username img {
|
||||
border: 1px solid #fff;
|
||||
-moz-box-shadow: 0 1px 1px rgba(0,0,0,0.25);
|
||||
width: 23px;
|
||||
height: 23px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
ul.nav .username .userId {
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
/* text-shadow: 1px 1px 0 #bbb; */
|
||||
}
|
||||
|
||||
ul.nav .navWrap {
|
||||
position: relative;
|
||||
/*
|
||||
width: 960px;
|
||||
left: 50%;
|
||||
margin-left: -480px;
|
||||
*/
|
||||
}
|
||||
|
||||
ul.nav li {
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
list-style-type: none;
|
||||
margin: 3px 0;
|
||||
font-size: 11px;
|
||||
line-height: 24px;
|
||||
background-image: -moz-linear-gradient(center top , #fafafa 0%, #ddd 100%);
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #888;
|
||||
-moz-box-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
ul.nav li:hover {
|
||||
background-color: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected {
|
||||
-moz-box-shadow:0 0 1px #666666 inset, 0 1px 0 #FFFFFF;
|
||||
background-image:-moz-linear-gradient(center top , #EEEEEE 0%, #CCCCCC 100%);
|
||||
}
|
||||
|
||||
ul.nav li:first-child {
|
||||
z-index: 1;
|
||||
-moz-border-radius: 2px 0 0 2px;
|
||||
}
|
||||
|
||||
ul.nav li:nth-child(2) {
|
||||
z-index: 2;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
ul.nav li:nth-child(3) {
|
||||
z-index: 1;
|
||||
-moz-border-radius: 0 2px 2px 0;
|
||||
}
|
||||
|
||||
ul.nav li a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul.nav li a.icon {
|
||||
width: 36px;
|
||||
height: 24px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
display: block;
|
||||
}
|
||||
|
||||
ul.nav li a.icon.twitter {
|
||||
background-image: url("../share/i/twitterIcon.png");
|
||||
}
|
||||
|
||||
ul.nav li a.icon.facebook {
|
||||
background-image: url("../share/i/facebookIcon.png");
|
||||
}
|
||||
|
||||
ul.nav li a.icon.gmail {
|
||||
background-image: url("../share/i/gmailIcon.png");
|
||||
}
|
||||
|
||||
ul.nav li a.icon.settings {
|
||||
background-image: url("../share/i/settingsIcon.png");
|
||||
}
|
||||
|
||||
ul.nav li.debug {
|
||||
position: absolute;
|
||||
right: 46px;
|
||||
top: 0;
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ul.nav li.debug span.name {
|
||||
display: block;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
font-weight: normal;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul.nav li.debug a.icon {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
ul.nav li span.name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected span.name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
ul.nav li.settings,
|
||||
ul.nav li.settings.ui-tabs-selected {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
text-align: center;
|
||||
-moz-border-radius: 2px;
|
||||
}
|
||||
|
||||
ul.nav li.settings:hover span.name,
|
||||
ul.nav li.settings.ui-tabs-selected span.name {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ul.nav li.settings span.name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.nav li span.name {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a.icon,
|
||||
ul.nav li.ui-tabs-selected span.name {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ul.nav li span.name {
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected span.name {
|
||||
color: #0a0a0a;
|
||||
}
|
||||
|
||||
ul.nav span.name {
|
||||
display: block;
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected.settings span.name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a.twitter,
|
||||
ul.nav li:hover a.twitter {
|
||||
background-image: url("../share/i/twitterIconColor.png");
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a.facebook,
|
||||
ul.nav li:hover a.facebook {
|
||||
background-image: url("../share/i/facebookIconColor.png");
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a.gmail,
|
||||
ul.nav li:hover a.gmail {
|
||||
background-image: url("../share/i/gmailIconColor.png");
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a {
|
||||
color: #0a0a0a;
|
||||
}
|
||||
|
||||
div.user {
|
||||
font-size: small;
|
||||
width: 140px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.user.inactive {
|
||||
opacity: 0.5;
|
||||
background: -moz-repeating-linear-gradient(top left -45deg, #aaa, #aaa 5px, #fff 5px, #fff 10px) #aaa no-repeat fixed;
|
||||
-moz-border-radius: 1%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.user .username {
|
||||
color: #444;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td.image {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
height: 71px;
|
||||
padding: 4px;
|
||||
border: 1px solid #bbb;
|
||||
margin: 0 5px 0 0;
|
||||
-moz-border-radius: 2px;
|
||||
background-image: -moz-linear-gradient(center top , #EEEEEE 0%, #DDDDDD 100%);
|
||||
}
|
||||
|
||||
div.thumb {
|
||||
border: 1px solid #aaa;
|
||||
background-color: #fff;
|
||||
height: 61px;
|
||||
width: 90px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
ul.info {
|
||||
display: inline-block;
|
||||
width: 150px;
|
||||
font-size: 11px;
|
||||
padding: 0 5px 0 10px;
|
||||
}
|
||||
|
||||
.info .description {
|
||||
color: #444;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.thumb .title {
|
||||
color: #3B5998;
|
||||
text-decoration: underline;
|
||||
font-size: small;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.thumb .description {
|
||||
color: #808080;
|
||||
font-size: x-small;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 2px 15px;
|
||||
background-image: -moz-linear-gradient(center top , #FAFAFA 0%, #DDDDDD 100%);
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #888;
|
||||
-moz-border-radius: 2px;
|
||||
margin-left: 5px;
|
||||
cursor: pointer;
|
||||
-moz-box-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
button.share {
|
||||
-moz-border-radius: 0 2px 2px 0;
|
||||
border-left: none;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
button:active {
|
||||
background-image: -moz-linear-gradient(center top , #EEEEEE 0%, #CCCCCC 100%);
|
||||
-moz-box-shadow:0 0 1px #666666 inset, 0 1px 0 #FFFFFF;
|
||||
}
|
||||
|
||||
textarea, input[type="text"] {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #888;
|
||||
font-family: "lucida grande"
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
-moz-border-radius: 2px;
|
||||
-moz-box-shadow:0 3px 3px -3px rgba(0, 0, 0, 0.25) inset, 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
textarea.message {
|
||||
min-height: 71px;
|
||||
-moz-border-radius: 2px 0 0 2px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
textarea:focus, input[type="text"]:focus {
|
||||
}
|
||||
|
||||
.inputs {
|
||||
margin: 0 5px 0 0;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
height: 26px;
|
||||
width: 238px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
input[type="text"]#to {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.entry {
|
||||
padding: 5px 10px;
|
||||
width: 100%;
|
||||
/*
|
||||
width: 960px;
|
||||
left: 50%;
|
||||
margin-left: -480px;
|
||||
*/
|
||||
position: relative;
|
||||
min-height: 71px;
|
||||
}
|
||||
|
||||
.entry .urlConfirmation {
|
||||
padding: 1px 5px;
|
||||
-moz-border-radius: 10px;
|
||||
background-image: -moz-linear-gradient(top, #fafafa 0%, #e6e6e6 100%);
|
||||
border: 1px solid #bebebe;
|
||||
color: green;
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
bottom: 5px;
|
||||
z-index: 1;
|
||||
color: green;
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.entry .urlConfirmation span {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#settings .entry ul {
|
||||
min-width: 660px;
|
||||
}
|
||||
|
||||
#settings .entry ul li {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
width: 220px;
|
||||
min-height: 71px;
|
||||
}
|
||||
|
||||
#settings .entry ul li:nth-child(1) {
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
|
||||
#settings .entry ul li:nth-child(2) {
|
||||
padding: 0 10px 0;
|
||||
}
|
||||
|
||||
#settings .entry ul li:nth-child(3) {
|
||||
padding: 0 0 0 10px;
|
||||
}
|
||||
|
||||
#settings .entry ul li button {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
#settings .entry ul li h1 {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.entry h1 {
|
||||
font-weight: bold;
|
||||
margin: 0 0 5px 0;
|
||||
color: #0a0a0a;
|
||||
padding: 5px 0 0 0;
|
||||
/* border-top: 1px dotted #888; */
|
||||
}
|
||||
|
||||
.entry h1 a {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.entry h1 img {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
#settings .entry .settings {
|
||||
width: 253px;
|
||||
margin: 0 0 0 10px;
|
||||
padding: 0 0 0 10px;
|
||||
border-left: 1px dotted #888;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
#settings .entry .success {
|
||||
width: 100%;
|
||||
line-height: 24px;
|
||||
color: #54B851;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#settings .entry .success span.check {
|
||||
width: 24px;
|
||||
background-color: #54B851;
|
||||
color: #fff;
|
||||
-moz-border-radius: 12px;
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* START hbox/vbox normalization from http://alex.dojotoolkit.org/2009/08/css-3-progress/ */
|
||||
/* hbox and vbox classes */
|
||||
|
||||
.hbox {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-align: stretch;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: horizontal;
|
||||
-moz-box-align: stretch;
|
||||
|
||||
display: box;
|
||||
box-orient: horizontal;
|
||||
box-align: stretch;
|
||||
}
|
||||
|
||||
.hbox > * {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.vbox {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-align: stretch;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
-moz-box-align: stretch;
|
||||
|
||||
display: box;
|
||||
box-orient: vertical;
|
||||
box-align: stretch;
|
||||
}
|
||||
|
||||
.vbox > * {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
box-flex: 1;
|
||||
}
|
||||
|
||||
.reverse {
|
||||
-webkit-box-direction: reverse;
|
||||
-moz-box-direction: reverse;
|
||||
box-direction: reverse;
|
||||
}
|
||||
|
||||
.boxFlex0 {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
}
|
||||
|
||||
.boxFlex1, .boxFlex {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
box-flex: 1;
|
||||
}
|
||||
|
||||
.boxFlex2 {
|
||||
-webkit-box-flex: 2;
|
||||
-moz-box-flex: 2;
|
||||
box-flex: 2;
|
||||
}
|
||||
|
||||
.boxGroup1 {
|
||||
-webkit-box-flex-group: 1;
|
||||
-moz-box-flex-group: 1;
|
||||
box-flex-group: 1;
|
||||
}
|
||||
|
||||
.boxGroup2 {
|
||||
-webkit-box-flex-group: 2;
|
||||
-moz-box-flex-group: 2;
|
||||
box-flex-group: 2;
|
||||
}
|
||||
|
||||
.start {
|
||||
-webkit-box-pack: start;
|
||||
-moz-box-pack: start;
|
||||
box-pack: start;
|
||||
}
|
||||
|
||||
.end {
|
||||
-webkit-box-pack: end;
|
||||
-moz-box-pack: end;
|
||||
box-pack: end;
|
||||
}
|
||||
|
||||
.center {
|
||||
-webkit-box-pack: center;
|
||||
-moz-box-pack: center;
|
||||
box-pack: center;
|
||||
}
|
||||
/* END hbox/vbox normalization from http://alex.dojotoolkit.org/2009/08/css-3-progress/ */
|
||||
|
||||
/* clearfix */
|
||||
|
||||
.clearfix:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
line-height: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
html[xmlns] .clearfix {
|
||||
display: block;
|
||||
}
|
||||
|
||||
* html .clearfix {
|
||||
height: 1%;
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||
- Version: MPL 1.1
|
||||
-
|
||||
- The contents of this file are subject to the Mozilla Public License Version
|
||||
- 1.1 (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.mozilla.org/MPL/
|
||||
-
|
||||
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
- for the specific language governing rights and limitations under the
|
||||
- License.
|
||||
-
|
||||
- The Original Code is Raindrop.
|
||||
-
|
||||
- The Initial Developer of the Original Code is
|
||||
- Mozilla Messaging, Inc..
|
||||
- Portions created by the Initial Developer are Copyright (C) 2009
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- -->
|
||||
<html>
|
||||
<head>
|
||||
<title>F1</title>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="neutralShare.css">
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$("#tabs").tabs({ fx: { opacity: 'toggle', duration: 200 } });
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
.ui-tabs .ui-tabs-hide { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="tabs" class="tabs-left">
|
||||
|
||||
<ul class="nav clearfix">
|
||||
<div class="navWrap clearfix">
|
||||
<li><a class="icon twitter" title="share on twitter" href="#twitter"><span class="name">Twitter</span></a></li>
|
||||
<li><a class="icon facebook" title="share on facebook" href="#facebook"><span class="name">Facebook</span></a></li>
|
||||
<li><a class="icon gmail" title="share on Gmail" href="#gmail"><span class="name">Gmail</span></a></li>
|
||||
<li class="settings"><a class="icon settings" href="#settings"><span class="name"><img src="i/settings.png"></span></a></li>
|
||||
<div class="username"><img src="i/bryanAvatar.jpg"><span class="userId">@clarkbw</span></div>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
<div id="twitter">
|
||||
<div class="entry hbox">
|
||||
<div class="boxFlex">
|
||||
<textarea class="message"></textarea>
|
||||
<span class="urlConfirmation"><span>re-insert link</span></span>
|
||||
</div>
|
||||
<button class="share">share</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="facebook">
|
||||
<div class="entry hbox">
|
||||
<div class="thumbnail">
|
||||
<div class="thumb"></div>
|
||||
<ul class="info">
|
||||
<li class="title">Title</li>
|
||||
<li class="description">Description</li>
|
||||
</ul>
|
||||
</div>
|
||||
<textarea class="message boxFlex"></textarea>
|
||||
<button class="share">share</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="gmail">
|
||||
<div class="entry hbox">
|
||||
<div class="inputs">
|
||||
<input id="to" type="text" value="to"/>
|
||||
<input id="subject" type="text" value="subject"/>
|
||||
</div>
|
||||
<div class="boxFlex">
|
||||
<textarea class="message"></textarea>
|
||||
<span class="urlConfirmation"><span>re-insert link</span></span>
|
||||
</div>
|
||||
<button class="share">share</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="settings">
|
||||
<div class="entry hbox">
|
||||
<ul class="boxFlex">
|
||||
<li>
|
||||
<h1><img src="../share/i/twitterIcon.png"> Twitter</h1>
|
||||
<button>Add Twitter</button>
|
||||
</li>
|
||||
<li>
|
||||
<h1><img src="../share/i/facebookIcon.png"> Facebook</h1>
|
||||
<button>Add Facebook</button>
|
||||
</li>
|
||||
<li>
|
||||
<h1><img src="../share/i/gmailIcon.png"> Gmail - <a href="#">manage</a> | <a href="#">add account</a></h1>
|
||||
<div class="success">
|
||||
<span title="gmail is properly configured!" class="check">✔</span> 3 accounts configured
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="settings">
|
||||
<h1>Advanced settings</h1>
|
||||
Don't see what you need? Try the <a href="#">account manager</a> to get into the nitty gritty.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,568 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-collapse: collapse;
|
||||
position: relative;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
font-style: inherit;
|
||||
font-size: 100%;
|
||||
vertical-align: top;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 14px;
|
||||
font-family: "helvetica neue", helvetica, arial, sans-serif;
|
||||
max-height: 128px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
background-position: bottom center;
|
||||
background-repeat: no-repeat;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
-moz-box-shadow: 0 -5px 2px -4px #DDDDDD inset;
|
||||
height: 125px;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid #ccc;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
ul.nav {
|
||||
background-image: url("i/background.gif");
|
||||
-moz-box-shadow: 0 -2px 3px rgba(0,0,0,0.5) inset;
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
ul.nav .username {
|
||||
height: 24px;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
line-height: 24px;
|
||||
position: absolute;
|
||||
right: 35px;
|
||||
top: 6px;
|
||||
}
|
||||
|
||||
ul.nav .username img {
|
||||
border: 1px solid #fff;
|
||||
width: 23px;
|
||||
height: 23px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
ul.nav .navWrap {
|
||||
width: 962px;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
margin-left:-481px;
|
||||
border-left: 1px solid #222;
|
||||
border-right: 1px solid #222;
|
||||
}
|
||||
|
||||
ul.nav li {
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
list-style-type: none;
|
||||
background-color: #444;
|
||||
margin: 10px 0 0 0px;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
-moz-border-radius: 5px 5px 0 0;
|
||||
-moz-box-shadow: 0 -2px 2px rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
ul.nav li:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
ul.nav li:nth-child(n+2) {
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
ul.nav li:nth-child(1) {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
ul.nav li:nth-child(2) {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
ul.nav li:nth-child(3) {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
ul.nav li a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul.nav li a.icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin: 0 5px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
display: block;
|
||||
}
|
||||
|
||||
ul.nav li a.icon.twitter {
|
||||
background-image: url("../share/i/twitter_w.png");
|
||||
}
|
||||
|
||||
ul.nav li a.icon.facebook {
|
||||
background-image: url("../share/i/facebook_w.png");
|
||||
}
|
||||
|
||||
ul.nav li a.icon.gmail {
|
||||
background-image: url("../share/i/gmail_w.png");
|
||||
}
|
||||
|
||||
ul.nav li a.icon.settings {
|
||||
background-image: url("i/settings.png");
|
||||
background-position: top left;
|
||||
}
|
||||
|
||||
ul.nav li.debug {
|
||||
position: absolute;
|
||||
right: 46px;
|
||||
top: 0;
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ul.nav li.debug span.name {
|
||||
display: block;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
font-weight: normal;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul.nav li.debug a.icon {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
ul.nav li span.name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected span.name {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
ul.nav li.settings,
|
||||
ul.nav li.settings.ui-tabs-selected {
|
||||
position: absolute;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
-moz-box-shadow: none;
|
||||
right: 15px;
|
||||
top: 0;
|
||||
width: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ul.nav li.settings:hover span.name,
|
||||
ul.nav li.settings.ui-tabs-selected span.name {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ul.nav li.settings span.name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected {
|
||||
background-color: #fff;
|
||||
background-image: -moz-linear-gradient(top, #fff 0%, #f2f2f2 100%);
|
||||
width: 128px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
ul.nav li a.icon,
|
||||
ul.nav li span.name {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a.icon,
|
||||
ul.nav li.ui-tabs-selected span.name {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ul.nav li span.name {
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected span.name {
|
||||
color: #0a0a0a;
|
||||
}
|
||||
|
||||
ul.nav span.name {
|
||||
display: block;
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected.settings {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected.settings span.name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a.twitter {
|
||||
background-image: url(".../share/i/twitter_b.png");
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a.facebook {
|
||||
background-image: url("../share/i/facebook_b.png");
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a.gmail {
|
||||
background-image: url("../share/i/gmail_b.png");
|
||||
}
|
||||
|
||||
ul.nav li.ui-tabs-selected a {
|
||||
color: #0a0a0a;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td.user {
|
||||
width: 140px;
|
||||
padding-right: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
td.thumb {
|
||||
width: 220px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
td.message {
|
||||
width: 300px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
td.button {
|
||||
padding: 1px 20px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
div.user {
|
||||
font-size: small;
|
||||
width: 140px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.user.inactive {
|
||||
opacity: 0.5;
|
||||
background: -moz-repeating-linear-gradient(top left -45deg, #aaa, #aaa 5px, #fff 5px, #fff 10px) #aaa no-repeat fixed;
|
||||
-moz-border-radius: 1%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.user .username {
|
||||
color: #444;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td.image {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
div.thumb {
|
||||
border: 1px solid #aaa;
|
||||
background-color: #fff;
|
||||
height: 71px;
|
||||
width: 90px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
ul.info {
|
||||
display: inline-block;
|
||||
width: 150px;
|
||||
font-size: 12px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.info .description {
|
||||
color: #666;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.thumb .title {
|
||||
color: #3B5998;
|
||||
text-decoration: underline;
|
||||
font-size: small;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.thumb .description {
|
||||
color: #808080;
|
||||
font-size: x-small;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 2px 15px;
|
||||
font-family: "helvetica neue", helvetica, arial, sans-serif;
|
||||
font-size: 12px;
|
||||
line-height:24px;
|
||||
background-image: -moz-linear-gradient(top,#fafafa 0%,#e6e6e6 100%);
|
||||
border: 1px solid #bebebe;
|
||||
-moz-box-shadow: 0 0 0 1px #fff inset;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover, button:active {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
button:active {
|
||||
-moz-box-shadow: 0 0 0 1px rgba(255,255,255,0.35) inset, 0 0 3px rgba(0,0,0,0.75) inset;
|
||||
}
|
||||
|
||||
textarea, input[type="text"] {
|
||||
-moz-box-shadow: 0 0 2px #CCCCCC inset;
|
||||
/* background-image: -moz-linear-gradient(center top , #FFFFFF 0%, #F2F2F2 100%); */
|
||||
border: 1px solid #BEBEBE;
|
||||
font-family: "helvetica neue",helvetica,arial,sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
textarea:focus, input[type="text"]:focus {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
.inputs {
|
||||
margin: 0 10px 0 0;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
height: 30px;
|
||||
width: 234px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
input[type="text"]#to {
|
||||
margin-bottom: 11px;
|
||||
}
|
||||
|
||||
.entry {
|
||||
padding: 10px;
|
||||
width: 962px;
|
||||
left: 50%;
|
||||
margin-left: -481px;
|
||||
position: relative;
|
||||
border-left: 1px solid #ccc;
|
||||
border-right: 1px solid #ccc;
|
||||
min-height: 70px;
|
||||
}
|
||||
|
||||
.entry .urlConfirmation {
|
||||
padding: 1px 5px;
|
||||
-moz-border-radius: 10px;
|
||||
background-image: -moz-linear-gradient(top, #fafafa 0%, #e6e6e6 100%);
|
||||
border: 1px solid #bebebe;
|
||||
color: green;
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
bottom: 5px;
|
||||
z-index: 1;
|
||||
color: green;
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.entry .urlConfirmation span {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#settings .entry ul li {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#settings .entry ul li button {
|
||||
margin: 0 10px 0 0;
|
||||
width: 128px;
|
||||
}
|
||||
|
||||
.entry h1 {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
/* START hbox/vbox normalization from http://alex.dojotoolkit.org/2009/08/css-3-progress/ */
|
||||
/* hbox and vbox classes */
|
||||
|
||||
.hbox {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-align: stretch;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: horizontal;
|
||||
-moz-box-align: stretch;
|
||||
|
||||
display: box;
|
||||
box-orient: horizontal;
|
||||
box-align: stretch;
|
||||
}
|
||||
|
||||
.hbox > * {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.vbox {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-align: stretch;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
-moz-box-align: stretch;
|
||||
|
||||
display: box;
|
||||
box-orient: vertical;
|
||||
box-align: stretch;
|
||||
}
|
||||
|
||||
.vbox > * {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
box-flex: 1;
|
||||
}
|
||||
|
||||
.reverse {
|
||||
-webkit-box-direction: reverse;
|
||||
-moz-box-direction: reverse;
|
||||
box-direction: reverse;
|
||||
}
|
||||
|
||||
.boxFlex0 {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
}
|
||||
|
||||
.boxFlex1, .boxFlex {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
box-flex: 1;
|
||||
}
|
||||
|
||||
.boxFlex2 {
|
||||
-webkit-box-flex: 2;
|
||||
-moz-box-flex: 2;
|
||||
box-flex: 2;
|
||||
}
|
||||
|
||||
.boxGroup1 {
|
||||
-webkit-box-flex-group: 1;
|
||||
-moz-box-flex-group: 1;
|
||||
box-flex-group: 1;
|
||||
}
|
||||
|
||||
.boxGroup2 {
|
||||
-webkit-box-flex-group: 2;
|
||||
-moz-box-flex-group: 2;
|
||||
box-flex-group: 2;
|
||||
}
|
||||
|
||||
.start {
|
||||
-webkit-box-pack: start;
|
||||
-moz-box-pack: start;
|
||||
box-pack: start;
|
||||
}
|
||||
|
||||
.end {
|
||||
-webkit-box-pack: end;
|
||||
-moz-box-pack: end;
|
||||
box-pack: end;
|
||||
}
|
||||
|
||||
.center {
|
||||
-webkit-box-pack: center;
|
||||
-moz-box-pack: center;
|
||||
box-pack: center;
|
||||
}
|
||||
/* END hbox/vbox normalization from http://alex.dojotoolkit.org/2009/08/css-3-progress/ */
|
||||
|
||||
/* clearfix */
|
||||
|
||||
.clearfix:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
line-height: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
html[xmlns] .clearfix {
|
||||
display: block;
|
||||
}
|
||||
|
||||
* html .clearfix {
|
||||
height: 1%;
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||
- Version: MPL 1.1
|
||||
-
|
||||
- The contents of this file are subject to the Mozilla Public License Version
|
||||
- 1.1 (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.mozilla.org/MPL/
|
||||
-
|
||||
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
- for the specific language governing rights and limitations under the
|
||||
- License.
|
||||
-
|
||||
- The Original Code is Raindrop.
|
||||
-
|
||||
- The Initial Developer of the Original Code is
|
||||
- Mozilla Messaging, Inc..
|
||||
- Portions created by the Initial Developer are Copyright (C) 2009
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- -->
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="share.css">
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$("#tabs").tabs({ fx: { opacity: 'toggle', duration: 200 } });
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.ui-tabs .ui-tabs-hide { display: none; }
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="tabs" class="tabs-left">
|
||||
|
||||
<ul class="nav clearfix">
|
||||
<div class="navWrap clearfix">
|
||||
<li><a class="icon twitter" href="#twitter"><span class="name">Twitter</span></a></li>
|
||||
<li><a class="icon facebook" href="#facebook"><span class="name">Facebook</span></a></li>
|
||||
<li><a class="icon gmail" href="#gmail"><span class="name">Gmail</span></a></li>
|
||||
<li class="settings"><a class="icon settings" href="#settings"><span class="name"><img src="i/settings.png"></span></a></li>
|
||||
<div class="username">@clarkbw <img src="i/bryanAvatar.jpg"></div>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
<div id="twitter">
|
||||
<div class="entry hbox">
|
||||
<div class="boxFlex">
|
||||
<textarea class="message"></textarea>
|
||||
<span class="urlConfirmation"><span>re-insert link</span></span>
|
||||
</div>
|
||||
<button>share</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="facebook">
|
||||
<div class="entry hbox">
|
||||
<div class="thumbnail">
|
||||
<div class="thumb"></div>
|
||||
<ul class="info">
|
||||
<li class="title">Title</li>
|
||||
<li class="description">Description</li>
|
||||
</ul>
|
||||
</div>
|
||||
<textarea class="message boxFlex"></textarea>
|
||||
<button>share</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="gmail">
|
||||
<div class="entry hbox">
|
||||
<div class="inputs">
|
||||
<input id="to" type="text" value="to"/>
|
||||
<input id="subject" type="text" value="subject"/>
|
||||
</div>
|
||||
<div class="boxFlex">
|
||||
<textarea class="message"></textarea>
|
||||
<span class="urlConfirmation"><span>re-insert link</span></span>
|
||||
</div>
|
||||
<button>share</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="settings">
|
||||
<div class="entry">
|
||||
<h1>Settings</h1>
|
||||
<ul>
|
||||
<li><button>Add Twitter</button></li>
|
||||
<li><button>Add Facebook</button></li>
|
||||
<li><button>Add GMail</button></li>
|
||||
<li><button>Add FFFFound</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
После Ширина: | Высота: | Размер: 3.3 KiB |
После Ширина: | Высота: | Размер: 1.7 KiB |
|
@ -0,0 +1,231 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>F1: Sidebar</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="js/jquery.textOverflow.js"></script>
|
||||
<script type="text/javascript" src="js/init.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="wrapper">
|
||||
|
||||
<div id="panel1" class="flip">
|
||||
|
||||
<header class="hbox">
|
||||
<h1 class="boxFlex">Share</h1>
|
||||
<nav>
|
||||
<ul>
|
||||
<li class="settings"><a class="configureToggle" href="#">configure</a></li>
|
||||
<li><span class="close"></span></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section id="pageInfo" class="hbox">
|
||||
<div class="thumbnail"><img src="i/thumb.jpg"></div>
|
||||
<h2 class="boxFlex overflow pageTitle">F1 by Mozilla Labs</h2>
|
||||
</section>
|
||||
|
||||
<section id="twitter" class="account selected">
|
||||
<div class="accountToggle hbox open">
|
||||
<span class="arrow"></span>
|
||||
<span class="icon twitter"></span>
|
||||
<h3 class="boxFlex overflow">Twitter</h3>
|
||||
<span class="username">_andychung</span>
|
||||
</div>
|
||||
<div class="accountPanel">
|
||||
<div class="padding">
|
||||
<label>type your message:</label>
|
||||
<textarea class="compose"></textarea>
|
||||
<div class="accountActions hbox">
|
||||
<span class="count boxFlex">140</span>
|
||||
<button>share</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="facebook" class="account">
|
||||
<div class="accountToggle hbox">
|
||||
<span class="arrow"></span>
|
||||
<span class="icon facebook"></span>
|
||||
<h3 class="boxFlex overflow">Facebook</h3>
|
||||
<span class="username">Andy Chung</span>
|
||||
</div>
|
||||
<div class="accountPanel">
|
||||
<div class="padding">
|
||||
<div class="facebookActions hbox">
|
||||
<div class="to">
|
||||
<label>send to:</label>
|
||||
<div class="dropdownContainer">
|
||||
<select class="facebookDropdown">
|
||||
<option selected value="1">my wall</option>
|
||||
<option value="2">group wall</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group boxFlex">
|
||||
<label>type in the name of group:</label>
|
||||
<input type="text">
|
||||
</div>
|
||||
<div class="list">
|
||||
<label>list</label>
|
||||
<button></button>
|
||||
</div>
|
||||
</div>
|
||||
<label>type your message:</label>
|
||||
<textarea class="compose"></textarea>
|
||||
<div class="accountActions hbox">
|
||||
<span class="count boxFlex">420</span>
|
||||
<button>share</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="google" class="account">
|
||||
<div class="accountToggle hbox">
|
||||
<span class="arrow"></span>
|
||||
<span class="icon google"></span>
|
||||
<h3 class="boxFlex overflow">Google Mail</h3>
|
||||
<span class="username">animalyouth@gmail.com</span>
|
||||
</div>
|
||||
<div class="accountPanel">
|
||||
<div class="padding">
|
||||
<div class="to">
|
||||
<label>to: <em>(enter emails separated by comma)</em></label>
|
||||
<input type="text">
|
||||
</div>
|
||||
<div class="subject">
|
||||
<label>subject:</label>
|
||||
<input type="text">
|
||||
</div>
|
||||
<label>type your message:</label>
|
||||
<textarea class="compose"></textarea>
|
||||
<div class="accountActions hbox">
|
||||
<span class="count boxFlex"></span>
|
||||
<button>share</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div style="position:absolute;bottom:0;">
|
||||
<section id="news" class="hbox">
|
||||
<div>
|
||||
<span class="icon rss"></span>
|
||||
</div>
|
||||
<div class="boxFlex">
|
||||
<h3>Latest from the F1 team</h3>
|
||||
<div class="story">"F1 goes live!"</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- begin settings panel -->
|
||||
<div id="panel2" class="flip">
|
||||
|
||||
<header class="hbox">
|
||||
<h1 class="boxFlex">Share configuration</h1>
|
||||
<nav>
|
||||
<ul>
|
||||
<li class="settings"><a class="configureToggle" href="#">return to sharing</a></li>
|
||||
<li><span class="close"></span></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<ul id="tabs" class="clearfix">
|
||||
<li class="manage selected">manage</li>
|
||||
<li class="add">add account</li>
|
||||
<li class="settings">settings</li>
|
||||
</ul>
|
||||
|
||||
<div id="accountPanels">
|
||||
|
||||
<section id="manageAccounts" class="configuration">
|
||||
<h2>manage your accounts</h2>
|
||||
<ul class="accountList">
|
||||
<li class="accountType hbox">
|
||||
<h3 class="accountName boxFlex overflow">
|
||||
<span class="icon twitter"></span>
|
||||
<span class="username">_andychung</span>
|
||||
</h3>
|
||||
<button>remove</button>
|
||||
</li>
|
||||
<li class="accountType hbox">
|
||||
<h3 class="accountName boxFlex overflow">
|
||||
<span class="icon facebook"></span>
|
||||
<span class="username">Andy Chung</span>
|
||||
</h3>
|
||||
<button>remove</button>
|
||||
</li>
|
||||
<li class="accountType hbox">
|
||||
<h3 class="accountName boxFlex overflow">
|
||||
<span class="icon google"></span>
|
||||
<span class="username">animalyouth@gmail.com</span>
|
||||
</h3>
|
||||
<button>remove</button>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section id="addAccounts" class="configuration">
|
||||
<h2>add more accounts</h2>
|
||||
<ul class="accountList">
|
||||
<li class="accountType hbox">
|
||||
<h3 class="accountName boxFlex overflow">
|
||||
<span class="icon twitter"></span>
|
||||
Twitter
|
||||
</h3>
|
||||
<button>add</button>
|
||||
</li>
|
||||
<li class="accountType hbox">
|
||||
<h3 class="accountName boxFlex overflow">
|
||||
<span class="icon facebook"></span>
|
||||
Facebook
|
||||
</h3>
|
||||
<button>add</button>
|
||||
</li>
|
||||
<li class="accountType hbox">
|
||||
<h3 class="accountName boxFlex overflow">
|
||||
<span class="icon google"></span>
|
||||
Google Mail
|
||||
</h3>
|
||||
<button>add</button>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section id="accountSettings" class="configuration">
|
||||
<h2>F1 settings</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<div class="pref"><input id="bookmark" type="checkbox"> <label for="bookmark">Always bookmark the links I share</label></div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="pref"><input id="signature" type="checkbox"> <label for="signature">Include F1 email signature</label></div>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<section id="save" class="configuration">
|
||||
<div class="done hbox">
|
||||
<span class="boxFlex"></span>
|
||||
<button class="save">done</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,103 @@
|
|||
$(document).ready(function($) {
|
||||
|
||||
// set panel min-height to full browser height
|
||||
$(window).bind("load resize", function(){
|
||||
var h = $(window).height();
|
||||
$("#wrapper, #panel1, #panel2").css({ "min-height" : (h) });
|
||||
});
|
||||
|
||||
// create ellipsis for gecko
|
||||
$(function() {
|
||||
$(".overflow").textOverflow(null,true);
|
||||
});
|
||||
|
||||
// simple accordian menu
|
||||
$(".accountToggle").click(function() {
|
||||
$(".accountPanel:visible").slideUp(200);
|
||||
if ($(this).next().is(":hidden")) {
|
||||
$(this).next().slideDown(200);
|
||||
}
|
||||
});
|
||||
|
||||
$(".accountPanel").hide();
|
||||
$(".open").trigger("click");
|
||||
|
||||
$(".accountToggle").click(function() {
|
||||
$(this).parent().toggleClass("selected");
|
||||
$(this).parent().siblings().removeClass("selected");
|
||||
});
|
||||
|
||||
// hide and display facebook form
|
||||
$(".group, .list").hide();
|
||||
|
||||
$("select.facebookDropdown").change(function () {
|
||||
if ($(".group, .list").is(":hidden")) {
|
||||
$(".group, .list").css({ "display" : "block" });
|
||||
}
|
||||
else {
|
||||
$(".group, .list").css({ "display" : "none" });
|
||||
}
|
||||
});
|
||||
|
||||
// account manager simple tabs
|
||||
$("ul#tabs li").click(function() {
|
||||
$(this).addClass("selected");
|
||||
$(this).siblings().removeClass("selected");
|
||||
});
|
||||
|
||||
$("ul#tabs li.manage").click(function() {
|
||||
if ($("section#manageAccounts").is(":hidden")) {
|
||||
$("section#manageAccounts").fadeIn(200);
|
||||
$("section#manageAccounts").siblings().fadeOut(0);
|
||||
}
|
||||
else {
|
||||
$("section#manageAccounts").noop();
|
||||
}
|
||||
});
|
||||
|
||||
$("ul#tabs li.add").click(function() {
|
||||
if ($("section#addAccounts").is(":hidden")) {
|
||||
$("section#addAccounts").fadeIn(200);
|
||||
$("section#addAccounts").siblings().fadeOut(0);
|
||||
}
|
||||
else {
|
||||
$("section#addAccounts").noop();
|
||||
}
|
||||
});
|
||||
|
||||
$("ul#tabs li.settings").click(function() {
|
||||
if ($("section#accountSettings").is(":hidden")) {
|
||||
$("section#accountSettings").fadeIn(200);
|
||||
$("section#accountSettings").siblings().fadeOut(0);
|
||||
}
|
||||
else {
|
||||
$("section#manageAccounts").noop();
|
||||
}
|
||||
});
|
||||
|
||||
$("section#addAccounts, section#accountSettings").hide();
|
||||
|
||||
// 3d flip with fade fallback
|
||||
$(function() {
|
||||
if (jQuery.browser.webkit) {
|
||||
$("a.configureToggle").bind("click", function() {
|
||||
$("#panel1").toggleClass("front_flip");
|
||||
$("#panel2").toggleClass("back_flip");
|
||||
});
|
||||
}
|
||||
else {
|
||||
$("a.configureToggle").bind("click", function() {
|
||||
if ($("#panel1").is(":visible")) {
|
||||
$("#panel1").fadeOut(100);
|
||||
$("#panel2").fadeIn(100);
|
||||
}
|
||||
else {
|
||||
$("#panel1").fadeIn(100);
|
||||
$("#panel2").fadeOut(100);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// done!
|
||||
});
|
|
@ -0,0 +1,108 @@
|
|||
/*!
|
||||
* jQuery Text Overflow v0.7
|
||||
*
|
||||
* Licensed under the new BSD License.
|
||||
* Copyright 2009-2010, Bram Stein
|
||||
* All rights reserved.
|
||||
*/
|
||||
/*global jQuery, document, setInterval*/
|
||||
(function ($) {
|
||||
var style = document.documentElement.style,
|
||||
hasTextOverflow = ('textOverflow' in style || 'OTextOverflow' in style),
|
||||
|
||||
domSplit = function (root, maxIndex) {
|
||||
var index = 0, result = [],
|
||||
domSplitAux = function (nodes) {
|
||||
var i = 0, tmp;
|
||||
|
||||
if (index > maxIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < nodes.length; i += 1) {
|
||||
if (nodes[i].nodeType === 1) {
|
||||
tmp = nodes[i].cloneNode(false);
|
||||
result[result.length - 1].appendChild(tmp);
|
||||
result.push(tmp);
|
||||
domSplitAux(nodes[i].childNodes);
|
||||
result.pop();
|
||||
} else if (nodes[i].nodeType === 3) {
|
||||
if (index + nodes[i].length < maxIndex) {
|
||||
result[result.length - 1].appendChild(nodes[i].cloneNode(false));
|
||||
} else {
|
||||
tmp = nodes[i].cloneNode(false);
|
||||
tmp.textContent = $.trim(tmp.textContent.substring(0, maxIndex - index));
|
||||
result[result.length - 1].appendChild(tmp);
|
||||
}
|
||||
index += nodes[i].length;
|
||||
} else {
|
||||
result.appendChild(nodes[i].cloneNode(false));
|
||||
}
|
||||
}
|
||||
};
|
||||
result.push(root.cloneNode(false));
|
||||
domSplitAux(root.childNodes);
|
||||
return $(result.pop().childNodes);
|
||||
};
|
||||
|
||||
$.extend($.fn, {
|
||||
textOverflow: function (str, autoUpdate) {
|
||||
var more = str || '…';
|
||||
|
||||
if (!hasTextOverflow) {
|
||||
return this.each(function () {
|
||||
var element = $(this),
|
||||
|
||||
// the clone element we modify to measure the width
|
||||
clone = element.clone(),
|
||||
|
||||
// we save a copy so we can restore it if necessary
|
||||
originalElement = element.clone(),
|
||||
originalText = element.text(),
|
||||
originalWidth = element.width(),
|
||||
low = 0, mid = 0,
|
||||
high = originalText.length,
|
||||
reflow = function () {
|
||||
if (originalWidth !== element.width()) {
|
||||
element.replaceWith(originalElement);
|
||||
element = originalElement;
|
||||
originalElement = element.clone();
|
||||
element.textOverflow(str, false);
|
||||
originalWidth = element.width();
|
||||
}
|
||||
};
|
||||
|
||||
element.after(clone.hide().css({
|
||||
'position': 'absolute',
|
||||
'width': 'auto',
|
||||
'overflow': 'visible',
|
||||
'max-width': 'inherit'
|
||||
}));
|
||||
|
||||
if (clone.width() > originalWidth) {
|
||||
while (low < high) {
|
||||
mid = Math.floor(low + ((high - low) / 2));
|
||||
clone.empty().append(domSplit(originalElement.get(0), mid)).append(more);
|
||||
if (clone.width() < originalWidth) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
|
||||
if (low < originalText.length) {
|
||||
element.empty().append(domSplit(originalElement.get(0), low - 1)).append(more);
|
||||
}
|
||||
}
|
||||
clone.remove();
|
||||
|
||||
if (autoUpdate) {
|
||||
setInterval(reflow, 200);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
|
@ -0,0 +1,625 @@
|
|||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/*
|
||||
general
|
||||
*/
|
||||
|
||||
body {
|
||||
font-family: "Lucida Grande", Verdana, Sans-serif;
|
||||
font-size: 11px;
|
||||
line-height: 110%;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
max-width: 400px;
|
||||
min-width: 200px;
|
||||
position: relative;
|
||||
border-right: 1px solid #404040;
|
||||
-webkit-perspective: 1500;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 24px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #aaa;
|
||||
cursor: pointer;
|
||||
padding: 0 10px;
|
||||
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
|
||||
background-image: -moz-linear-gradient(center top , #fafafa 0%, #ddd 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fafafa), color-stop(100%, #ddd));
|
||||
}
|
||||
|
||||
button:active {
|
||||
-moz-box-shadow: 0 0 1px #666666 inset;
|
||||
-webkit-box-shadow: 0 0 1px #666666 inset;
|
||||
box-shadow: 0 0 1px #666666 inset;
|
||||
|
||||
background-image: -moz-linear-gradient(center top , #eee 0%, #ccc 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #eee), color-stop(100%, #ccc));
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 13px;
|
||||
color: #535f6d;
|
||||
text-shadow: 1px 1px 0 rgba(255,255,255, 0.5);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
color: #535f6d;
|
||||
}
|
||||
|
||||
/*
|
||||
panel settings
|
||||
*/
|
||||
|
||||
#panel1,
|
||||
#panel2 {
|
||||
width: 100%;
|
||||
color: #535f6d;
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#panel1 {
|
||||
background-color: #d4dde5;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#panel1 a,
|
||||
#panel2 a {
|
||||
color: #535f6d;
|
||||
}
|
||||
|
||||
#panel2 {
|
||||
background-color: #E9EEF2;
|
||||
z-index: 1;
|
||||
-webkit-transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
/*
|
||||
header section
|
||||
*/
|
||||
|
||||
header {
|
||||
width: 100%;
|
||||
padding: 8px 5px 10px 10px;
|
||||
background-color: #d4dde5;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
header a {
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
header a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
header nav ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
header nav ul li {
|
||||
display: inline-block;
|
||||
padding: 0 5px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
header nav ul li.settings {
|
||||
border-width: 0 1px 0 0;
|
||||
border-style: solid;
|
||||
border-color: #535f6d;
|
||||
}
|
||||
|
||||
header span.close {
|
||||
width: 12px;
|
||||
height: 13px;
|
||||
background-image: url("i/sprite.png");
|
||||
background-position: center 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
header span.close:active {
|
||||
background-position: center -13px;
|
||||
}
|
||||
|
||||
/*
|
||||
page info
|
||||
*/
|
||||
section#pageInfo {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
section#pageInfo .thumbnail {
|
||||
border: 1px solid #a6afb6;
|
||||
-moz-box-shadow: 1px 1px 0 rgba(255,255,255, 0.5);
|
||||
-webkit-box-shadow: 1px 1px 0 rgba(255,255,255, 0.5);
|
||||
box-shadow: 1px 1px 0 rgba(255,255,255, 0.5);
|
||||
}
|
||||
|
||||
section#pageInfo .thumbnail img {
|
||||
float: left;
|
||||
}
|
||||
|
||||
section#pageInfo h2 {
|
||||
line-height: 60px;
|
||||
margin: 0 0 0 20px;
|
||||
}
|
||||
|
||||
/*
|
||||
generic styles for account panels
|
||||
*/
|
||||
section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
section.account {
|
||||
color: #535F6D;
|
||||
display: block;
|
||||
border-width: 1px 0;
|
||||
border-color: #a6afb6;
|
||||
border-style: solid;
|
||||
margin-top: -1px;
|
||||
background-image: -moz-linear-gradient(top, #d4dde5 0%, #c6d1da 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #d4dde5), color-stop(100%, #c6d1da));
|
||||
}
|
||||
|
||||
section.account:hover,
|
||||
section.account.selected {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
section.account.selected {
|
||||
background-color: #e9eef2;
|
||||
}
|
||||
|
||||
section.account .username {
|
||||
display: none;
|
||||
}
|
||||
|
||||
section.account.selected .username {
|
||||
display: block;
|
||||
}
|
||||
|
||||
section.account .accountToggle {
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
span.arrow,
|
||||
span.icon {
|
||||
display: inline-block;
|
||||
background-image: url("i/sprite.png");
|
||||
background-repeat: no-repeat;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
span.arrow {
|
||||
width: 12px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
span.icon {
|
||||
width: 16px;
|
||||
height: 14px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
section.account .accountToggle span.arrow {
|
||||
background-position: center -102px;
|
||||
}
|
||||
|
||||
section.account.selected .accountToggle span.arrow {
|
||||
background-position: center -120px;
|
||||
}
|
||||
|
||||
section.account .accountPanel {
|
||||
display: block;
|
||||
}
|
||||
|
||||
section.account .accountPanel .padding {
|
||||
padding: 0 10px 10px 10px;
|
||||
}
|
||||
|
||||
section.account textarea,
|
||||
section.account input[type="text"] {
|
||||
width: 100%;
|
||||
font-family: "Lucida Grande", Verdana, Sans-serif;
|
||||
font-size: 11px;
|
||||
padding: 5px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #A6AFB6;
|
||||
-moz-box-shadow: 0 1px 1px rgba(0,0,0,0.15) inset;
|
||||
-webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.15) inset;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,0.15) inset;
|
||||
}
|
||||
|
||||
section.account textarea:focus,
|
||||
section.account input[type="text"]:focus {
|
||||
-moz-box-shadow: 0 0 0 2px #C2ECFF inset;
|
||||
-webkit-box-shadow: 0 0 0 2px #C2ECFF inset;
|
||||
box-shadow: 0 0 0 2px #C2ECFF inset;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline: none;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
section.account textarea {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
section.account input[type="text"] {
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
section.account .accountActions {
|
||||
width: 100%;
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
|
||||
section.account span.count {
|
||||
line-height: 24px;
|
||||
color: #535F6D;
|
||||
}
|
||||
|
||||
section.account label {
|
||||
display: block;
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
/*
|
||||
twitter styles
|
||||
*/
|
||||
span.icon.twitter {
|
||||
background-position: center -35px;
|
||||
}
|
||||
|
||||
/*
|
||||
facebook styles
|
||||
*/
|
||||
section#facebook.account .facebookActions {
|
||||
margin: 0 0 10px 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
section#facebook.account .facebookActions .to {
|
||||
width: 100px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
section#facebook.account .facebookActions .to .dropdownContainer {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
section#facebook.account .facebookActions .to select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
section#facebook.account .facebookActions .list label {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
section#facebook.account .facebookActions .list button {
|
||||
border-left: none;
|
||||
width: 24px;
|
||||
background-image: url("i/sprite.png"), -moz-linear-gradient(center top , #fafafa 0%, #ddd 100%);
|
||||
background-image: url("i/sprite.png"), -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fafafa), color-stop(100%, #ddd));
|
||||
background-position: center -157px, center top;
|
||||
background-repeat: no-repeat;
|
||||
-moz-border-radius: 0 2px 2px 0;
|
||||
-webkit-border-radius: 0 2px 2px 0;
|
||||
border-radius: 0 2px 2px 0;
|
||||
}
|
||||
|
||||
section#facebook.account .facebookActions .list button:active {
|
||||
background-image: url("i/sprite.png"), -moz-linear-gradient(center top , #eee 0%, #ccc 100%);
|
||||
background-image: url("i/sprite.png"), -webkit-gradient(linear, left top, left bottom, color-stop(0%, #eee), color-stop(100%, #ccc));
|
||||
}
|
||||
|
||||
span.icon.facebook {
|
||||
background-position: center -59px;
|
||||
}
|
||||
|
||||
/*
|
||||
google styles
|
||||
*/
|
||||
section#google.account .subject {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
span.icon.google {
|
||||
background-position: center -82px;
|
||||
}
|
||||
|
||||
/*
|
||||
account configuration
|
||||
*/
|
||||
|
||||
ul#tabs {
|
||||
width: 100%;
|
||||
padding: 10px 10px 0 10px;
|
||||
list-style-type: none;
|
||||
background-color: #D4DDE5;
|
||||
}
|
||||
|
||||
ul#tabs li {
|
||||
padding: 7px 20px;
|
||||
margin: 0 3px 0 0;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
background-color: #E9EEF2;
|
||||
border-width: 1px 1px 0 1px;
|
||||
border-style: solid;
|
||||
border-color: #A6AFB6;
|
||||
-moz-border-radius: 3px 3px 0 0;
|
||||
-webkit-border-radius: 3px 3px 0 0;
|
||||
border-radius: 3px 3px 0 0;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ul#tabs li.selected {
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#accountPanels {
|
||||
padding: 10px 0 0;
|
||||
border-top: 1px solid #a6afb6;
|
||||
position: relative;
|
||||
z-index: 90;
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
section.configuration {
|
||||
padding: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
section.configuration h2 {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
section.configuration ul {
|
||||
background-color: #fff;
|
||||
border: 1px solid #A6AFB6;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
section.configuration ul li {
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #A6AFB6;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
section.configuration ul li:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
section.configuration h3 {
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
section.configuration h3 .username {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
section.configuration input[type="checkbox"] {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
section.configuration .done {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
section#news {
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
section#news span.icon.rss {
|
||||
background-position: center -183px;
|
||||
margin: 0 5px 0 0;
|
||||
}
|
||||
|
||||
section#news .story {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
/*
|
||||
hbox & vbox
|
||||
*/
|
||||
|
||||
.hbox {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-align: stretch;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: horizontal;
|
||||
-moz-box-align: stretch;
|
||||
|
||||
display: box;
|
||||
box-orient: horizontal;
|
||||
box-align: stretch;
|
||||
}
|
||||
|
||||
.hbox > * {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.vbox {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-align: stretch;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
-moz-box-align: stretch;
|
||||
|
||||
display: box;
|
||||
box-orient: vertical;
|
||||
box-align: stretch;
|
||||
}
|
||||
|
||||
.vbox > * {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
box-flex: 1;
|
||||
}
|
||||
|
||||
.reverse {
|
||||
-webkit-box-direction: reverse;
|
||||
-moz-box-direction: reverse;
|
||||
box-direction: reverse;
|
||||
}
|
||||
|
||||
.boxFlex0 {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
}
|
||||
|
||||
.boxFlex1, .boxFlex {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
box-flex: 1;
|
||||
}
|
||||
|
||||
.boxFlex2 {
|
||||
-webkit-box-flex: 2;
|
||||
-moz-box-flex: 2;
|
||||
box-flex: 2;
|
||||
}
|
||||
|
||||
.boxGroup1 {
|
||||
-webkit-box-flex-group: 1;
|
||||
-moz-box-flex-group: 1;
|
||||
box-flex-group: 1;
|
||||
}
|
||||
|
||||
.boxGroup2 {
|
||||
-webkit-box-flex-group: 2;
|
||||
-moz-box-flex-group: 2;
|
||||
box-flex-group: 2;
|
||||
}
|
||||
|
||||
.start {
|
||||
-webkit-box-pack: start;
|
||||
-moz-box-pack: start;
|
||||
box-pack: start;
|
||||
}
|
||||
|
||||
.end {
|
||||
-webkit-box-pack: end;
|
||||
-moz-box-pack: end;
|
||||
box-pack: end;
|
||||
}
|
||||
|
||||
.center {
|
||||
-webkit-box-pack: center;
|
||||
-moz-box-pack: center;
|
||||
box-pack: center;
|
||||
}
|
||||
|
||||
/*
|
||||
clearfix
|
||||
*/
|
||||
|
||||
.clearfix:after {
|
||||
content: ".";
|
||||
display: block;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
line-height: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
html[xmlns] .clearfix {
|
||||
display: block;
|
||||
}
|
||||
|
||||
* html .clearfix {
|
||||
height: 1%;
|
||||
}
|
||||
|
||||
/*
|
||||
webkit specific styles
|
||||
*/
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
|
||||
#wrapper {
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
.overflow {
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.flip {
|
||||
-webkit-transform-style: preserve-3d;
|
||||
-webkit-backface-visibility: hidden;
|
||||
-webkit-transition: -webkit-transform 0.7s ease-in-out;
|
||||
}
|
||||
|
||||
.front_flip {
|
||||
-webkit-transform: rotateY(-180deg);
|
||||
z-index: 900;
|
||||
}
|
||||
|
||||
.back_flip {
|
||||
-webkit-transform: rotateY(0deg) !important;
|
||||
z-index: 1000;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||
- Version: MPL 1.1
|
||||
-
|
||||
- The contents of this file are subject to the Mozilla Public License Version
|
||||
- 1.1 (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.mozilla.org/MPL/
|
||||
-
|
||||
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
- for the specific language governing rights and limitations under the
|
||||
- License.
|
||||
-
|
||||
- The Original Code is Raindrop.
|
||||
-
|
||||
- The Initial Developer of the Original Code is
|
||||
- Mozilla Messaging, Inc..
|
||||
- Portions created by the Initial Developer are Copyright (C) 2009
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- -->
|
||||
|
||||
<!-- A hacky sample to attempt a send and handle auth failure automatically
|
||||
then attempt a resend
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Send a message</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
|
||||
<script src="../../scripts/requireplugins-jquery.js" charset="utf-8"></script>
|
||||
<script>require(["index.js"]);</script>
|
||||
<style>
|
||||
html, body {
|
||||
overflow: hidden;
|
||||
}
|
||||
body {
|
||||
background-color: white;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="settings">
|
||||
|
||||
<div class="row">
|
||||
<div class="c4 logo">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- send form -->
|
||||
<div class="section send">
|
||||
<form name="messageForm" id="messageForm" action="#">
|
||||
<div class="row">
|
||||
<div class="c1">
|
||||
<input name="message">
|
||||
Send via
|
||||
<input type="radio" name="domain" value="twitter.com">Twitter
|
||||
<input type="radio" name="domain" value="facebook.com">Facebook
|
||||
<input type="radio" name="domain" value="noservice.com">No Service
|
||||
|
||||
<input type="hidden" name="end_point_success" value="/scratch/send/#success">
|
||||
<input type="hidden" name="end_point_failure" value="/scratch/send/#failure">
|
||||
<input type="hidden" name="end_point_auth_failure" value="/scratch/send/#auth_failure">
|
||||
<button>send</button>
|
||||
|
||||
</div>
|
||||
<div class="c1">
|
||||
<div class="usernameError error invisible">Please enter your Twitter name</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- send success section -->
|
||||
<div class="section success hidden">
|
||||
<div class="row">
|
||||
<div class="c1">
|
||||
<h4 class="success">Success!</h4>
|
||||
<p>Your message was sent</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- auth failure section
|
||||
|
||||
This is the end_point for when the *send* request fails auth (but not
|
||||
when the explicit auth request fails) - when this happens we do the
|
||||
explicit auth.
|
||||
-->
|
||||
<div class="section auth_failure hidden">
|
||||
<div class="row">
|
||||
<div class="c1">
|
||||
<p>Authorizing...</p>
|
||||
<!-- the js code arranges to submit the auth form below... -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section auth_form hidden"> <!-- this is never made visible -->
|
||||
<form name="authForm" id="authForm" action="/api/account/authorize" method="POST">
|
||||
<div class="row">
|
||||
<input type="hidden" name="domain">
|
||||
<input type="hidden" name="end_point_success" value="/scratch/send/#auth_success">
|
||||
<input type="hidden" name="end_point_auth_failure" value="/scratch/send/#final_auth_failure">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- final auth failure section
|
||||
This is the end_point for when the explicit auth request fails - we have
|
||||
given up here...
|
||||
-->
|
||||
<div class="section final_auth_failure hidden">
|
||||
<div class="row">
|
||||
<div class="c1">
|
||||
<p>Failed to authorize...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- auth success section
|
||||
This is the end_point for when the explicit auth request succeeds - we
|
||||
then attempt to retry the send.
|
||||
-->
|
||||
<div class="section auth_success hidden">
|
||||
<div class="row">
|
||||
<div class="c1">
|
||||
<p>Sending...</p>
|
||||
<!-- the JS code re-submits the send form -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- general failure section - an error other than auth failure...-->
|
||||
<div id="resultMsg" class="section failure hidden">
|
||||
<div class="row">
|
||||
<div class="c1">
|
||||
<p id="resultReason">Sorry - we failed for obscure reasons...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,481 @@
|
|||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
|
@ -0,0 +1,35 @@
|
|||
The Stay-Puft Marshmallow Font
|
||||
|
||||
Copyright (c) 2003 by John Stracke
|
||||
|
||||
Not a very impressive piece of work, but fun. I sat down to fiddle
|
||||
with pfaedit, and started seeing what I could do freehand, with
|
||||
minimal splines. The result was all rounded (not surprising), sort of
|
||||
marshmallowy, and I started thinking of it as the Stay-Puft
|
||||
Marshmallow Font (see Ghostbusters if you don't get it). Once I had a
|
||||
name, I felt compelled to round out the font (ISO 8859-1, at least).
|
||||
The outcome looks sort of like Comic Sans MS. It's kind of cute, and
|
||||
might be good for frivolous stuff such as birthday cards. I've used
|
||||
it on my National Academy of Silly Walks merchandise
|
||||
(http://www.cafepress.com/sillywalks/).
|
||||
|
||||
It is released under the terms of the GNU Lesser General Public
|
||||
License (see COPYING.LIB). Where the LGPL refers to "source code", I
|
||||
take that to refer to the file called StayPuft.sfd, which is a file
|
||||
for editing with pfaedit (http://pfaedit.sourceforge.net/), an outline
|
||||
font editor program. Thus, according to the LGPL, if you distribute
|
||||
this font, you must make StayPuft.sfd available to the recipient(s)
|
||||
under the terms the LGPL specifies for source availability. Each of
|
||||
the download links below is an archive (tarfile or zipfile) which
|
||||
includes StayPuft.sfd, the LGPL, a readme, and at least one font file
|
||||
(e.g., Isabella.ttf for TrueType files). I chose the LGPL instead of
|
||||
the GPL because, arguably, using the GPL might mean that PostScript
|
||||
and PDF files with this font embedded would be GPLed (they're like
|
||||
programs that link to a static library).
|
||||
|
||||
The font has ASCII, Latin-1, and a few other useful characters: left
|
||||
and right quotation marks (single and double), ellipsis, long dash,
|
||||
and Euro. I don't intend to round it out as much as I did with
|
||||
Isabella (http://www.thibault.org/fonts/isabella/); this is a much
|
||||
less interesting project. Anyone who wants to donate extra
|
||||
letterforms is welcome, of course.
|
После Ширина: | Высота: | Размер: 285 KiB |
|
@ -0,0 +1,402 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
/* @font-face typography */
|
||||
|
||||
@font-face {
|
||||
font-family: StayPuft;
|
||||
src: url("f/StayPuft/StayPuft.ttf");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
* {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, Sans-serif;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
color: #0a0a0a;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
b {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #006FFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: normal;
|
||||
font-size: 21px;
|
||||
margin: 0;
|
||||
padding: 5px 10px;
|
||||
/* border: 1px solid #884D51; */
|
||||
background-image: -moz-linear-gradient(center top , #FF7A7A 0%, #FF5C5C 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #FF7A7A), color-stop(100%, #FF5C5C));
|
||||
border: 1px solid #D94C4C;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
h1 a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
h2 a {
|
||||
color: #0a0a0a;
|
||||
}
|
||||
|
||||
h1 a:hover,
|
||||
h2 a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1 a:visited {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
h2 a:visited {
|
||||
color: black;
|
||||
}
|
||||
|
||||
h3 .type {
|
||||
font-size: smaller;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#toc {
|
||||
-moz-column-count: 3;
|
||||
-webkit-column-count: 3;
|
||||
column-count: 3;
|
||||
-moz-column-gap: 20px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
#toc a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#toc a.sectionToc {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#toc a.methodToc {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#toc a.methodToc:before {
|
||||
content: "- ";
|
||||
}
|
||||
|
||||
#toc .tocItem {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
#listing,
|
||||
#play {
|
||||
float: left;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#play {
|
||||
overflow-x: auto;
|
||||
background-color: #f2f2f2;
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
|
||||
#playInstructions {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.method {
|
||||
position: relative;
|
||||
border-top: 1px solid #C6ADFF;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.method .try {
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
padding: 5px 0px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
-moz-border-radius: 0 40px 40px 0;
|
||||
-webkit-border-radius: 0 40px 40px 0;
|
||||
border-radius: 0 40px 40px 0;
|
||||
}
|
||||
|
||||
|
||||
.method h2 {
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
padding: 5px 10px;
|
||||
/* border: 1px solid #884D51; */
|
||||
background-image: -moz-linear-gradient(center top , #EDE6FF 0%, #DAC9FF 100%);
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #EDE6FF), color-stop(100%, #DAC9FF));
|
||||
border: 1px solid #C6ADFF;
|
||||
border-top: none;
|
||||
-moz-border-radius: 0 0 10px 10px;
|
||||
-webkit-border-radius: 0 0 10px 10px;
|
||||
border-radius: 0 0 10px 10px;
|
||||
display: table;
|
||||
}
|
||||
|
||||
.method .section {
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
.method .section h3 {
|
||||
margin-left: -20px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.method .section > ul {
|
||||
padding-left: 20px;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.method .section p {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.method .required {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.apiCall {
|
||||
padding: 10px ;
|
||||
position: relative;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.apiCall:nth-child(odd) {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
|
||||
.apiCallClose {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 0px;
|
||||
font-weight: bold;
|
||||
color: #0a0a0a;
|
||||
border: 0;
|
||||
font-family: "helvetica neue", helvetica, arial, sans-serif;
|
||||
font-size: 14px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.apiCall .apiUrlExpand {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 60px;
|
||||
}
|
||||
|
||||
.apiCall h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.apiCall h4 {
|
||||
margin: 10px 0 5px 0;
|
||||
}
|
||||
|
||||
.apiCall .editApiUrl {
|
||||
width: 50%;
|
||||
margin-top: 4px;
|
||||
font-weight: bold;
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.apiCall .requestBody {
|
||||
width: 100%;
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.apiCall .output {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.apiCall button[name=submit] {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.jsonResult .expander {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: xx-small;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
.jsonResult ol.array,
|
||||
.jsonResult ul.object {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.jsonResult .prop,
|
||||
.jsonResult .brace,
|
||||
.jsonResult .bracket {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* START hbox/vbox normalization from http://alex.dojotoolkit.org/2009/08/css-3-progress/ */
|
||||
/* hbox and vbox classes */
|
||||
|
||||
.hbox {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-align: stretch;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: horizontal;
|
||||
-moz-box-align: stretch;
|
||||
|
||||
display: box;
|
||||
box-orient: horizontal;
|
||||
box-align: stretch;
|
||||
}
|
||||
|
||||
.hbox > * {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.vbox {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-align: stretch;
|
||||
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
-moz-box-align: stretch;
|
||||
|
||||
display: box;
|
||||
box-orient: vertical;
|
||||
box-align: stretch;
|
||||
}
|
||||
|
||||
.vbox > * {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
box-flex: 1;
|
||||
}
|
||||
|
||||
.reverse {
|
||||
-webkit-box-direction: reverse;
|
||||
-moz-box-direction: reverse;
|
||||
box-direction: reverse;
|
||||
}
|
||||
|
||||
.boxFlex0 {
|
||||
-webkit-box-flex: 0;
|
||||
-moz-box-flex: 0;
|
||||
box-flex: 0;
|
||||
}
|
||||
|
||||
.boxFlex1, .boxFlex {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
box-flex: 1;
|
||||
}
|
||||
|
||||
.boxFlex2 {
|
||||
-webkit-box-flex: 2;
|
||||
-moz-box-flex: 2;
|
||||
box-flex: 2;
|
||||
}
|
||||
|
||||
.boxGroup1 {
|
||||
-webkit-box-flex-group: 1;
|
||||
-moz-box-flex-group: 1;
|
||||
box-flex-group: 1;
|
||||
}
|
||||
|
||||
.boxGroup2 {
|
||||
-webkit-box-flex-group: 2;
|
||||
-moz-box-flex-group: 2;
|
||||
box-flex-group: 2;
|
||||
}
|
||||
|
||||
.start {
|
||||
-webkit-box-pack: start;
|
||||
-moz-box-pack: start;
|
||||
box-pack: start;
|
||||
}
|
||||
|
||||
.end {
|
||||
-webkit-box-pack: end;
|
||||
-moz-box-pack: end;
|
||||
box-pack: end;
|
||||
}
|
||||
|
||||
.center {
|
||||
-webkit-box-pack: center;
|
||||
-moz-box-pack: center;
|
||||
box-pack: center;
|
||||
}
|
||||
/* END hbox/vbox normalization from http://alex.dojotoolkit.org/2009/08/css-3-progress/ */
|
|
@ -0,0 +1,240 @@
|
|||
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||
- Version: MPL 1.1
|
||||
-
|
||||
- The contents of this file are subject to the Mozilla Public License Version
|
||||
- 1.1 (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.mozilla.org/MPL/
|
||||
-
|
||||
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
- for the specific language governing rights and limitations under the
|
||||
- License.
|
||||
-
|
||||
- The Original Code is Raindrop.
|
||||
-
|
||||
- The Initial Developer of the Original Code is
|
||||
- Mozilla Messaging, Inc..
|
||||
- Portions created by the Initial Developer are Copyright (C) 2009
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Raindrop API</title>
|
||||
<link type="text/css" rel="stylesheet" href="/0.3.4/rdapi/index.css">
|
||||
<script src="/0.3.4/scripts/requireplugins-jquery.js" charset="utf-8"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
/*global require: false */
|
||||
require({
|
||||
paths: {
|
||||
'index': '/0.3.4/rdapi/scripts/index',
|
||||
}
|
||||
},
|
||||
['index']
|
||||
);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="listing">
|
||||
|
||||
<div class="header">
|
||||
<h1 id="topHeading">Raindrop API</h1>
|
||||
<p>This is the Raindrop API explorer. Read the important <a href="#Notes">Notes</a> first.</p>
|
||||
</div>
|
||||
|
||||
<div id="toc">
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<div class="sectionContent">
|
||||
<!-- The name attribute for Notes is added after we fill in the content,
|
||||
otherwise Firefox has a weird box calculation problem. -->
|
||||
<h1 class="section"><a id="NotesTitle" href="#Notes">Notes</a></h1>
|
||||
|
||||
<p><a href="http://en.wikipedia.org/wiki/JSON">JSON</a> is used for all API responses.
|
||||
The request arguments are normally <a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1">form-urlencoded</a>
|
||||
arguments (<b>Content-Type: application/x-www-form-urlencoded; charset=UTF-8</b>), except
|
||||
for APIs that only accept a request body. In those cases, the request body should be JSON,
|
||||
and the Content-Type for the request should be <b>application/json; charset=UTF-8</b>. Note that UTF-8
|
||||
should be used as the charset.</p>
|
||||
|
||||
<div class="method">
|
||||
<h2><a id="StandardResponseTitle" href="#StandardResponse">Notes: Standard Response</a></h2>
|
||||
<p>The success version of the Standard Response is used by a few APIs for success responses. Other APIs use
|
||||
a specific success object that relates to the API. See the specific API call for more information.</p>
|
||||
|
||||
<p>The error version of the Standard Response is used by <b>all APIs</b> to indicate error responses.</p>
|
||||
|
||||
<p>A <b>success response</b> will be an object with the following properties (only used by some APIs):</p>
|
||||
<ul>
|
||||
<li><b>ids</b> (array): Any IDs affected by the API call. May be empty</li>
|
||||
<li><b>result</b> (boolean): Value of true</li>
|
||||
<li><b>error</b> (object): null</li>
|
||||
</ul>
|
||||
|
||||
<p>An <b>error response</b> will be an object with the following properties (this is the error response
|
||||
returned from all APIs):</p>
|
||||
<ul>
|
||||
<li><b>ids</b> (array): Any IDs affected by the API call. May be empty</li>
|
||||
<li><b>result</b> (object): null if the API call has an error</li>
|
||||
<li><b>error</b> (object): An object with the following properties:
|
||||
<ul>
|
||||
<li><b>name</b> (string): an error type name</li>
|
||||
<li><b>message</b> (string): An English description of the error</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="method">
|
||||
<h2><a id="ConversationTitle" href="#Conversation">Notes: Conversation Object</a></h2>
|
||||
<p class="required">TODO</p>
|
||||
</div>
|
||||
<div class="method">
|
||||
<h2><a id="MessageTitle" href="#Message">Notes: Message Object</a></h2>
|
||||
<p class="required">TODO</p>
|
||||
</div>
|
||||
<div class="method">
|
||||
<h2><a id="AttachmentTitle" href="#Attachment">Notes: Attachment Object</a></h2>
|
||||
<p class="required">TODO</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="play">
|
||||
<p id="playInstructions">Use a "Try It" link to try an API in this area.</p>
|
||||
</div>
|
||||
|
||||
<form class="apiCall" action="#">
|
||||
<h3 class="apiUrl"></h3>
|
||||
<select class="apiUrlExpand hidden">
|
||||
<option value=''>Change URL</option>
|
||||
<ul class="apiUrlChoices hidden">
|
||||
</ul>
|
||||
</select>
|
||||
|
||||
<div class="parameterUrl hidden">
|
||||
<h4>URL Parameters</h4>
|
||||
<table>
|
||||
<tbody class="urlParams"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="request">
|
||||
<h4>Request Parameters</h4>
|
||||
<table>
|
||||
<tbody class="requestParams"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="body">
|
||||
<h4>Request Body</h4>
|
||||
<textarea class="requestBody"></textarea>
|
||||
</div>
|
||||
<button name="submit">Submit</button>
|
||||
<button class="apiCallClose">close</button>
|
||||
<div class="output"></div>
|
||||
</form>
|
||||
|
||||
<div class="methodContent template" id="methodContent">
|
||||
<p>{^doc}</p>
|
||||
|
||||
{is(routes.length) [}
|
||||
<div class="section">
|
||||
<h3>URL</h3>
|
||||
<ul>
|
||||
{routes [}
|
||||
<li>{}</li>
|
||||
{]}
|
||||
</ul>
|
||||
</div>
|
||||
{]}
|
||||
|
||||
{and(urlargs, urlargs.length) [}
|
||||
<div class="section">
|
||||
<h3>URL Arguments</h3>
|
||||
<ul>
|
||||
{urlargs[}
|
||||
<li><b class="{required [}required{]}">{name}</b> ({type}): {doc}</li>
|
||||
{]}
|
||||
</ul>
|
||||
</div>
|
||||
{]}
|
||||
|
||||
{and(queryargs, queryargs.length) [}
|
||||
<div class="section">
|
||||
<h3>Parameters</h3>
|
||||
<ul>
|
||||
{queryargs[}
|
||||
<li><b class="{required [}required{]}">{name}</b> ({type}): {doc}</li>
|
||||
{]}
|
||||
</ul>
|
||||
</div>
|
||||
{]}
|
||||
|
||||
{is(body) [}
|
||||
<div class="section">
|
||||
{body [}
|
||||
<h3>Request Body <span class="type">({type})</span></h3>
|
||||
<p>{doc}</p>
|
||||
{]}
|
||||
|
||||
{examplebody [}
|
||||
<b>Example</b>:
|
||||
<pre class="sampleBodyPre">{prettyJson(_)}</pre>
|
||||
{]}
|
||||
</div>
|
||||
{]}
|
||||
|
||||
{response [}
|
||||
<div class="section">
|
||||
<h3>Response <span class="type">({type})</span></h3>
|
||||
<p>{^addApiHyperlinks(doc)}</p>
|
||||
</div>
|
||||
{]}
|
||||
</div>
|
||||
|
||||
<div class="tocItem template" id="sectionToc">
|
||||
<a class="sectionToc" href="#{section}">{section}</a>
|
||||
{methods [}
|
||||
<a class="methodToc" href="#{link}">{name}</a>
|
||||
{]}
|
||||
</div>
|
||||
|
||||
<div class="sectionContent template" id="sectionContent">
|
||||
<h1 class="section"><a href="#{section}" name="{section}">{section}</a></h1>
|
||||
<p>{^doc}</p>
|
||||
{methods [}
|
||||
<div class="method">
|
||||
<a class="try" href="#try:{link}">Try It!</a>
|
||||
<h2><a href="#{link}" name="{link}">{section}: {name}</a></h2>
|
||||
{^content}
|
||||
</div>
|
||||
{]}
|
||||
</div>
|
||||
|
||||
<div class="jsonResult template" id="jsonResult">
|
||||
{#jsonBranch}
|
||||
</div>
|
||||
|
||||
<script class="template" id="jsonBranch" type="text/template">
|
||||
{. _rdApiType getType(_)}
|
||||
{eq(_rdApiType, 'object') [}
|
||||
<span class="brace">{</span> <button class="expander">▼</button> <ul class="object">
|
||||
{eachProp(_) [}
|
||||
<li><span class="prop">{prop}</span> : {#jsonBranch value}</li>
|
||||
{]}
|
||||
</ul> <span class="brace">}</span>
|
||||
{] eq(_rdApiType, 'array') [}
|
||||
<span class="bracket">[</span> <button class="expander">▼</button> <ol class="array">
|
||||
{_ [}
|
||||
<li>{#jsonBranch}</li>
|
||||
{]}
|
||||
</ol> <span class="bracket">]</span>
|
||||
{] [}
|
||||
<span class="value">{formatSimpleType(_)}</span>
|
||||
{]}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,504 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
'use strict';
|
||||
/*jslint plusplus: false, regexp: false */
|
||||
/*global require: false, define: false, location: true, setTimeout: false,
|
||||
alert: false, window: false, document: false */
|
||||
|
||||
define([ 'jquery', 'rdapi', 'blade/object', 'blade/jig'],
|
||||
function ($, rdapi, object, jig) {
|
||||
|
||||
var docs, urlSection, toc = [],
|
||||
urlParamRegExp = /\{([^\}]+)\}/g,
|
||||
fragLinkRegExp = /#StandardResponse|#Attachment|#Message|#Conversation/g,
|
||||
apiLinks = {
|
||||
'#StandardResponse': 'Standard Response',
|
||||
'#Attachment': 'Attachment',
|
||||
'#Message': 'Message',
|
||||
'#Conversation': 'Conversation'
|
||||
};
|
||||
|
||||
//Add a pretty JSON method for use in templates
|
||||
jig.addFn({
|
||||
prettyJson: function (text) {
|
||||
return JSON.stringify(JSON.parse(text), null, " ");
|
||||
},
|
||||
addApiHyperlinks: function (text) {
|
||||
var output = '', startIndex = 0, match;
|
||||
fragLinkRegExp.lastIndex = 0;
|
||||
while ((match = fragLinkRegExp.exec(text))) {
|
||||
match = match[0];
|
||||
output += jig.htmlEscape(text.substring(startIndex, fragLinkRegExp.lastIndex - match.length));
|
||||
output += '<a href="' + match + '">' + apiLinks[match] + '</a>';
|
||||
startIndex = fragLinkRegExp.lastIndex;
|
||||
}
|
||||
if (startIndex < text.length - 1) {
|
||||
output += jig.htmlEscape(text.substring(startIndex, text.length));
|
||||
}
|
||||
return output;
|
||||
},
|
||||
getType: function (it) {
|
||||
if (require.isArray(it)) {
|
||||
return 'array';
|
||||
} else if (typeof it === "object" && it !== undefined && it !== null) {
|
||||
return 'object';
|
||||
} else {
|
||||
return 'other';
|
||||
}
|
||||
},
|
||||
formatSimpleType: function (it) {
|
||||
if (it === null) {
|
||||
return 'null';
|
||||
} else if (it === 0) {
|
||||
return '0';
|
||||
} else if (it === undefined) {
|
||||
return 'undefined';
|
||||
} else if (it === true) {
|
||||
return 'true';
|
||||
} else if (it === false) {
|
||||
return 'false';
|
||||
} else {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//Array sorting method for method entries. Separated as a distinct
|
||||
//function to make JSLint happy.
|
||||
function methodSort(a, b) {
|
||||
return a.name > b.name ? 1 : -1;
|
||||
}
|
||||
|
||||
function hashUpdated() {
|
||||
//Hmm, an overflow div does not jump if the hash is changed, as in
|
||||
//a back/forward button press, so force it.
|
||||
var hash = location.href.split('#')[1] || '',
|
||||
listingNode = $('#listing')[0],
|
||||
targetNode;
|
||||
|
||||
if (hash) {
|
||||
targetNode = $('[name="' + hash + '"]')[0];
|
||||
if (!targetNode) {
|
||||
if (hash.indexOf('%') !== -1) {
|
||||
//Try unescaping the URL.
|
||||
hash = decodeURIComponent(hash);
|
||||
targetNode = $('[name="' + hash + '"]')[0];
|
||||
} else {
|
||||
//Try escaping it
|
||||
hash = encodeURIComponent(hash);
|
||||
targetNode = $('[name="' + hash + '"]')[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
if (targetNode) {
|
||||
listingNode.scrollTop = listingNode.scrollTop + targetNode.getBoundingClientRect().top;
|
||||
} else {
|
||||
listingNode.scrollTop = 0;
|
||||
}
|
||||
}, 15);
|
||||
}
|
||||
|
||||
function updateApiUrl(form, url) {
|
||||
var apiUrl = form.find('.apiUrl'),
|
||||
parameterUrl = form.find('.parameterUrl'),
|
||||
match, urlParam, urlParams = '', urlParamObj;
|
||||
|
||||
//Show the API URL
|
||||
apiUrl.html(url).removeClass('hidden');
|
||||
parameterUrl.addClass('hidden');
|
||||
|
||||
//If the URL has arguments in its path, show options for it.
|
||||
if (url.indexOf('{') !== -1) {
|
||||
//Put in the parameterized URL and attach the source
|
||||
//URL as a property on the DOM node for better perf
|
||||
parameterUrl
|
||||
.removeClass('hidden')
|
||||
.find('.editApiUrl')
|
||||
.remove()
|
||||
.end()
|
||||
.prepend('<input type="text" class="editApiUrl" value="' + url + '">')[0]
|
||||
.apiUrl = url;
|
||||
|
||||
//Hide the normal h2 title
|
||||
apiUrl.addClass('hidden');
|
||||
|
||||
//Parse out the fields in play
|
||||
urlParamRegExp.lastIndex = 0;
|
||||
while ((match = urlParamRegExp.exec(url))) {
|
||||
urlParam = match[1];
|
||||
urlParamObj = form[0].raindropApiMethod.urlargs && form[0].raindropApiMethod.urlargs[urlParam];
|
||||
|
||||
urlParams += '<tr><td class="urlParamName">' + urlParam + '</td><td class="urlParamValue">';
|
||||
|
||||
if (urlParamObj && urlParamObj.allowed) {
|
||||
urlParams += '<select class="urlParamSelect" name="' + urlParam + '">' +
|
||||
'<option value=""></option>';
|
||||
urlParamObj.allowed.forEach(function (value) {
|
||||
urlParams += '<option value="' + value + '">' + value + '</option>';
|
||||
});
|
||||
urlParams += '</select>';
|
||||
} else {
|
||||
urlParams += '<input type="text" class="urlParam" name="' + urlParam + '">';
|
||||
}
|
||||
|
||||
urlParams += '</td></tr>';
|
||||
}
|
||||
form.find('.urlParams').html(urlParams);
|
||||
}
|
||||
}
|
||||
|
||||
//delegated event handler that handles changes to URL arg fields, both input text ones,
|
||||
//and select elements.
|
||||
function changeApiUrl(evt) {
|
||||
//Handle key ups for modifying URL parameters
|
||||
//Only do an update on a timed delay, so that
|
||||
//the DOM is not beaten up for each key stroke.
|
||||
if (!urlSection) {
|
||||
urlSection = $(evt.target).parents('.parameterUrl');
|
||||
setTimeout(function () {
|
||||
var apiUrl = urlSection[0].apiUrl;
|
||||
|
||||
urlSection.find('.urlParam, .urlParamSelect').each(function (i, node) {
|
||||
var value = node.value.trim();
|
||||
if (value) {
|
||||
apiUrl = apiUrl.replace('{' + node.name + '}', value);
|
||||
}
|
||||
});
|
||||
|
||||
//Update the final URL
|
||||
urlSection.find('.editApiUrl').val(apiUrl);
|
||||
|
||||
urlSection = null;
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
||||
function getCsrfToken() {
|
||||
var token = /csrf=([^\; ]+)/.exec(document.cookie);
|
||||
return token && token[1] ? token[1] : null;
|
||||
}
|
||||
|
||||
rdapi('docs', {
|
||||
success: function (json) {
|
||||
var prop, methodName, apiSection, methods, method, tocItem, obj,
|
||||
i, route, parts, urlParam;
|
||||
|
||||
docs = json;
|
||||
|
||||
//TOC is by API section and method name, build it up,
|
||||
//as well as the content that goes for each section.
|
||||
for (prop in docs) {
|
||||
if (docs.hasOwnProperty(prop)) {
|
||||
apiSection = docs[prop];
|
||||
methods = apiSection.methods;
|
||||
|
||||
//Create the TOC item for this API section.
|
||||
tocItem = {
|
||||
section: prop,
|
||||
doc: apiSection.doc.replace(/<h1[^<]*<\/h1>/g, ''),
|
||||
value: apiSection,
|
||||
methods: []
|
||||
};
|
||||
|
||||
//Create a method section in the TOC as well as the content
|
||||
//that shows up in the main document section.
|
||||
for (methodName in methods) {
|
||||
if (methods.hasOwnProperty(methodName)) {
|
||||
method = methods[methodName];
|
||||
|
||||
//Create quick lookups for urlargs parameters
|
||||
if (method.urlargs) {
|
||||
method.urlargs.forEach(function (arg) {
|
||||
method.urlargs[arg.name] = arg;
|
||||
});
|
||||
}
|
||||
|
||||
//Make sure the API routes are prefixed with /api
|
||||
if (method.routes) {
|
||||
for (i = 0; (route = method.routes[i]); i++) {
|
||||
//For any URL methods, if only one valid value,
|
||||
//then just fix it to that value. Thinking mostly
|
||||
//of contacts API where @{user} is normally just @me
|
||||
parts = route.split('/');
|
||||
parts.forEach(function (part, j) {
|
||||
urlParamRegExp.lastIndex = 0;
|
||||
parts[j] = part.replace(urlParamRegExp, function (match, p1) {
|
||||
if (method.urlargs) {
|
||||
urlParam = method.urlargs[p1];
|
||||
if (urlParam && urlParam.allowed && urlParam.allowed.length === 1) {
|
||||
return urlParam.allowed[0];
|
||||
}
|
||||
}
|
||||
return match;
|
||||
});
|
||||
});
|
||||
route = parts.join('/');
|
||||
|
||||
if (route.indexOf('/api') !== 0) {
|
||||
method.routes[i] = '/api' + route;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obj = object.create(method, [{
|
||||
name: methodName,
|
||||
link: encodeURIComponent(prop) + ":" + encodeURIComponent(methodName)
|
||||
}]);
|
||||
|
||||
//Generate the HTML content for this section.
|
||||
obj.content = jig(jig.cache('methodContent'), obj, {}).replace(/<h1[^<]*<\/h1>/g, '');
|
||||
|
||||
tocItem.methods.push(obj);
|
||||
//Store a shortcut to reference the method by name.
|
||||
tocItem.methods[methodName] = obj;
|
||||
}
|
||||
}
|
||||
|
||||
//Sort the methods
|
||||
tocItem.methods.sort(methodSort);
|
||||
|
||||
//Store a shortcut to reference the section by name.
|
||||
toc[prop] = tocItem;
|
||||
toc.push(tocItem);
|
||||
}
|
||||
}
|
||||
|
||||
//Sort the toc contents
|
||||
toc.sort(function (a, b) {
|
||||
return a.section > b.section ? 1 : -1;
|
||||
});
|
||||
|
||||
//Wait for page load to fill in the page content
|
||||
$(function () {
|
||||
var tocHtml = '',
|
||||
html = '',
|
||||
apiCallNode = $('.apiCall')[0],
|
||||
play = $('#play');
|
||||
|
||||
//Remove the apiCall node from the DOM, since just used for clone operations.
|
||||
apiCallNode.parentNode.removeChild(apiCallNode);
|
||||
|
||||
toc.forEach(function (tocItem) {
|
||||
//Create TOC entry
|
||||
tocHtml += jig(jig.cache('sectionToc'), tocItem, {});
|
||||
|
||||
//Create content entry
|
||||
html += jig(jig.cache('sectionContent'), tocItem, {});
|
||||
});
|
||||
|
||||
$("#toc").append(tocHtml);
|
||||
$("#content").append(html);
|
||||
|
||||
//Add the name attributes to static sections here instead of the HTML
|
||||
//to avoid a weird box sizing issue in Firefox.
|
||||
['Notes', 'Conversation', 'Message', 'Attachment'].forEach(function (name) {
|
||||
document.getElementById(name + 'Title').setAttribute('name', name);
|
||||
});
|
||||
|
||||
//If have a location hash, then navigate to it now, since the links for
|
||||
//all TOC values have been inserted.
|
||||
hashUpdated();
|
||||
window.addEventListener('hashchange', hashUpdated, false);
|
||||
|
||||
$('body')
|
||||
//Handle the Try links
|
||||
.delegate('.try', 'click', function (evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
//Get the API container
|
||||
var form = $(apiCallNode.cloneNode(true)).appendTo('#play'),
|
||||
params = '',
|
||||
linkParts = evt.target.href.split("#")[1].split(':'),
|
||||
method = toc[linkParts[1]].methods[decodeURIComponent(linkParts[2])],
|
||||
routes = method.routes,
|
||||
apiUrl = routes && routes[0] || '',
|
||||
routeChoices = '';
|
||||
|
||||
//Put the API data structure on the form, for ease of referencing later.
|
||||
form[0].raindropApiMethod = method;
|
||||
|
||||
//If more than one route, give a choice
|
||||
if (routes && routes.length > 1) {
|
||||
routes.forEach(function (route) {
|
||||
routeChoices += '<option value="' + route + '" class="apiUrlChoice">' + route + '</option>';
|
||||
});
|
||||
|
||||
form.find('.apiUrlExpand')
|
||||
.removeClass('hidden')
|
||||
.append(routeChoices);
|
||||
}
|
||||
|
||||
updateApiUrl(form, apiUrl);
|
||||
|
||||
//Request options
|
||||
if (!method.queryargs || !method.queryargs.length) {
|
||||
form.find('.request').addClass('hidden');
|
||||
} else {
|
||||
method.queryargs.forEach(function (arg) {
|
||||
params += '<tr><td class="paramName">' + arg.name + '</td><td class="paramValue">';
|
||||
|
||||
if (arg.allowed) {
|
||||
params += '<select name="' + arg.name + '">' +
|
||||
'<option value=""></option>';
|
||||
|
||||
arg.allowed.forEach(function (value) {
|
||||
params += '<option value="' + value + '">' + value + '</option>';
|
||||
});
|
||||
params += '</select>';
|
||||
} else {
|
||||
params += '<input type="text" name="' + arg.name + '">';
|
||||
}
|
||||
|
||||
params += '</td></tr>';
|
||||
});
|
||||
form.find('.requestParams').html(params);
|
||||
}
|
||||
|
||||
//Request Body
|
||||
if (!method.body) {
|
||||
form.find('.body').addClass('hidden');
|
||||
} else {
|
||||
if (method.examplebody) {
|
||||
form.find('.requestBody').val(method.examplebody);
|
||||
}
|
||||
}
|
||||
//Make sure the new form is visible.
|
||||
play[0].scrollTop = play[0].scrollHeight;
|
||||
|
||||
})
|
||||
.delegate('.apiUrlExpand', 'change', function (evt) {
|
||||
//Update the API URL choice.
|
||||
var item = $(evt.target),
|
||||
url = item.val(),
|
||||
form = item.parents('form').first();
|
||||
|
||||
if (url) {
|
||||
updateApiUrl(form, url);
|
||||
}
|
||||
})
|
||||
.delegate('.urlParam', 'keyup', changeApiUrl)
|
||||
.delegate('.urlParamSelect', 'change', changeApiUrl)
|
||||
//Handle play form submissions.
|
||||
.delegate('.apiCall', 'submit', function (evt) {
|
||||
var form = $(evt.target),
|
||||
method = form[0].raindropApiMethod,
|
||||
inputs = form.find('.requestParams input, .requestParams select'),
|
||||
url = form.find('.apiUrl').html(),
|
||||
editableUrl = form.find('.editApiUrl'),
|
||||
requestBody = form.find('.requestBody').val().trim(),
|
||||
data = {},
|
||||
options, csrfToken;
|
||||
|
||||
evt.preventDefault();
|
||||
|
||||
//If there was a parameterized URL, favor that
|
||||
if (!form.find('.parameterUrl').hasClass('hidden') && editableUrl.length) {
|
||||
url = editableUrl.val().trim();
|
||||
if (url.indexOf('{') !== -1) {
|
||||
alert('Please edit URL parameters to make a valid URL');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Put together the request attributes.
|
||||
inputs.each(function (i, node) {
|
||||
var value = $(node).val();
|
||||
if (value) {
|
||||
data[node.name] = value;
|
||||
}
|
||||
});
|
||||
|
||||
//If a request body, then favor that for the data
|
||||
if (method.body && requestBody) {
|
||||
if (inputs.length) {
|
||||
//Already have some data, need to clear
|
||||
//it out, add it to the URL as query args
|
||||
//to the URL. This is actually a bit goofy,
|
||||
//should just have all query args or all
|
||||
//body args. prefs/set is one API that goes here.
|
||||
url += (url.indexOf('?') === -1 ? '?' : '&') +
|
||||
$.param(data);
|
||||
}
|
||||
|
||||
data = requestBody;
|
||||
}
|
||||
|
||||
|
||||
options = {
|
||||
type: 'POST',
|
||||
url: url,
|
||||
data: data,
|
||||
processData: !method.body,
|
||||
contentType: (method.body ?
|
||||
'application/json; charset=UTF-8' :
|
||||
'application/x-www-form-urlencoded; charset=UTF-8'),
|
||||
success: function (data, textStatus, xhr) {
|
||||
form.find('.output').html(jig.render(jig.cache('jsonResult'), data));
|
||||
},
|
||||
error: function (xhr, textStatus, errorThrown) {
|
||||
form.find('.output').html(jig.render(jig.cache('jsonResult'), {
|
||||
ERROR: xhr.responseText
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
csrfToken = getCsrfToken();
|
||||
if (csrfToken) {
|
||||
options.beforeSend = function (xhr) {
|
||||
xhr.setRequestHeader('X-CSRF', csrfToken);
|
||||
};
|
||||
}
|
||||
|
||||
//Construct the data call.
|
||||
$.ajax(options);
|
||||
})
|
||||
//Handle close action for an API Call form
|
||||
.delegate('form .apiCallClose', 'click', function (evt) {
|
||||
evt.preventDefault();
|
||||
$(evt.target).parents('form').remove();
|
||||
})
|
||||
//Handle expanding and closing of sections in the JSON response
|
||||
//for API calls
|
||||
.delegate('.expander', 'click', function (evt) {
|
||||
var button = $(evt.target),
|
||||
listNode = button.next('ul,ol')[0];
|
||||
if (button.hasClass('closed')) {
|
||||
listNode.style.display = '';
|
||||
button.removeClass('closed');
|
||||
button.html('▼');
|
||||
} else {
|
||||
listNode.style.display = 'none';
|
||||
button.addClass('closed');
|
||||
button.html('►');
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
},
|
||||
error: function (xhr, textStatus, errorThrown) {
|
||||
$('#content').html(jig.htmlEscape(xhr.responseText));
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,2 @@
|
|||
User-agent: *
|
||||
Disallow: /api
|
|
@ -0,0 +1,241 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
/*jslint plusplus: false, indent: 2 */
|
||||
/*global require: false, define: false, window: false, setTimeout: false */
|
||||
"use strict";
|
||||
|
||||
define([ 'jquery', 'blade/object', 'blade/fn', 'module', 'dispatch',
|
||||
'text!AutoCompleteRefresh.html'],
|
||||
function ($, object, fn, module, dispatch,
|
||||
refreshHtml) {
|
||||
|
||||
function split(val) {
|
||||
return val.split(/,\s*/);
|
||||
}
|
||||
|
||||
function extractLast(term) {
|
||||
return split(term).pop();
|
||||
}
|
||||
|
||||
return object(null, null, {
|
||||
className: module.id.replace('/', '-'),
|
||||
|
||||
refreshShowing: false,
|
||||
askRefresh: true,
|
||||
|
||||
init: function (node, contactService) {
|
||||
this.dom = $(node);
|
||||
this.attachedWidget = false;
|
||||
this.acOptions = [];
|
||||
|
||||
// Listen for changes to the contacts.
|
||||
contactService.notify(fn.bind(this, this.attachAutoComplete));
|
||||
|
||||
this.contactService = contactService;
|
||||
|
||||
dispatch.sub('optionsChanged', fn.bind(this, function (data) {
|
||||
// allow refetching contacts when a new page is shared.
|
||||
this.askRefresh = true;
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the formatted autocomplete options and binds the
|
||||
* autocomplete widget, but only on the first call.
|
||||
*/
|
||||
attachAutoComplete: function (contactService, contactList) {
|
||||
contactList = contactList || [];
|
||||
this.acOptions = [];
|
||||
|
||||
// Update the acOptions with formatted contact values.
|
||||
contactList.forEach(fn.bind(this, function (contact) {
|
||||
this.acOptions.push(contactService.formatContact(contact));
|
||||
}));
|
||||
|
||||
if (!this.attachedWidget) {
|
||||
|
||||
this.attachedWidget = true;
|
||||
|
||||
// jQuery UI autocomplete setup from the jQuery UI demo page
|
||||
this.dom
|
||||
// don't navigate away from the field on tab when selecting an item,
|
||||
// or when tabbing to the refresh contacts button.
|
||||
.bind("keydown", fn.bind(this, function (event) {
|
||||
if (event.keyCode === $.ui.keyCode.ENTER) {
|
||||
// Do not submit the form on enter in the autocomplete field.
|
||||
event.preventDefault();
|
||||
} else if (event.keyCode === $.ui.keyCode.TAB) {
|
||||
if (this.dom.data("autocomplete").menu.active) {
|
||||
//autocomplete is up.
|
||||
event.preventDefault();
|
||||
this.dom.autocomplete().select();
|
||||
} else if (this.open) {
|
||||
// select the first item in the autocomplete.
|
||||
var item = this.dom.autocomplete('widget').find('li');
|
||||
this.dom.data("autocomplete").menu.active = item;
|
||||
|
||||
this.dom.autocomplete().select();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// close out the refresh UI immediately so user can see the
|
||||
// rest of the input form.
|
||||
if (this.refreshShowing) {
|
||||
this.hideRefresh();
|
||||
}
|
||||
} else if (event.keyCode === $.ui.keyCode.DOWN && this.refreshShowing) {
|
||||
// refresh contacts showing so focus on the refresh button.
|
||||
event.preventDefault();
|
||||
this.focusingOnRefresh = true;
|
||||
this.refreshDom.find('button').focus();
|
||||
} else if (event.keyCode === $.ui.keyCode.ESCAPE && this.refreshShowing) {
|
||||
this.askRefresh = false;
|
||||
this.hideRefresh();
|
||||
}
|
||||
}))
|
||||
.bind('blur', fn.bind(this, function (event) {
|
||||
// be sure to close down the refresh UI if open, but do it
|
||||
// on a timeout to allow button clicks in the UI. A bit hacky
|
||||
// since it is a timing related thing.
|
||||
if (this.refreshShowing && !this.focusingOnRefresh) {
|
||||
setTimeout(fn.bind(this, function () {
|
||||
this.hideRefresh();
|
||||
this.focusingOnRefresh = false;
|
||||
}), 500);
|
||||
}
|
||||
}))
|
||||
.autocomplete({
|
||||
minLength: 0,
|
||||
source: fn.bind(this, function (request, response) {
|
||||
// delegate back to autocomplete, but extract the last term
|
||||
this.filtered = $.ui.autocomplete.filter(this.acOptions, extractLast(request.term));
|
||||
|
||||
// give the user the option to refresh the contacts
|
||||
// if no matches.
|
||||
if (!this.filtered.length && this.askRefresh) {
|
||||
setTimeout(fn.bind(this, this.showRefresh), 0);
|
||||
} else if (this.refreshShowing) {
|
||||
this.hideRefresh();
|
||||
}
|
||||
|
||||
response(this.filtered);
|
||||
}),
|
||||
focus: function () {
|
||||
// prevent value inserted on focus
|
||||
return false;
|
||||
},
|
||||
select: function (event, ui) {
|
||||
var terms = split(this.value);
|
||||
// remove the current input
|
||||
terms.pop();
|
||||
// add the selected item
|
||||
terms.push(ui.item.value);
|
||||
// add placeholder to get the comma-and-space at the end
|
||||
terms.push("");
|
||||
this.value = terms.join(", ");
|
||||
return false;
|
||||
},
|
||||
open: fn.bind(this, function (event, ui) {
|
||||
// Set the width of the autocomplete once shown.
|
||||
if (!this.relatedWidth) {
|
||||
this.determineRelatedWidth();
|
||||
}
|
||||
this.open = true;
|
||||
this.dom.autocomplete('widget').width(this.relatedWidth);
|
||||
}),
|
||||
close: fn.bind(this, function (event, ui) {
|
||||
this.open = false;
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// account for a previous search waiting on a refresh.
|
||||
if (this.waitingSearch) {
|
||||
this.dom.autocomplete('search', this.waitingSearch);
|
||||
this.dom.focus();
|
||||
delete this.waitingSearch;
|
||||
this.hideSpinner();
|
||||
}
|
||||
},
|
||||
|
||||
determineRelatedWidth: function () {
|
||||
// Make sure to set the size of the autocomplete to not be bigger
|
||||
// than the input area it is bound to.
|
||||
var widthNode = this.dom[0];
|
||||
while (widthNode && (this.relatedWidth = widthNode.getBoundingClientRect().width) <= 0) {
|
||||
widthNode = widthNode.parentNode;
|
||||
}
|
||||
},
|
||||
|
||||
hideRefresh: function () {
|
||||
this.refreshDom.hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows UI to allow refreshing the contacts list.
|
||||
*/
|
||||
showRefresh: function () {
|
||||
if (!this.relatedWidth) {
|
||||
this.determineRelatedWidth();
|
||||
}
|
||||
|
||||
if (!this.refreshDom) {
|
||||
this.refreshDom = $(refreshHtml)
|
||||
.css({
|
||||
width: this.relatedWidth + 'px'
|
||||
})
|
||||
.insertAfter(this.dom[0])
|
||||
.find('button')
|
||||
.bind('click', fn.bind(this, function (evt) {
|
||||
evt.preventDefault();
|
||||
this.waitingSearch = this.dom.val().trim();
|
||||
this.showSpinner();
|
||||
this.askRefresh = false;
|
||||
this.contactService.fetch();
|
||||
this.hideRefresh();
|
||||
}))
|
||||
.bind('blur', fn.bind(this, function (evt) {
|
||||
this.hideRefresh();
|
||||
}))
|
||||
.end();
|
||||
}
|
||||
|
||||
this.refreshDom.show();
|
||||
|
||||
this.refreshShowing = true;
|
||||
},
|
||||
|
||||
hideSpinner: function () {
|
||||
this.spinnerDom.hide();
|
||||
},
|
||||
|
||||
showSpinner: function () {
|
||||
if (!this.spinnerDom) {
|
||||
this.spinnerDom = $('<div class="AutoCompleteSpinner"></div>')
|
||||
.appendTo(this.dom[0].parentNode);
|
||||
}
|
||||
this.spinnerDom.show();
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
<div class="AutoCompleteRefresh">No matches. <button tabindex="-1" class="refresh">Refresh Contacts</button></div>
|
|
@ -0,0 +1,243 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
/*jslint plusplus: false, indent: 2 */
|
||||
/*global require: false, define: false, window: false */
|
||||
"use strict";
|
||||
|
||||
define([ 'jquery', 'blade/object', 'blade/fn', 'dispatch', 'rdapi', 'accounts'],
|
||||
function ($, object, fn, dispatch, rdapi, accounts) {
|
||||
|
||||
var Contacts;
|
||||
|
||||
Contacts = object(null, null, {
|
||||
init: function (svc, svcAccount) {
|
||||
this.svc = svc;
|
||||
this.svcAccount = svcAccount;
|
||||
|
||||
this.callbacks = [];
|
||||
this.lastUpdated = this.fromStore().lastUpdated;
|
||||
// Time check is one day.
|
||||
this.timeCheck = 24 * 60 * 60 * 1000;
|
||||
|
||||
// listen for changes in the options, and if a greater than a day,
|
||||
// refresh the contacts.
|
||||
this.optionsChangeSub = dispatch.sub('optionsChanged', fn.bind(this, function (options) {
|
||||
if (this.needFetch()) {
|
||||
this.fetch();
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroys this instance, not necessarily the data. For that, use
|
||||
* clear().
|
||||
* Used as an opportunity to unbind event listeners.
|
||||
*/
|
||||
destroy: function () {
|
||||
dispatch.unsub('optionsChanged', this.optionsChangeSub);
|
||||
},
|
||||
|
||||
clear: function () {
|
||||
var acct = this.svcAccount;
|
||||
accounts.setData(acct.domain, acct.userid, acct.username, 'contacts');
|
||||
},
|
||||
|
||||
needFetch: function () {
|
||||
return !this.lastUpdated || (new Date()).getTime() - this.lastUpdated > this.timeCheck;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves stored contacts. Should only be used internally or by subclasses.
|
||||
*/
|
||||
fromStore: function () {
|
||||
var acct = this.svcAccount;
|
||||
return accounts.getData(acct.domain, acct.userid, acct.username, 'contacts') || {};
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves contacts to storage. Should only be used internally or by
|
||||
* subclasses.
|
||||
*
|
||||
* @param {Object} data an object with a "list" property which is this
|
||||
* list of contacts to store.
|
||||
*/
|
||||
toStore: function (data) {
|
||||
var acct = this.svcAccount;
|
||||
|
||||
if (!data.lastUpdated) {
|
||||
data.lastUpdated = this.lastUpdated;
|
||||
}
|
||||
|
||||
accounts.setData(acct.domain, acct.userid, acct.username, 'contacts', data);
|
||||
|
||||
this.notifyCallbacks();
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Includes any new names from a successful share into the autocomplete.
|
||||
* By default, it does nothing, but subclasses may do something with it.
|
||||
* @param {String} contactsText a comma-separated string of contacts that
|
||||
* follow the format returned from findContact().
|
||||
*/
|
||||
incorporate: function (contactsText) {
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify about changes to the autocomplete list. Can be async, so callback is needed.
|
||||
* @param {Function} callback called when contacts are available.
|
||||
* It will receive an array of contacts.
|
||||
*/
|
||||
notify: function (callback) {
|
||||
this.callbacks.push(callback);
|
||||
this.contacts = this.fromStore().list;
|
||||
|
||||
if (!this.contacts || this.needFetch()) {
|
||||
this.fetch();
|
||||
} else {
|
||||
this.notifyCallbacks();
|
||||
}
|
||||
},
|
||||
|
||||
fetch: function () {
|
||||
var acct = this.svcAccount,
|
||||
svcData = accounts.getService(acct.domain, acct.userid, acct.username);
|
||||
|
||||
rdapi('contacts/' + acct.domain, {
|
||||
type: 'POST',
|
||||
data: {
|
||||
username: acct.username,
|
||||
userid: acct.userid,
|
||||
startindex: 0,
|
||||
maxresults: 500,
|
||||
account: JSON.stringify(svcData)
|
||||
},
|
||||
//Only wait for 10 seconds, then give up.
|
||||
timeout: 10000,
|
||||
success: fn.bind(this, function (json) {
|
||||
//Transform data to a form usable by the front end.
|
||||
if (json && !json.error) {
|
||||
var entries = json.result.entry;
|
||||
|
||||
this.contacts = this.getFormattedContacts(entries);
|
||||
this.lastUpdated = (new Date()).getTime();
|
||||
|
||||
this.toStore({
|
||||
list: this.contacts
|
||||
});
|
||||
}
|
||||
}),
|
||||
error: fn.bind(this, function (xhr, textStatus, errorThrown) {
|
||||
// does not matter what the error is, just eat it and hide
|
||||
// the UI showing a wait.
|
||||
this.notifyCallbacks();
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
notifyCallbacks: function () {
|
||||
this.callbacks.forEach(fn.bind(this, function (callback) {
|
||||
callback(this, this.contacts);
|
||||
}));
|
||||
},
|
||||
|
||||
findContact: function (to) {
|
||||
var contactId = to;
|
||||
|
||||
(this.contacts || []).some(function (contact) {
|
||||
if (contact.displayName === to) {
|
||||
contactId = contact.email || contact.userid || contact.username;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
return contactId;
|
||||
},
|
||||
|
||||
/**
|
||||
* Translates contact data from server into a format used on the client.
|
||||
* @param {Array} entries
|
||||
* @returns {Array}
|
||||
*/
|
||||
getFormattedContacts: function (entries) {
|
||||
var data = [];
|
||||
entries.forEach(function (entry) {
|
||||
if (entry.accounts && entry.accounts.length) {
|
||||
entry.accounts.forEach(function (account) {
|
||||
data.push({
|
||||
displayName: entry.displayName,
|
||||
email: '',
|
||||
userid: account.userid,
|
||||
username: account.username
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts a string that was created by formatContact to real IDs
|
||||
* understood by the back-end API calls.
|
||||
*
|
||||
* @param {String} toText a comma-separated list of contacts.
|
||||
* @returns {String} a comma-separated list of ID-based contacts.
|
||||
*/
|
||||
convert: function (toText) {
|
||||
var newrecip = [],
|
||||
result = '',
|
||||
recip;
|
||||
|
||||
if (this.contacts) {
|
||||
recip = toText.split(',');
|
||||
recip.forEach(fn.bind(this, function (to) {
|
||||
var contactId = this.findContact(to.trim());
|
||||
if (contactId) {
|
||||
newrecip.push(contactId);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if (newrecip.length > 0) {
|
||||
result = newrecip.join(', ');
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Formats the contact for display, such as for use in an autocomplete.
|
||||
* Overridden by Contact overlays.
|
||||
*/
|
||||
formatContact: function (contact) {
|
||||
return contact.displayName;
|
||||
}
|
||||
});
|
||||
|
||||
Contacts.modelVersion = '3';
|
||||
|
||||
return Contacts;
|
||||
});
|
|
@ -0,0 +1,133 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
/*jslint indent: 2, regexp: false */
|
||||
/*global define: false */
|
||||
"use strict";
|
||||
|
||||
define([ 'blade/object', 'Contacts', 'jquery', 'accounts', 'blade/fn'],
|
||||
function (object, Contacts, $, accounts, fn) {
|
||||
|
||||
var bracketRegExp = /<([^>])+>/;
|
||||
|
||||
/**
|
||||
* Overrides the formatting of contacts and converting
|
||||
* one of those formatted contacts into a user ID.
|
||||
*/
|
||||
return object(Contacts, null, function (parent) {
|
||||
return {
|
||||
formatContact: function (contact) {
|
||||
var value = contact.displayName;
|
||||
if (contact.email !== value) {
|
||||
value += ' <' + contact.email + '>';
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
findContact: function (to) {
|
||||
return to;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if a to string is already in the contacts array.
|
||||
* @param {String} to a plain email address (no name).
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
contains: function (to) {
|
||||
return this.contacts.some(function (contact) {
|
||||
return contact.email === to;
|
||||
});
|
||||
},
|
||||
|
||||
incorporate: function (contactsText) {
|
||||
var acct = this.svcAccount,
|
||||
newContacts = [],
|
||||
storedContacts,
|
||||
contacts = contactsText.split(',');
|
||||
|
||||
contacts.forEach(fn.bind(this, function (contact) {
|
||||
contact = contact.trim();
|
||||
|
||||
var match = bracketRegExp.exec(contact);
|
||||
|
||||
contact = (match && match[1]) || contact;
|
||||
|
||||
if (!this.contains(contact)) {
|
||||
newContacts.push({
|
||||
displayName: contact,
|
||||
email: contact
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
if (newContacts.length) {
|
||||
// update storage of manually entered contacts.
|
||||
storedContacts = accounts.getData(acct.domain,
|
||||
acct.userid,
|
||||
acct.username,
|
||||
'enteredContacts') || [];
|
||||
|
||||
storedContacts = storedContacts.concat(newContacts);
|
||||
accounts.setData(acct.domain, acct.userid, acct.username,
|
||||
'enteredContacts', storedContacts);
|
||||
|
||||
// update the master merged list of contacts.
|
||||
this.contacts = this.contacts.concat(newContacts);
|
||||
this.toStore({
|
||||
list: this.contacts
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
getFormattedContacts: function (entries) {
|
||||
var data = [],
|
||||
acct = this.svcAccount,
|
||||
storedContacts = accounts.getData(acct.domain,
|
||||
acct.userid,
|
||||
acct.username,
|
||||
'enteredContacts');
|
||||
|
||||
// convert server data to the right format.
|
||||
entries.forEach(function (entry) {
|
||||
if (entry.emails && entry.emails.length) {
|
||||
entry.emails.forEach(function (email) {
|
||||
var displayName = entry.displayName ? entry.displayName : email.value;
|
||||
data.push({
|
||||
displayName: displayName,
|
||||
email: email.value
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// add in any manually saved email addresses.
|
||||
if (storedContacts) {
|
||||
data = data.concat(storedContacts);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
|
@ -0,0 +1,61 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
/*jslint indent: 2 */
|
||||
/*global define: false */
|
||||
"use strict";
|
||||
|
||||
define([ 'blade/object', 'Contacts', 'jquery'],
|
||||
function (object, Contacts, $) {
|
||||
var idRegExp = /\@(\S+)/;
|
||||
|
||||
/**
|
||||
* Overrides the formatting of contacts and converting
|
||||
* one of those formatted contacts into a user ID.
|
||||
*/
|
||||
return object(Contacts, null, function (parent) {
|
||||
return {
|
||||
formatContact: function (contact) {
|
||||
var value = '@' + contact.username;
|
||||
return value;
|
||||
},
|
||||
|
||||
findContact: function (to) {
|
||||
var match = idRegExp.exec(to),
|
||||
value = '',
|
||||
name = (match && match[1]) || to;
|
||||
if (name) {
|
||||
(this.contacts || []).some(function (contact) {
|
||||
if (contact.username === name) {
|
||||
value = contact.userid;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
|
@ -0,0 +1,83 @@
|
|||
@charset "UTF-8";
|
||||
|
||||
/* TODO: some of these styles, like text sizing/box sizing and colors/borders
|
||||
need to be set in the app that includes a Select widget. */
|
||||
.Select {
|
||||
position:relative;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
padding-right: 15px;
|
||||
z-index: 100;
|
||||
border: 1px solid #A6AFB6;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15) inset;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.Select.open {
|
||||
overflow: visible;
|
||||
padding-right: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.Select ul {
|
||||
list-style: none;
|
||||
z-index: 100;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.Select.open ul {
|
||||
position: absolute;
|
||||
border: 1px solid gray;
|
||||
}
|
||||
|
||||
.Select li {
|
||||
display: none;
|
||||
height: 0;
|
||||
padding: 0 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.Select li.selected {
|
||||
display: block;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.Select.open li {
|
||||
display: block;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.Select.open li.selected {
|
||||
/* background-color: grey; */
|
||||
}
|
||||
|
||||
.Select.open li.selected:hover,
|
||||
.Select.open li:hover {
|
||||
color:white;
|
||||
background-color: #535F6D;
|
||||
}
|
||||
|
||||
.Select .triangle {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 18px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
padding: 0 2px;
|
||||
z-index: 101;
|
||||
color: #A6AFB6;
|
||||
background-color: white;
|
||||
background-image: url("/share/i/sprite.png");
|
||||
background-position: center -362px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.Select.open .triangle {
|
||||
display: none;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<div class="{className}">
|
||||
<input type="hidden" name="{name}" value="{value}">
|
||||
<ul>
|
||||
{options [}
|
||||
<li data-value="{value}">{name}</li>
|
||||
{]}
|
||||
</ul>
|
||||
<div class="triangle"></div>
|
||||
</div>
|
|
@ -0,0 +1,206 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
/*jslint indent: 2, */
|
||||
/*global define: false, document: false */
|
||||
"use strict";
|
||||
|
||||
define([ 'blade/object', 'blade/Widget', 'blade/array', 'jquery', 'module',
|
||||
'text!./Select.html', 'text!./Select.css'],
|
||||
function (object, Widget, array, $, module,
|
||||
template, css) {
|
||||
|
||||
var className = module.id.replace(/\//g, '-'),
|
||||
style = document.createElement('style'),
|
||||
openSelect;
|
||||
|
||||
//Add the css to that page.
|
||||
style.type = 'text/css';
|
||||
//If class name is changed since this is an anonymous module, update the
|
||||
//CSS classes.
|
||||
if (className !== 'Select') {
|
||||
css = css.replace(/\.Select/g, '.' + className);
|
||||
}
|
||||
style.textContent = css;
|
||||
document.getElementsByTagName('head')[0].appendChild(style);
|
||||
|
||||
//Set up event handlers.
|
||||
$(function () {
|
||||
$('body')
|
||||
.delegate('.' + className + ' .triangle', 'click', function (evt) {
|
||||
Widget.closest(module.id, evt, 'onTriangleClick');
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
})
|
||||
.delegate('.' + className + ' li', 'click', function (evt) {
|
||||
Widget.closest(module.id, evt, 'onOptionClick');
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
});
|
||||
|
||||
$(document).bind('click', function (evt) {
|
||||
if (openSelect) {
|
||||
openSelect.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Define the widget.
|
||||
* This widget assumes its member variables include the following
|
||||
* properties (passed in on create of the widget)
|
||||
*
|
||||
* @param {Array} options: the options to show, with each option being
|
||||
* an object with "name" and "value" properties.
|
||||
* @param {String} name: the name to use for the form field.
|
||||
* @param {Number} selectedIndex: the index of the options that should
|
||||
* be selected.
|
||||
*/
|
||||
return object(Widget, null, function (parent) {
|
||||
return {
|
||||
moduleId: module.id,
|
||||
className: className,
|
||||
|
||||
template: template,
|
||||
|
||||
onCreate: function () {
|
||||
if (this.value) {
|
||||
var index, value = this.value;
|
||||
// Find the matching index for the value.
|
||||
this.options.some(function (item, i) {
|
||||
if (item.value === value) {
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this.selectedIndex = index;
|
||||
} else {
|
||||
// No default value, work it out via selectedIndex if available.
|
||||
this.selectedIndex = this.selectedIndex || 0;
|
||||
this.value = this.options[this.selectedIndex].value;
|
||||
}
|
||||
},
|
||||
|
||||
onRender: function () {
|
||||
this.dom = $(this.node);
|
||||
|
||||
//Apply selected style.
|
||||
$('li', this.node).eq(this.selectedIndex).addClass('selected');
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
delete this.dom;
|
||||
parent(this, "destroy", arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Selects an item based on its index.
|
||||
*/
|
||||
selectIndex: function (index) {
|
||||
return this.val(this.options[index].value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get or set the value for the select. Uses the value for the option.
|
||||
*/
|
||||
val: function (newValue) {
|
||||
if (newValue === undefined) {
|
||||
// Get
|
||||
return $('li.selected', this.node)[0].getAttribute('data-value');
|
||||
} else {
|
||||
// Set the value.
|
||||
var liNode, ulNode, index;
|
||||
|
||||
// Find the li node that corresponds with the value.
|
||||
array.to.apply(null, $('li', this.dom)).some(function (node, i) {
|
||||
if (node.getAttribute('data-value') === newValue) {
|
||||
liNode = node;
|
||||
index = i;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
this.selectedIndex = index;
|
||||
|
||||
ulNode = liNode.parentNode;
|
||||
|
||||
// Find the index.
|
||||
this.selectedIndex = array.to.apply(null, $('li', ulNode)).indexOf(liNode);
|
||||
|
||||
// Make sure the right node has the selected class
|
||||
$('li', ulNode).removeClass('selected');
|
||||
$(liNode).addClass('selected');
|
||||
|
||||
this.close();
|
||||
|
||||
this.dom.trigger('change');
|
||||
|
||||
return newValue;
|
||||
}
|
||||
},
|
||||
|
||||
close: function () {
|
||||
var liNode = $('li.selected', this.node)[0];
|
||||
|
||||
// Put the value in the hidden input
|
||||
$('input', this.node).val(liNode.getAttribute('data-value'));
|
||||
|
||||
// Remove the open class.
|
||||
this.dom.removeClass('open');
|
||||
|
||||
// Remove the artificial width
|
||||
this.node.style.width = '';
|
||||
},
|
||||
|
||||
open: function () {
|
||||
if (openSelect) {
|
||||
openSelect.close();
|
||||
}
|
||||
|
||||
// Since the options will position absolute, give the Select
|
||||
// width so that surrounding content does not collapse around it.
|
||||
this.node.style.width = this.node.getBoundingClientRect().width + 'px';
|
||||
|
||||
this.dom.addClass('open');
|
||||
openSelect = this;
|
||||
},
|
||||
|
||||
onTriangleClick: function (evt) {
|
||||
this.open();
|
||||
},
|
||||
|
||||
onOptionClick: function (evt) {
|
||||
// Open the options if not already open.
|
||||
if (!this.dom.hasClass('open')) {
|
||||
this.open();
|
||||
return;
|
||||
}
|
||||
|
||||
this.val(evt.target.getAttribute('data-value'));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,67 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
/*jslint plusplus: false */
|
||||
/*global require: false, define: false */
|
||||
"use strict";
|
||||
|
||||
define([ 'jquery', 'blade/object', 'blade/fn'],
|
||||
function ($, object, fn) {
|
||||
|
||||
return object(null, null, {
|
||||
init: function (node, countNode, limit) {
|
||||
this.dom = $(node);
|
||||
this.domPlaceholderText = this.dom[0].getAttribute('placeholder') || '';
|
||||
this.countDom = $(countNode);
|
||||
this.limit = limit;
|
||||
this.dom.bind('keyup', fn.bind(this, 'checkCount'));
|
||||
this.checkCount();
|
||||
},
|
||||
|
||||
checkCount: function () {
|
||||
var value = this.dom[0].value,
|
||||
count;
|
||||
|
||||
if (value.trim() === this.domPlaceholderText) {
|
||||
value = '';
|
||||
}
|
||||
|
||||
count = this.limit - value.length;
|
||||
if (count < 0) {
|
||||
this.countDom.addClass("TextCountOver");
|
||||
} else {
|
||||
this.countDom.removeClass("TextCountOver");
|
||||
}
|
||||
this.countDom.text(count === this.limit ? '' : count);
|
||||
},
|
||||
|
||||
updateLimit: function (limit) {
|
||||
this.limit = limit;
|
||||
this.checkCount();
|
||||
},
|
||||
|
||||
isOver: function () {
|
||||
return this.dom[0].value.length > this.limit;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,404 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
/*jslint indent: 2, plusplus: false */
|
||||
/*global require: false, define: false, window: false, location: true,
|
||||
localStorage: false, opener: false, setTimeout: false */
|
||||
'use strict';
|
||||
|
||||
define([ 'storage', 'dispatch', 'rdapi', 'services'],
|
||||
function (storage, dispatch, rdapi, services) {
|
||||
|
||||
function isCacheMatch(cache, domain, userid, username) {
|
||||
return cache.domain === domain &&
|
||||
((userid && cache.userid === userid) ||
|
||||
(username && cache.username === username));
|
||||
}
|
||||
|
||||
function fromJson(value) {
|
||||
if (value) {
|
||||
value = JSON.parse(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
var store = storage(), impl,
|
||||
changeTypes = {
|
||||
//localStorage is the most robust, since the change in localStorage
|
||||
//can be listened to across windows.
|
||||
|
||||
'localStorage': {
|
||||
|
||||
accounts: function (ok, error) {
|
||||
// accounts now simply provides existing accounts retreived during
|
||||
// the oauth dances
|
||||
var accountCache = fromJson(store.accountCache) || [],
|
||||
serviceCache = fromJson(store.serviceCache);
|
||||
|
||||
if (!serviceCache) {
|
||||
// fetch now, let the response call ok
|
||||
// Set up serviceCache. This should only ever happen
|
||||
// if the local store is cleared (e.g. first run, cleared cookies)
|
||||
impl.fetch(ok, error);
|
||||
return;
|
||||
}
|
||||
|
||||
serviceCache = serviceCache || [];
|
||||
|
||||
//Call ok callback with current knowledge. If there is a change in the
|
||||
//account info, then the fetch will trigger changed event later.
|
||||
if (ok) {
|
||||
ok(accountCache, serviceCache);
|
||||
}
|
||||
},
|
||||
|
||||
update: function (account_data) {
|
||||
// XXX TODO
|
||||
// get the account and push it into localstore, don't overwrite, we
|
||||
// get one account at a time here
|
||||
// We write into accountCache to have account.fetch continue to work.
|
||||
// We also write into serviceCache which will be used by api calls
|
||||
// to send the auth keys
|
||||
var accountCache = fromJson(store.accountCache) || [],
|
||||
serviceCache = fromJson(store.serviceCache),
|
||||
existing = false,
|
||||
profile, p, a, acct;
|
||||
|
||||
// move the profile into accountCache
|
||||
profile = account_data.profile;
|
||||
for (p = 0; p < accountCache.length; p++) {
|
||||
acct = accountCache[p].accounts[0];
|
||||
if (isCacheMatch(acct, account_data.domain, account_data.userid,
|
||||
account_data.username)) {
|
||||
accountCache[p] = profile;
|
||||
existing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!existing) {
|
||||
accountCache.push(profile);
|
||||
}
|
||||
store.accountCache = JSON.stringify(accountCache);
|
||||
|
||||
// we store the entire object in serviceCache, at some point in the
|
||||
// future we will remove accountCache
|
||||
if (serviceCache) {
|
||||
existing = false;
|
||||
for (a = 0; a < serviceCache.length; a++) {
|
||||
if (isCacheMatch(serviceCache[a], account_data.domain,
|
||||
account_data.userid, account_data.username)) {
|
||||
serviceCache[a] = account_data;
|
||||
existing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
serviceCache = [];
|
||||
}
|
||||
if (!existing) {
|
||||
serviceCache.push(account_data);
|
||||
}
|
||||
store.serviceCache = JSON.stringify(serviceCache);
|
||||
impl.changed();
|
||||
},
|
||||
|
||||
// remove this once there is time enough for all users
|
||||
// to have been migrated over to the new cache.
|
||||
fetch: function (ok, error) {
|
||||
rdapi('account/get/full', {
|
||||
success: function (json) {
|
||||
if (json.error) {
|
||||
json = [];
|
||||
}
|
||||
|
||||
store.serviceCache = JSON.stringify(json);
|
||||
var accountCache = [], svc, p;
|
||||
for (p = 0; p < json.length; p++) {
|
||||
accountCache.push(json[p].profile);
|
||||
|
||||
// clear the contacts cache
|
||||
// remove this clearCache call when 3.6 is removed.
|
||||
svc = services.domains[json[p].domain];
|
||||
svc.clearCache(store);
|
||||
}
|
||||
store.accountCache = JSON.stringify(accountCache);
|
||||
if (ok) {
|
||||
ok(accountCache, json);
|
||||
}
|
||||
},
|
||||
error: error || function () {}
|
||||
});
|
||||
},
|
||||
|
||||
remove: function (domain, userid, username) {
|
||||
var accountCache = fromJson(store.accountCache),
|
||||
serviceCache = fromJson(store.serviceCache),
|
||||
i, cache, a, p, s, svc;
|
||||
|
||||
if (serviceCache) {
|
||||
for (i = 0; (cache = serviceCache[i]); i++) {
|
||||
if (isCacheMatch(cache, domain, userid, username)) {
|
||||
serviceCache.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
store.serviceCache = JSON.stringify(serviceCache);
|
||||
}
|
||||
|
||||
// eventually we will deprecate accountCache
|
||||
if (accountCache) {
|
||||
for (p = 0; p < accountCache.length; p++) {
|
||||
s = accountCache[p].accounts;
|
||||
for (a = 0; a < s.length; a++) {
|
||||
if (isCacheMatch(s[a], domain, userid, username)) {
|
||||
accountCache.splice(p, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
store.accountCache = JSON.stringify(accountCache);
|
||||
}
|
||||
|
||||
// clear the contacts cache
|
||||
svc = services.domains[domain];
|
||||
|
||||
// remove this clearCache call when 3.6 is removed.
|
||||
svc.clearCache(store);
|
||||
|
||||
// Delete auxillary data.
|
||||
impl.clearData(domain, userid, username);
|
||||
|
||||
impl.changed();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set auxillary data related to an account. Deleted when the account
|
||||
* is deleted.
|
||||
*/
|
||||
setData: function (domain, userid, username, name, value) {
|
||||
var key = [domain, userid, username].join('|') + 'Data',
|
||||
data = fromJson(store[key]) || {};
|
||||
|
||||
if (value === undefined || value === null) {
|
||||
delete data[name];
|
||||
} else {
|
||||
data[name] = value;
|
||||
}
|
||||
|
||||
store[key] = JSON.stringify(data);
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get auxillary data related to an account.
|
||||
*/
|
||||
getData: function (domain, userid, username, name) {
|
||||
var key = [domain, userid, username].join('|') + 'Data',
|
||||
data = fromJson(store[key]) || {};
|
||||
|
||||
return data ? data[name] : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears auxillary data related to an account. Deleted when the account
|
||||
* is deleted.
|
||||
*/
|
||||
clearData: function (domain, userid, username) {
|
||||
var key = [domain, userid, username].join('|') + 'Data';
|
||||
delete store[key];
|
||||
},
|
||||
|
||||
getService: function (domain, userid, username) {
|
||||
var serviceCache = fromJson(store.serviceCache),
|
||||
i, cache;
|
||||
|
||||
if (serviceCache) {
|
||||
for (i = 0; (cache = serviceCache[i]); i++) {
|
||||
if (isCacheMatch(cache, domain, userid, username)) {
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
changed: function () {
|
||||
store.accountChanged = (new Date()).getTime();
|
||||
//Force the onchange events to occur. Sometimes the storage
|
||||
//events do not fire?
|
||||
if (opener && !opener.closed) {
|
||||
dispatch.pub('accountsChanged', null, opener);
|
||||
}
|
||||
dispatch.pub('accountsChanged');
|
||||
},
|
||||
|
||||
onChange: function (action) {
|
||||
//Listen to storage changes, and if a the accountChanged key
|
||||
//changes, refresh.
|
||||
var lastValue = store.accountChanged;
|
||||
window.addEventListener('storage', function (evt) {
|
||||
//Only refresh if the accounts were changed.
|
||||
if (store.accountChanged !== lastValue) {
|
||||
action();
|
||||
}
|
||||
}, false);
|
||||
//Also use direct notification in case storage events fail.
|
||||
dispatch.sub('accountsChanged', action);
|
||||
}
|
||||
},
|
||||
//Some extensions mess with localStorage, so in that case, fall back to
|
||||
//using dispatching.
|
||||
'memory': {
|
||||
|
||||
accounts: function (ok, error) {
|
||||
},
|
||||
|
||||
changed: function () {
|
||||
//Use dispatching. Dispatch to current window, but also to an opener
|
||||
//if available.
|
||||
store.accountChanged = (new Date()).getTime();
|
||||
|
||||
if (opener) {
|
||||
dispatch.pub('accountsChanged', null, opener);
|
||||
}
|
||||
dispatch.pub('accountsChanged');
|
||||
},
|
||||
|
||||
onChange: function (action) {
|
||||
dispatch.sub('accountsChanged', action);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
impl = changeTypes[storage.type];
|
||||
|
||||
/**
|
||||
* Gets the accounts. Can use a cached value.
|
||||
* @param {Function} ok function to receive the account info.
|
||||
* @param {Function} error function to call if an error.
|
||||
*/
|
||||
function accounts(ok, error) {
|
||||
return impl.accounts(ok, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the accounts from a json account object.
|
||||
* @param {Object} cookie object to update from
|
||||
*/
|
||||
accounts.update = function (account_data) {
|
||||
impl.update(account_data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an accounts from storage.
|
||||
* @param {string} domain
|
||||
* @param {string} userid
|
||||
* @param {string} username
|
||||
*/
|
||||
accounts.remove = function (account, userid, username) {
|
||||
impl.remove(account, userid, username);
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch accounts stored on server.
|
||||
* DEPRECATED, interim use for auto-adding accounts that
|
||||
* users have already configured
|
||||
*/
|
||||
accounts.fetch = function (ok, error) {
|
||||
impl.fetch(ok, error);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a full service account record
|
||||
* @param {string} domain
|
||||
* @param {string} userid
|
||||
* @param {string} username
|
||||
*/
|
||||
accounts.getService = function (account, userid, username) {
|
||||
return impl.getService(account, userid, username);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the account data. Use this when it is known that the server
|
||||
* info is no longer valid/expired.
|
||||
*/
|
||||
accounts.clear = function () {
|
||||
delete store.accountCache;
|
||||
delete store.serviceCache;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets auxillary data associated with an account.
|
||||
* @param {string} domain
|
||||
* @param {string} userid
|
||||
* @param {string} username
|
||||
*/
|
||||
accounts.setData = function (account, userid, username, name, value) {
|
||||
return impl.setData(account, userid, username, name, value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets auxillary data associated with an account.
|
||||
* @param {string} domain
|
||||
* @param {string} userid
|
||||
* @param {string} username
|
||||
*/
|
||||
accounts.getData = function (account, userid, username, name) {
|
||||
return impl.getData(account, userid, username, name);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets auxillary data associated with an account.
|
||||
* @param {string} domain
|
||||
* @param {string} userid
|
||||
* @param {string} username
|
||||
*/
|
||||
accounts.clearData = function (account, userid, username) {
|
||||
return impl.clearData(account, userid, username);
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the cache of accounts has changed.
|
||||
*/
|
||||
accounts.changed = function () {
|
||||
return impl.changed();
|
||||
};
|
||||
|
||||
/**
|
||||
* Default action is to just reload.
|
||||
*/
|
||||
function defaultAction() {
|
||||
location.reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to set up the action when accounts change.
|
||||
* Call it with no args to get the default behavior, page reload.
|
||||
*/
|
||||
accounts.onChange = function (action) {
|
||||
return impl.onChange(action || defaultAction);
|
||||
};
|
||||
|
||||
return accounts;
|
||||
});
|
|
@ -0,0 +1,147 @@
|
|||
/**
|
||||
* @license blade/Widget Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
|
||||
* Available via the MIT, GPL or new BSD license.
|
||||
* see: http://github.com/jrburke/blade for details
|
||||
*/
|
||||
/*jslint plusplus: false, nomen: false */
|
||||
/*global define: false, document */
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Parts of this taken from Dojo, in particular DOM work related to
|
||||
* dojo._toDom()
|
||||
*/
|
||||
|
||||
define([ 'require', './object', './jig', 'module'],
|
||||
function (require, object, jig, module) {
|
||||
|
||||
var tempNode,
|
||||
baseAttrName = 'data-' + module.id.replace(/\//g, '-') + '-' +
|
||||
(Math.random() + '').replace(/\d\./, ''),
|
||||
typeAttr = baseAttrName + '-wtype',
|
||||
idAttr = baseAttrName + '-wid',
|
||||
idCounter = 0,
|
||||
registry = {},
|
||||
|
||||
Widget = object(null, null, {
|
||||
template: null,
|
||||
/**
|
||||
* Creates a new instance. Should be called by any derived objects.
|
||||
* data can have some special properties:
|
||||
* parent: the parent node to
|
||||
*
|
||||
*/
|
||||
init: function (data, relNode, position) {
|
||||
object.mixin(this, data, true);
|
||||
|
||||
//Start widget lifecycle
|
||||
if (this.onCreate) {
|
||||
this.onCreate();
|
||||
}
|
||||
|
||||
if (this.template) {
|
||||
this.node = this.render();
|
||||
if (this.onRender) {
|
||||
this.onRender(relNode);
|
||||
}
|
||||
}
|
||||
|
||||
if (relNode && this.node) {
|
||||
if (position === 'before') {
|
||||
relNode.parentNode.insertBefore(this.node, relNode);
|
||||
} else if (position === 'after') {
|
||||
relNode.parentNode.insertBefore(this.node, relNode.nextSibling);
|
||||
} else if (position === 'prepend' && relNode.firstChild) {
|
||||
relNode.insertBefore(this.node, relNode.firstChild);
|
||||
} else {
|
||||
relNode.appendChild(this.node);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render: function (relativeNode) {
|
||||
var doc, child, renderedNode, id;
|
||||
if (this.template) {
|
||||
//Normalize template by trimming whitespace.
|
||||
this.template = this.template.trim();
|
||||
|
||||
doc = relativeNode && relativeNode.ownerDocument || document;
|
||||
id = 'id' + idCounter++;
|
||||
|
||||
//Set up a temp node to hold template
|
||||
if (!tempNode || tempNode.ownerDocument !== doc) {
|
||||
tempNode = doc.createElement('div');
|
||||
}
|
||||
|
||||
tempNode.innerHTML = this.templatize();
|
||||
|
||||
// one node shortcut => return the node itself
|
||||
if (tempNode.childNodes.length === 1) {
|
||||
renderedNode = tempNode.removeChild(tempNode.firstChild);
|
||||
renderedNode.setAttribute(idAttr, id);
|
||||
renderedNode.setAttribute(typeAttr, this.moduleId);
|
||||
} else {
|
||||
// return multiple nodes as a document fragment
|
||||
renderedNode = doc.createDocumentFragment();
|
||||
while ((child = tempNode.firstChild)) {
|
||||
renderedNode.appendChild(child);
|
||||
if (child.nodeType === 1) {
|
||||
child.setAttribute(idAttr, id);
|
||||
child.setAttribute(typeAttr, this.moduleId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._widgetId = id;
|
||||
registry[id] = this;
|
||||
}
|
||||
|
||||
return renderedNode;
|
||||
},
|
||||
|
||||
templatize: function () {
|
||||
var text = this.template,
|
||||
cache = jig.cache(text) || jig.cache(text, text, this.jigOptions);
|
||||
|
||||
return jig.render(cache, this, this.jigOptions);
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroys the widget. Derived objects should call this method
|
||||
* after they do their destroy work. destroy is a nice time to
|
||||
* clean up event handlers.
|
||||
*/
|
||||
destroy: function () {
|
||||
if (this.node && this.node.parentNode) {
|
||||
this.node.parentNode.removeChild(this.node);
|
||||
}
|
||||
delete this.node;
|
||||
delete registry[this._widgetId];
|
||||
}
|
||||
});
|
||||
|
||||
Widget.closest = function (widgetType, evt, funcName) {
|
||||
var refNode = evt.target,
|
||||
widget;
|
||||
|
||||
//Walk up the list of nodes until a match with the type is found.
|
||||
while (refNode) {
|
||||
if (refNode.getAttribute(typeAttr) === widgetType) {
|
||||
break;
|
||||
}
|
||||
refNode = refNode.parentNode;
|
||||
}
|
||||
|
||||
if (refNode) {
|
||||
widget = registry[refNode.getAttribute(idAttr)];
|
||||
if (widget) {
|
||||
widget[funcName](evt);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Widget.registry = registry;
|
||||
|
||||
return Widget;
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* @license blade/array Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
|
||||
* Available via the MIT, GPL or new BSD license.
|
||||
* see: http://github.com/jrburke/blade for details
|
||||
*/
|
||||
/*jslint nomen: false, plusplus: false */
|
||||
/*global define: false */
|
||||
|
||||
'use strict';
|
||||
|
||||
define([], function () {
|
||||
var ostring = Object.prototype.toString,
|
||||
ap = Array.prototype,
|
||||
aps = ap.slice,
|
||||
|
||||
array = {
|
||||
/**
|
||||
* Determines if the input a function.
|
||||
* @param {Object} it whatever you want to test to see if it is a function.
|
||||
* @returns Boolean
|
||||
*/
|
||||
is: function (it) {
|
||||
return ostring.call(it) === "[object Array]";
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts an array-like thing into a real array
|
||||
* @param{ArrayLike} arrayLike something that looks like an array,
|
||||
* has a length and can access members via indices.
|
||||
* @returns {Array}
|
||||
*/
|
||||
to: function (arrayLike) {
|
||||
return [].concat(aps.call(arguments, 0));
|
||||
}
|
||||
};
|
||||
|
||||
return array;
|
||||
});
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* @license blade/defer Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
|
||||
* Available via the MIT, GPL or new BSD license.
|
||||
* see: http://github.com/jrburke/blade for details
|
||||
*/
|
||||
/*jslint nomen: false, plusplus: false */
|
||||
/*global define: false */
|
||||
|
||||
'use strict';
|
||||
|
||||
define(['./fn', './dispatch'], function (fn, bladeDispatch) {
|
||||
|
||||
/**
|
||||
* Creates an object representing a deferred action.
|
||||
* @param {Function} [onCancel] optional function to call if the deferred
|
||||
* action is canceled
|
||||
* @param {Array} otherEventNames an array of event names to also allow
|
||||
* sending and notifying on this type of deferred action. This allows you
|
||||
* to express more complex interactions besides something that just indicates
|
||||
* "ok", "error" or "cancel".
|
||||
* @returns {Object} object representing the deferred action. It contains
|
||||
* two properties:
|
||||
* send: a function to send events. It takes a string name for the event,
|
||||
* "ok", "error" or "cancel", and a value.
|
||||
* listener: an object that only exposes an "ok", "error" and "cancel"
|
||||
* functions that allow listening to those respective events. If otherEventNames
|
||||
* specified other events, then there are listener registration functions
|
||||
* for those event names too.
|
||||
*/
|
||||
function defer(onCancel, otherEventNames) {
|
||||
var dfd = {},
|
||||
sentName, i, evtName,
|
||||
dispatch = bladeDispatch.make(),
|
||||
makeCb = function (name) {
|
||||
return function (obj, f) {
|
||||
var cb = fn.bind(obj, f);
|
||||
dispatch.onAfter(name, function (evt) {
|
||||
return cb(evt.returnValue);
|
||||
}, true);
|
||||
return dfd.listener;
|
||||
};
|
||||
};
|
||||
|
||||
//Set up the cancellation action if desired.
|
||||
if (onCancel) {
|
||||
dispatch.onAfter('cancel', function (evt) {
|
||||
return onCancel();
|
||||
});
|
||||
}
|
||||
|
||||
dfd.send = function (name, value) {
|
||||
//Do not allow sending more than one message for the deferred.
|
||||
if (sentName) {
|
||||
throw new Error('blade/defer object already sent event: ' + sentName);
|
||||
}
|
||||
sentName = name;
|
||||
|
||||
dispatch.send({
|
||||
name: name,
|
||||
args: [value],
|
||||
persist: true
|
||||
});
|
||||
|
||||
//If no error handlers on this deferred, be sure to at least
|
||||
//log it to allow some sort of debugging.
|
||||
if (name === 'error' &&
|
||||
(!dispatch._dispatchAfterQ || ! dispatch._dispatchAfterQ.error) &&
|
||||
defer.onErrorDefault) {
|
||||
defer.onErrorDefault(value);
|
||||
}
|
||||
|
||||
return dfd;
|
||||
};
|
||||
|
||||
dfd.listener = {
|
||||
ok: makeCb('ok'),
|
||||
error: makeCb('error'),
|
||||
cancel: makeCb('cancel')
|
||||
};
|
||||
|
||||
//Allow wiring up other event names
|
||||
if (otherEventNames) {
|
||||
for (i = 0; (evtName = otherEventNames[i]); i++) {
|
||||
dfd.listener[evtName] = makeCb[evtName];
|
||||
}
|
||||
}
|
||||
|
||||
return dfd;
|
||||
}
|
||||
|
||||
defer.onErrorDefault = function (err) {
|
||||
throw err;
|
||||
};
|
||||
|
||||
return defer;
|
||||
});
|
|
@ -0,0 +1,227 @@
|
|||
/**
|
||||
* @license blade/dispatch Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
|
||||
* Available via the MIT, GPL or new BSD license.
|
||||
* see: http://github.com/jrburke/blade for details
|
||||
*/
|
||||
/*jslint nomen: false, plusplus: false */
|
||||
/*global define: false */
|
||||
|
||||
'use strict';
|
||||
|
||||
define(['./object', './fn'], function (object, fn) {
|
||||
var emptyFunc = function () {},
|
||||
mainDispatch,
|
||||
slice = Array.prototype.slice,
|
||||
|
||||
needBind = function (f) {
|
||||
return f !== undefined && (typeof f === 'string' || fn.is(f));
|
||||
},
|
||||
|
||||
register = function (type) {
|
||||
return function (name, obj, f) {
|
||||
//Adjust args to allow for a bind call
|
||||
if (needBind(f)) {
|
||||
f = fn.bind(obj, f);
|
||||
} else {
|
||||
f = obj;
|
||||
}
|
||||
|
||||
var qName = type,
|
||||
typeQ = this[qName] || (this[qName] = {}),
|
||||
q = typeQ[name] || (typeQ[name] = []), index;
|
||||
|
||||
index = q.push(f) - 1;
|
||||
q.count = q.count ? q.count + 1 : 1;
|
||||
|
||||
//Return an unregister function to allow removing
|
||||
//a listener. Notice that it can make the q array sparsely
|
||||
//populated. This should be a sparsely populated array
|
||||
//to allow a callback to unregister itself without affecting
|
||||
//other callbacks in the array.
|
||||
return function () {
|
||||
q[index] = null;
|
||||
q.count -= 1;
|
||||
if (q.count === 0) {
|
||||
delete typeQ[name];
|
||||
}
|
||||
|
||||
//Clean up closure references for good measure/avoid leaks.
|
||||
qName = typeQ = q = null;
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
onAfter = register('_dispatchAfterQ'),
|
||||
|
||||
/**
|
||||
* Defines the dispatch object. You can call its methods for a general
|
||||
* publish/subscribe mechanism, or mixin its prototype properties
|
||||
* to another object to give that object dispatch capabilities.
|
||||
*/
|
||||
dispatch = {
|
||||
on: register('_dispatchBeforeQ'),
|
||||
onAfter: function (name, obj, f, wantValue) {
|
||||
var doBind = needBind(f), result, value, callback, evt;
|
||||
//Adjust args if needing a bind
|
||||
if (doBind) {
|
||||
callback = f = fn.bind(obj, f);
|
||||
} else {
|
||||
wantValue = f;
|
||||
callback = obj;
|
||||
}
|
||||
|
||||
result = doBind ? onAfter.call(this, name, f, wantValue) : onAfter.call(this, name, obj, f);
|
||||
if (wantValue) {
|
||||
//value is the property on the object, unless it is something
|
||||
//that should be immutable or does not exist, then only get a value from _dispatchPersisted
|
||||
value = name in this ? this[name] :
|
||||
(this._dispatchPersisted && name in this._dispatchPersisted ? this._dispatchPersisted[name] : undefined);
|
||||
evt = {
|
||||
preventDefault: emptyFunc,
|
||||
stopPropagation: emptyFunc,
|
||||
returnValue: value
|
||||
};
|
||||
|
||||
if (value !== undefined) {
|
||||
callback(evt);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sends an event. An event can have its values modified by "before"
|
||||
* listeners before the default action happens. A "before" listener
|
||||
* can also prevent the default action from occurring. "after" listeners
|
||||
* only get to be notified of the return value from the event.
|
||||
*
|
||||
* @param {Object||String} message the message can either be an object
|
||||
* with the following properties:
|
||||
* @param {String} message.name the name of the message
|
||||
* @param {Array} message.args the array of arguments for the message
|
||||
* @param {Boolean}message.persist the result of the send should be
|
||||
* remembered, so that any subsequent listeners that listen after
|
||||
* the result is rememberd can opt to get the last good value.
|
||||
* @param {Function} [message.defaultAction] a default action to take
|
||||
* if any of the "before" listeners do not call preventDefault()
|
||||
* on the event object they receive.
|
||||
*
|
||||
* If message is a string, then that is like the "name" property mentioned
|
||||
* above, and any additional function arguments are treated as the
|
||||
* args array.
|
||||
*
|
||||
* If defaultAction is not passed, then the default action will be to
|
||||
* either set the property value on this object that matches the name
|
||||
* to the first arg value, or if the name maps to function property
|
||||
* on the object, it will call that function with the args.
|
||||
*
|
||||
* @returns {Object} the returnValue from any
|
||||
*/
|
||||
send: function (message) {
|
||||
if (typeof message === 'string') {
|
||||
//Normalize message to object arg form.
|
||||
message = {
|
||||
name: message,
|
||||
args: slice.call(arguments, 1)
|
||||
};
|
||||
}
|
||||
|
||||
var name = message.name,
|
||||
beforeQ = this._dispatchBeforeQ && this._dispatchBeforeQ[name],
|
||||
afterQ = this._dispatchAfterQ && this._dispatchAfterQ[name],
|
||||
preventDefault = false, stopImmediatePropagation,
|
||||
evt = {
|
||||
preventDefault: function () {
|
||||
preventDefault = true;
|
||||
},
|
||||
stopImmediatePropagation: function () {
|
||||
stopImmediatePropagation = true;
|
||||
},
|
||||
args: message.args
|
||||
},
|
||||
i, result, value, args, isFunc, persisted;
|
||||
|
||||
//Trigger before listeners
|
||||
if (beforeQ) {
|
||||
for (i = 0; i < beforeQ.length; i++) {
|
||||
//array can be sparse because of unregister functions
|
||||
if (beforeQ[i]) {
|
||||
beforeQ[i](evt);
|
||||
if (stopImmediatePropagation) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//If a before handler prevents the default action, exit
|
||||
//early, using any return value found in the event that may
|
||||
//have been set by a before handler.
|
||||
if (preventDefault) {
|
||||
return evt.returnValue;
|
||||
}
|
||||
|
||||
//Do the default action.
|
||||
if (message.defaultAction) {
|
||||
result = message.defaultAction.apply(this, evt.args);
|
||||
} else {
|
||||
//Only bother if the property already exists on the object,
|
||||
//otherwise it is a catch all or just an event router
|
||||
args = evt.args;
|
||||
if (name in this) {
|
||||
isFunc = fn.is(this[name]);
|
||||
value = this[name];
|
||||
|
||||
if (args && args.length) {
|
||||
//A set operation
|
||||
result = isFunc ? value.apply(this, args) : this[name] = args[0];
|
||||
} else {
|
||||
//A get operation
|
||||
result = isFunc ? this[name]() : value;
|
||||
}
|
||||
} else if (this._dispatchCatchAll) {
|
||||
//Allow the catch all to get it.
|
||||
result = this._dispatchCatchAll(name, args);
|
||||
} else {
|
||||
result = args && args[0];
|
||||
}
|
||||
}
|
||||
|
||||
//Trigger mutable after listeners first, before the immutable ones
|
||||
//to allow the mutable ones to modify the result.
|
||||
if (afterQ) {
|
||||
stopImmediatePropagation = false;
|
||||
evt.returnValue = result;
|
||||
for (i = 0; i < afterQ.length; i++) {
|
||||
//array can be sparse because of unregister functions
|
||||
if (afterQ[i]) {
|
||||
afterQ[i](evt);
|
||||
if (stopImmediatePropagation) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
result = evt.returnValue;
|
||||
}
|
||||
|
||||
//Hold on to the result if need be. Useful for the deferred/promise
|
||||
//cases where listeners can be added after the deferred completes.
|
||||
if (message.persist) {
|
||||
persisted = this._dispatchPersisted || (this._dispatchPersisted = {});
|
||||
persisted[message.name] = result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
//Create a top level dispatch that can be used for "global" event routing,
|
||||
//and which can make new dispatch objects that have all the methods above,
|
||||
//but without the instance variables.
|
||||
mainDispatch = object.create(dispatch);
|
||||
mainDispatch.make = function () {
|
||||
return object.create(dispatch);
|
||||
};
|
||||
|
||||
return mainDispatch;
|
||||
});
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* @license blade/func Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
|
||||
* Available via the MIT, GPL or new BSD license.
|
||||
* see: http://github.com/jrburke/blade for details
|
||||
*/
|
||||
/*jslint nomen: false, plusplus: false */
|
||||
/*global define: false */
|
||||
|
||||
'use strict';
|
||||
|
||||
define([], function () {
|
||||
var slice = Array.prototype.slice,
|
||||
ostring = Object.prototype.toString,
|
||||
|
||||
fn = {
|
||||
/**
|
||||
* Determines if the input a function.
|
||||
* @param {Object} it whatever you want to test to see if it is a function.
|
||||
* @returns Boolean
|
||||
*/
|
||||
is: function (it) {
|
||||
return ostring.call(it) === '[object Function]';
|
||||
},
|
||||
|
||||
/**
|
||||
* Different from Function.prototype.bind in ES5 --
|
||||
* it has the "this" argument listed first. This is generally
|
||||
* more readable, since the "this" object is visible before
|
||||
* the function body, reducing chances for error by missing it.
|
||||
* If only obj has a real value then obj will be returned,
|
||||
* allowing this method to be called even if you are not aware
|
||||
* of the format of the obj and f types.
|
||||
* It also allows the function to be a string name, in which case,
|
||||
* obj[f] is used to find the function.
|
||||
* @param {Object||Function} obj the "this" object, or a function.
|
||||
* @param {Function||String} f the function of function name that
|
||||
* should be called with obj set as the "this" value.
|
||||
* @returns {Function}
|
||||
*/
|
||||
bind: function (obj, f) {
|
||||
//Do not bother if
|
||||
if (!f) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
//Make sure we have a function
|
||||
if (typeof f === 'string') {
|
||||
f = obj[f];
|
||||
}
|
||||
var args = slice.call(arguments, 2);
|
||||
return function () {
|
||||
return f.apply(obj, args.concat(slice.call(arguments, 0)));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
return fn;
|
||||
});
|
|
@ -0,0 +1,858 @@
|
|||
/**
|
||||
* @license blade/jig Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
|
||||
* Available via the MIT, GPL or new BSD license.
|
||||
* see: http://github.com/jrburke/blade for details
|
||||
*/
|
||||
/*jslint nomen: false, plusplus: false */
|
||||
/*global define: false, document: false, console: false, jQuery: false */
|
||||
|
||||
'use strict';
|
||||
|
||||
define(['require', './object'], function (require, object) {
|
||||
|
||||
//Fix unit test: something is wrong with it, says it passes, but
|
||||
//with attachData change, the string is actually different now.
|
||||
//TODO: for attachData, only generate a new ID when the data value changes,
|
||||
//and similarly, only attach the data one time per data value.
|
||||
|
||||
//If have <img class="contactPhoto" src="{foo}"> browser tries to fetch
|
||||
//{foo} if that is in markup. Doing a <{/}img, then FF browser treats that
|
||||
//as <{/}img. Using <img{/} ends up with <img{ }="" in text.
|
||||
|
||||
var jig, commands,
|
||||
ostring = Object.prototype.toString,
|
||||
decode = typeof decodeURIComponent === 'undefined' ? function () {} : decodeURIComponent,
|
||||
startToken = '{',
|
||||
endToken = '}',
|
||||
rawHtmlToken = '^',
|
||||
templateRefToken = '#',
|
||||
argSeparator = ' ',
|
||||
//First character in an action cannot be something that
|
||||
//could be the start of a regular JS property name,
|
||||
//or an array indice indicator, [, or the HTML raw output
|
||||
//indicator, ^.
|
||||
propertyRegExp = /[_\[\^\w]/,
|
||||
defaultArg = '_',
|
||||
startTagRegExp = /<\s*\w+/,
|
||||
wordRegExp = /^\d+$/,
|
||||
badCommentRegExp = /\/(\/)?\s*\]/,
|
||||
templateCache = {},
|
||||
defaultFuncs = {
|
||||
openCurly: function () {
|
||||
return '{';
|
||||
},
|
||||
closeCurly: function () {
|
||||
return '}';
|
||||
},
|
||||
eq: function (a, b) {
|
||||
return a === b;
|
||||
},
|
||||
gt: function (a, b) {
|
||||
return a > b;
|
||||
},
|
||||
gte: function (a, b) {
|
||||
return a >= b;
|
||||
},
|
||||
lt: function (a, b) {
|
||||
return a < b;
|
||||
},
|
||||
lte: function (a, b) {
|
||||
return a <= b;
|
||||
},
|
||||
or: function (a, b) {
|
||||
return a || b;
|
||||
},
|
||||
and: function (a, b) {
|
||||
return a && b;
|
||||
},
|
||||
is: function (a) {
|
||||
return !!a;
|
||||
},
|
||||
eachProp: function (obj) {
|
||||
//Converts object properties into an array
|
||||
//of objects that have 'prop' and 'value' properties.
|
||||
var prop, ret = [];
|
||||
for (prop in obj) {
|
||||
if (obj.hasOwnProperty(prop)) {
|
||||
ret.push({
|
||||
prop: prop,
|
||||
value: obj[prop]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//Sort the names to be roughly alphabetic
|
||||
return ret.sort(function (a, b) {
|
||||
return a.prop > b.prop ? 1 : -1;
|
||||
});
|
||||
}
|
||||
},
|
||||
attachData = false,
|
||||
dataIdCounter = 1,
|
||||
controlIdCounter = 1,
|
||||
dataRegistry = {},
|
||||
tempNode = typeof document !== 'undefined' && document.createElement ?
|
||||
document.createElement('div') : null,
|
||||
templateClassRegExp = /(\s*)(template)(\s*)/;
|
||||
|
||||
function isArray(it) {
|
||||
return ostring.call(it) === '[object Array]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a property from a context object. Allows for an alternative topContext
|
||||
* object that can be used for the first part property lookup if it is not
|
||||
* found in context first.
|
||||
* @param {Array} parts the list of nested properties to look up on a context.
|
||||
* @param {Object} context the context to start the property lookup
|
||||
* @param {Object} [topContext] an object to use as an alternate context
|
||||
* for the very first part property to look up if it is not found in context.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function getProp(parts, context, topContext) {
|
||||
var obj = context, i, p;
|
||||
for (i = 0; obj && (p = parts[i]); i++) {
|
||||
obj = (typeof obj === 'object' && p in obj ? obj[p] : (topContext && i === 0 && p in topContext ? topContext[p] : undefined));
|
||||
}
|
||||
return obj; // mixed
|
||||
}
|
||||
|
||||
function strToInt(value) {
|
||||
return value ? parseInt(value, 10) : 0;
|
||||
}
|
||||
|
||||
function getObject(name, data, options) {
|
||||
var brackRegExp = /\[([\w0-9\.'":]+)\]/,
|
||||
part = name,
|
||||
parent = data,
|
||||
isTop = true,
|
||||
match, pre, prop, obj, startIndex, endIndex, indices, result,
|
||||
parenStart, parenEnd, func, funcName, arg, args, i, firstChar;
|
||||
|
||||
//If asking for the default arg it means giving back the current data.
|
||||
if (name === defaultArg) {
|
||||
return data;
|
||||
}
|
||||
|
||||
//If name is just an integer, just return it.
|
||||
if (wordRegExp.test(name)) {
|
||||
return strToInt(name);
|
||||
}
|
||||
|
||||
//An empty string is just returned.
|
||||
if (name === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
//If the name looks like a string, just return that.
|
||||
firstChar = name.charAt(0);
|
||||
if (firstChar === "'" || firstChar === "'") {
|
||||
return name.substring(1, name.length - 1);
|
||||
}
|
||||
|
||||
//First check for function call. Function must be globally visible.
|
||||
if ((parenStart = name.indexOf('(')) !== -1) {
|
||||
parenEnd = name.lastIndexOf(')');
|
||||
funcName = name.substring(0, parenStart);
|
||||
func = options.fn[funcName];
|
||||
if (!func) {
|
||||
jig.error('Cannot find function named: ' + funcName + ' for ' + name);
|
||||
return '';
|
||||
}
|
||||
arg = name.substring(parenStart + 1, parenEnd);
|
||||
if (arg.indexOf(',') !== -1) {
|
||||
args = arg.split(',');
|
||||
for (i = args.length - 1; i >= 0; i--) {
|
||||
args[i] = getObject(args[i], data, options);
|
||||
}
|
||||
result = func.apply(null, args);
|
||||
} else {
|
||||
result = func(getObject(arg, data, options));
|
||||
}
|
||||
if (parenEnd < name.length - 1) {
|
||||
//More data properties after the function call, fetch them
|
||||
//If the part after the paren is a dot, then skip over that part
|
||||
if (name.charAt(parenEnd + 1) === '.') {
|
||||
parenEnd += 1;
|
||||
}
|
||||
return getObject(name.substring(parenEnd + 1, name.length), result, options);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
//Now handle regular object references, which could have [] notation.
|
||||
while ((match = brackRegExp.exec(part))) {
|
||||
prop = match[1].replace(/['"]/g, '');
|
||||
pre = part.substring(0, match.index);
|
||||
|
||||
part = part.substring(match.index + match[0].length, part.length);
|
||||
if (part.indexOf('.') === 0) {
|
||||
part = part.substring(1, part.length);
|
||||
}
|
||||
|
||||
obj = getProp(pre.split('.'), parent, isTop ? options.context : null);
|
||||
isTop = false;
|
||||
|
||||
if (!obj && prop) {
|
||||
jig.error('blade/jig: No property "' + prop + '" on ' + obj);
|
||||
return '';
|
||||
}
|
||||
|
||||
if (prop.indexOf(':') !== -1) {
|
||||
//An array slice action
|
||||
indices = prop.split(':');
|
||||
startIndex = strToInt(indices[0]);
|
||||
endIndex = strToInt(indices[1]);
|
||||
|
||||
if (!endIndex) {
|
||||
obj = obj.slice(startIndex);
|
||||
} else {
|
||||
obj = obj.slice(startIndex, endIndex);
|
||||
}
|
||||
} else {
|
||||
if (options.strict && !(prop in obj)) {
|
||||
jig.error('blade/jig: no property "' + prop + '"');
|
||||
}
|
||||
obj = obj[prop];
|
||||
}
|
||||
parent = obj;
|
||||
}
|
||||
|
||||
if (!part) {
|
||||
result = parent;
|
||||
} else {
|
||||
result = getProp(part.split('.'), parent, isTop ? options.context : null);
|
||||
}
|
||||
|
||||
if (options.strict && result === undefined) {
|
||||
jig.error('blade/jig: undefined value for property "' + name + '"');
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a compiled template based on the template ID. Will look in the
|
||||
* DOM for an element with that ID if a template is not found already in
|
||||
* the compiled cache.
|
||||
* @param {String} id the ID of the template/DOM node
|
||||
* @param {Object} [options]
|
||||
*
|
||||
* @returns {Array} the compiled template.
|
||||
*/
|
||||
function compiledById(id, options) {
|
||||
options = options || {};
|
||||
var compiled = jig.cache(id, options), node;
|
||||
|
||||
//Did not find the text template. Maybe it is a DOM element.
|
||||
if (compiled === undefined && typeof document !== 'undefined') {
|
||||
node = document.getElementById(id);
|
||||
if (node) {
|
||||
jig.parse([node], options);
|
||||
}
|
||||
compiled = jig.cache(id, options);
|
||||
}
|
||||
if (compiled === undefined) {
|
||||
throw new Error('blade/jig: no template or node with ID: ' + id);
|
||||
}
|
||||
return compiled;
|
||||
}
|
||||
|
||||
commands = {
|
||||
'_default_': {
|
||||
doc: 'Property reference',
|
||||
action: function (args, data, options, children, render) {
|
||||
var value = args[0] ? getObject(args[0], data, options) : data,
|
||||
comparison = args[1] ? getObject(args[1], data, options) : undefined,
|
||||
i, text = '';
|
||||
|
||||
//If comparing to some other value, then the value is the data,
|
||||
//and need to compute if the values compare.
|
||||
if (args[1]) {
|
||||
comparison = value === comparison;
|
||||
value = data;
|
||||
} else {
|
||||
//Just use the value, so the value is used in the comparison.
|
||||
comparison = value;
|
||||
}
|
||||
//Want to allow returning 0 for values, so this next check is
|
||||
//a bit verbose.
|
||||
if (comparison === false || comparison === null ||
|
||||
comparison === undefined || (isArray(comparison) && !comparison.length)) {
|
||||
return '';
|
||||
} else if (children) {
|
||||
if (isArray(value)) {
|
||||
for (i = 0; i < value.length; i++) {
|
||||
text += render(children, value[i], options);
|
||||
}
|
||||
} else {
|
||||
//If the value is true or false, then just use parent data.
|
||||
//for the child rendering.
|
||||
if (typeof value === 'boolean') {
|
||||
value = data;
|
||||
}
|
||||
text = render(children, value, options);
|
||||
}
|
||||
} else {
|
||||
text = value;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
},
|
||||
'!': {
|
||||
doc: 'Not',
|
||||
action: function (args, data, options, children, render) {
|
||||
var value = getObject(args[0], data, options),
|
||||
comparison = args[1] ? getObject(args[1], data, options) : undefined;
|
||||
|
||||
//If comparing to some other value, then the value is the data,
|
||||
//and need to compute if the values compare.
|
||||
if (args[1]) {
|
||||
comparison = value === comparison;
|
||||
value = data;
|
||||
} else {
|
||||
//Just use the value, so the value is used in the comparison.
|
||||
comparison = value;
|
||||
}
|
||||
|
||||
if (children && !comparison) {
|
||||
return render(children, data, options);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
},
|
||||
'#': {
|
||||
doc: 'Template reference',
|
||||
action: function (args, data, options, children, render) {
|
||||
var compiled = compiledById(args[0], options);
|
||||
data = getObject(args.length > 1 ? args[1] : defaultArg, data, options);
|
||||
return render(compiled, data, options);
|
||||
}
|
||||
},
|
||||
'.': {
|
||||
doc: 'Variable declaration',
|
||||
action: function (args, data, options, children, render) {
|
||||
options.context[args[0]] = getObject(args[1], data, options);
|
||||
//TODO: allow definining a variable then doing a block with
|
||||
//that variable.
|
||||
return '';
|
||||
}
|
||||
},
|
||||
'>': {
|
||||
doc: 'Else',
|
||||
action: function (args, data, options, children, render) {
|
||||
if (children) {
|
||||
return render(children, data, options);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
jig = function (text, data, options) {
|
||||
var id;
|
||||
if (typeof text === 'string') {
|
||||
if (text.charAt(0) === '#') {
|
||||
//a lookup by template ID
|
||||
id = text.substring(1, text.length);
|
||||
text = compiledById(id, options);
|
||||
} else {
|
||||
text = jig.compile(text, options);
|
||||
}
|
||||
}
|
||||
return jig.render(text, data, options);
|
||||
};
|
||||
|
||||
jig.htmlEscape = function (text) {
|
||||
return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
};
|
||||
|
||||
function compile(text, options) {
|
||||
var compiled = [],
|
||||
start = 0,
|
||||
useRawHtml = false,
|
||||
controlId = 0,
|
||||
segment, index, match, tag, command, args, lastArg, lastChar,
|
||||
children, i, tempTag;
|
||||
|
||||
while ((index = text.indexOf(options.startToken, start)) !== -1) {
|
||||
//Output any string that is before the template tag start
|
||||
if (index !== start) {
|
||||
compiled.push(text.substring(start, index));
|
||||
}
|
||||
|
||||
//Find the end of the token
|
||||
segment = text.substring(index);
|
||||
match = options.endRegExp.exec(segment);
|
||||
if (!match) {
|
||||
//Just a loose start thing could be a regular punctuation.
|
||||
compiled.push(segment);
|
||||
return compiled;
|
||||
} else {
|
||||
//Command Match!
|
||||
|
||||
//Increment start past the match.
|
||||
start = index + match[0].length;
|
||||
|
||||
//Pull out the command
|
||||
tag = text.substring(index + options.startToken.length, index + match[0].length - options.endToken.length).trim();
|
||||
|
||||
//decode in case the value was in an URL field, like an href or an img src attribute
|
||||
tag = decode(tag);
|
||||
|
||||
//if the command is commented out end block call, that messes with stuff,
|
||||
//just throw to let the user know, otherwise browser can lock up.
|
||||
if (badCommentRegExp.test(tag)) {
|
||||
throw new Error('blade/jig: end block tags should not be commented: ' + tag);
|
||||
}
|
||||
|
||||
command = tag.charAt(0);
|
||||
|
||||
if (command === ']' && controlId) {
|
||||
//In a control block, previous block was a related control block,
|
||||
//so parse it without the starting ] character.
|
||||
tempTag = tag.substring(1).trim();
|
||||
if (tempTag === '[') {
|
||||
command = '>';
|
||||
} else {
|
||||
command = tempTag.charAt(0);
|
||||
//Remove the starting ] so it is seen as a regular tag
|
||||
tag = tempTag;
|
||||
}
|
||||
}
|
||||
|
||||
if (command && !options.propertyRegExp.test(command)) {
|
||||
//Have a template command
|
||||
tag = tag.substring(1).trim();
|
||||
} else {
|
||||
command = '_default_';
|
||||
//Command could contain just the raw HTML indicator.
|
||||
useRawHtml = (command === options.rawHtmlToken);
|
||||
}
|
||||
|
||||
//Allow for raw HTML output, but it is not the default.
|
||||
//template references use raw by default though.
|
||||
if ((useRawHtml = tag.indexOf(options.rawHtmlToken) === 0)) {
|
||||
tag = tag.substring(options.rawHtmlToken.length, tag.length);
|
||||
}
|
||||
//However, template references use raw always
|
||||
if (command === templateRefToken) {
|
||||
useRawHtml = true;
|
||||
}
|
||||
|
||||
args = tag.split(options.argSeparator);
|
||||
lastArg = args[args.length - 1];
|
||||
lastChar = lastArg.charAt(lastArg.length - 1);
|
||||
children = null;
|
||||
|
||||
if (command === ']') {
|
||||
//If there are no other args, this is an end tag, to close
|
||||
//out a block and possibly a set of control blocks.
|
||||
if (lastChar !== '[') {
|
||||
//End of a block. End the recursion, let the parent know
|
||||
//the place where parsing stopped.
|
||||
compiled.templateEnd = start;
|
||||
|
||||
//Also end of a control section, indicate it as such.
|
||||
compiled.endControl = true;
|
||||
} else {
|
||||
//End of a block. End the recursion, let the parent know
|
||||
//the place where parsing stopped, before this end tag,
|
||||
//so it can process it and match it to a control flow
|
||||
//from previous control tag.
|
||||
compiled.templateEnd = start - match[0].length;
|
||||
}
|
||||
|
||||
return compiled;
|
||||
} else if (lastChar === '[') {
|
||||
//If last arg ends with a [ it means a block element.
|
||||
|
||||
//Assign a new control section ID if one is not in play already
|
||||
if (!controlId) {
|
||||
controlId = controlIdCounter++;
|
||||
}
|
||||
|
||||
//Adjust the last arg to not have the block character.
|
||||
args[args.length - 1] = lastArg.substring(0, lastArg.length - 1);
|
||||
|
||||
//Process the block
|
||||
children = compile(text.substring(start), options);
|
||||
|
||||
//Skip the part of the string that is part of the child compile.
|
||||
start += children.templateEnd;
|
||||
}
|
||||
|
||||
//If this defines a template, save it off,
|
||||
//if a comment (starts with /), then ignore it.
|
||||
if (command === '+') {
|
||||
options.templates[args[0]] = children;
|
||||
} else if (command !== '/') {
|
||||
//Adjust args if some end in commas, it means they are function
|
||||
//args.
|
||||
if (args.length > 1) {
|
||||
for (i = args.length - 1; i >= 0; i--) {
|
||||
if (args[i].charAt(args[i].length - 1) === ',') {
|
||||
args[i] = args[i] + args[i + 1];
|
||||
args.splice(i + 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compiled.push({
|
||||
action: options.commands[command].action,
|
||||
useRawHtml: useRawHtml,
|
||||
args: args,
|
||||
controlId: controlId,
|
||||
children: children
|
||||
});
|
||||
}
|
||||
|
||||
//If the end of a block, clear the control ID
|
||||
if (children && children.endControl) {
|
||||
controlId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (start !== text.length - 1) {
|
||||
compiled.push(text.substring(start, text.length));
|
||||
}
|
||||
|
||||
return compiled;
|
||||
}
|
||||
|
||||
jig.compile = function (text, options) {
|
||||
//Mix in defaults
|
||||
options = options || {};
|
||||
object.mixin(options, {
|
||||
startToken: startToken,
|
||||
endToken: endToken,
|
||||
rawHtmlToken: rawHtmlToken,
|
||||
propertyRegExp: propertyRegExp,
|
||||
commands: commands,
|
||||
argSeparator: argSeparator,
|
||||
templates: templateCache
|
||||
});
|
||||
|
||||
options.endRegExp = new RegExp('[^\\r\\n]*?' + endToken);
|
||||
|
||||
//Do some reset to avoid a number from getting too big.
|
||||
controlIdCounter = 1;
|
||||
|
||||
return compile(text, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a node to a compiled template, and will store it in the cache. If already
|
||||
* in the cache, it will give back the cached value.
|
||||
*/
|
||||
function nodeToCompiled(node, options) {
|
||||
var text, compiled, clss,
|
||||
id = node.id,
|
||||
cache = options.templates || templateCache;
|
||||
|
||||
//If the nodes has already been cached, then just get the cached value.
|
||||
if (cache[id]) {
|
||||
return cache[id];
|
||||
}
|
||||
|
||||
//Call listener to allow processing of the node before
|
||||
//template complication happens.
|
||||
if (options.onBeforeParse) {
|
||||
options.onBeforeParse(node);
|
||||
}
|
||||
|
||||
if (node.nodeName.toUpperCase() === 'SCRIPT') {
|
||||
text = node.text.trim();
|
||||
if (node.parentNode) {
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
} else {
|
||||
//Put node in temp node to get the innerHTML so node's element
|
||||
//html is in the output.
|
||||
tempNode.appendChild(node);
|
||||
|
||||
//Remove the id node and the template class, since this
|
||||
//template text could be duplicated many times, and a
|
||||
//template class is no longer useful.
|
||||
node.removeAttribute('id');
|
||||
clss = (node.getAttribute('class') || '').trim();
|
||||
if (clss) {
|
||||
node.setAttribute('class', clss.replace(templateClassRegExp, '$1$3'));
|
||||
}
|
||||
|
||||
//Decode braces when may get URL encoded as part of hyperlinks
|
||||
text = tempNode.innerHTML.replace(/%7B/g, '{').replace(/%7D/g, '}');
|
||||
|
||||
//Clear out the temp node for the next use.
|
||||
tempNode.removeChild(node);
|
||||
}
|
||||
compiled = jig.compile(text, options);
|
||||
jig.cache(id, compiled, options);
|
||||
return compiled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an HTML document for templates, compiles them, and stores them
|
||||
* in a cache of templates to use on the page. Only useful in browser environments.
|
||||
* Script tags with type="text/template" are parsed, as well as DOM elements
|
||||
* that have a class of "template" on them. The found nodes will be removed
|
||||
* from the DOM as part of the parse operation.
|
||||
*
|
||||
* @param {Array-Like} [nodes] An array-like list of nodes. Could be a NodeList.
|
||||
* @param {Object} [options] A collection of options to use for compilation.
|
||||
*/
|
||||
jig.parse = function (nodes, options) {
|
||||
//Allow nodes to not be passed in, but still have options.
|
||||
if (nodes && !nodes.length) {
|
||||
options = nodes;
|
||||
nodes = null;
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
nodes = nodes || document.querySelectorAll('.template, script[type="text/template"]');
|
||||
|
||||
var node, i;
|
||||
|
||||
for (i = nodes.length - 1; i > -1 && (node = nodes[i]); i--) {
|
||||
nodeToCompiled(node, options);
|
||||
}
|
||||
};
|
||||
|
||||
function render(compiled, data, options) {
|
||||
var text = '', i, dataId, controlId, currentControlId, currentValue, lastValue;
|
||||
if (typeof compiled === 'string') {
|
||||
text = compiled;
|
||||
} else if (isArray(compiled)) {
|
||||
for (i = 0; i < compiled.length; i++) {
|
||||
//Account for control blocks (if/elseif/else)
|
||||
//control blocks all have the same control ID, so only call the next
|
||||
//control block if the first one did not return a value.
|
||||
currentControlId = compiled[i].controlId;
|
||||
if (!currentControlId || currentControlId !== controlId || !lastValue) {
|
||||
currentValue = render(compiled[i], data, options);
|
||||
text += currentValue;
|
||||
if (currentControlId) {
|
||||
controlId = currentControlId;
|
||||
lastValue = currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//A template command to run.
|
||||
text = compiled.action(compiled.args, data, options, compiled.children, render);
|
||||
if (!text) {
|
||||
text = '';
|
||||
} else if (!compiled.useRawHtml && !compiled.children) {
|
||||
//Only html escape commands that are not block actions.
|
||||
text = jig.htmlEscape(text.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (options.attachData) {
|
||||
if (startTagRegExp.test(text)) {
|
||||
dataId = 'id' + (dataIdCounter++);
|
||||
text = text.replace(startTagRegExp, '$& data-blade-jig="' + dataId + '" ');
|
||||
dataRegistry[dataId] = data;
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a compiled template.
|
||||
*
|
||||
* @param {Array} compiled a compiled template
|
||||
* @param {Object} data the data to use in the template
|
||||
* @param {Object} options options for rendering. They include:
|
||||
* @param {Object} templates a cache of compiled templates that might be
|
||||
* referenced by the primary template
|
||||
* @param {Object} options.fn a set of functions that might be used
|
||||
* by the template(s). Each property on this object is a name of a function
|
||||
* that may show up in the templates, and the value should be the function
|
||||
* definition.
|
||||
* @returns {String} the rendered template.
|
||||
*/
|
||||
jig.render = function (compiled, data, options) {
|
||||
var i, result = '';
|
||||
|
||||
//Normalize options, filling in defaults.
|
||||
options = options || {};
|
||||
object.mixin(options, {
|
||||
templates: templateCache,
|
||||
attachData: attachData,
|
||||
strict: jig.strict
|
||||
});
|
||||
|
||||
//Mix in default functions
|
||||
if (options.fn) {
|
||||
object.mixin(options.fn, defaultFuncs);
|
||||
} else {
|
||||
options.fn = defaultFuncs;
|
||||
}
|
||||
|
||||
//Mix in top level context object
|
||||
options.context = options.context || object.create(data);
|
||||
|
||||
//If data is an array, then render should be called for each item
|
||||
//in the array.
|
||||
if (isArray(data)) {
|
||||
for (i = 0; i < data.length; i++) {
|
||||
result += render(compiled, data[i], options);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//Default case, just render
|
||||
return render(compiled, data, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable strict template rendering checks. If a property does not exist on a
|
||||
* data object, then an error will be logged.
|
||||
*/
|
||||
jig.strict = false;
|
||||
|
||||
/**
|
||||
* Track errors by logging to console if available.
|
||||
*/
|
||||
jig.error = function (msg) {
|
||||
throw msg;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds functions to the default set of functions that can be used inside
|
||||
* a template. Newer definitions of a function will take precedence
|
||||
* over the previously registered function.
|
||||
* @param {Object} an object whose properties are names of functions
|
||||
* and values are the functions that correspond to the names.
|
||||
*/
|
||||
jig.addFn = function (obj) {
|
||||
object.mixin(defaultFuncs, obj, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets and sets the data bound to a particular rendered template. Setting
|
||||
* the data does not change the already rendered template.
|
||||
*
|
||||
* @param {String||DOMNode} dataId the data ID, or a DOM node with a
|
||||
* data-blade-jig attribute that was generated from a rendered template.
|
||||
* @returns {Object} the bound data. Can return undefined if there is
|
||||
* no data stored with that ID.
|
||||
*/
|
||||
jig.data = function (dataId, value) {
|
||||
if (typeof dataId !== 'string') {
|
||||
//Should be a DOM node or node list if it is not already a string.
|
||||
if (!dataId.nodeType) {
|
||||
dataId = dataId[0];
|
||||
}
|
||||
dataId = dataId.getAttribute('data-blade-jig');
|
||||
}
|
||||
|
||||
if (value !== undefined) {
|
||||
return (dataRegistry[dataId] = value);
|
||||
} else {
|
||||
return dataRegistry[dataId];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes some data that was bound to a rendered template.
|
||||
* @param {String} dataId the data ID. It can be fetched from the
|
||||
* data-blade-jig attribute on a rendered template.
|
||||
*/
|
||||
jig.removeData = function (dataId) {
|
||||
delete dataRegistry[dataId];
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets an object given a string representation. For example,
|
||||
* jig.getObject('foo.bar', baz) will return the baz.foo.bar value.
|
||||
*
|
||||
* @param {String} name the string value to fetch. The following formats
|
||||
* are allowed: 'foo.bar', 'foo['bar']', 'foo[0]', 'foo[2:6]'. The last one
|
||||
* will return an array subset. Functions are also supported: 'doSomething(foo.bar)'
|
||||
* but the doSomething function needs to be defined in the options.fn
|
||||
* property, as options.fn.doSomething = function (){}
|
||||
*
|
||||
* @param {Object} data the object to use as the basis for the object lookup.
|
||||
*
|
||||
* @param {Object} options. Options to the lookup. The only supported option
|
||||
* at this time is options.func, and object defining functions can could be
|
||||
* called.
|
||||
*
|
||||
* @returns {Object} it could return null if the name is not found off the data
|
||||
*/
|
||||
jig.getObject = getObject;
|
||||
|
||||
/**
|
||||
* Gets or sets a compiled template from a template cache.
|
||||
* @param {String} id the template ID
|
||||
* @param {String} [value] A string to compile to a template, or
|
||||
* the compiled template value.
|
||||
* @param {Object} [options] optional options object with a 'templates'
|
||||
* property that contains some cached templates. If provided, a matching
|
||||
* cache value for the ID will be used from options.templates, otherwise,
|
||||
* the ID will be used to look up in the global blade/jig template cache.
|
||||
* @returns {Object} a compiled template. It could return undefined if
|
||||
* not match is found.
|
||||
*/
|
||||
jig.cache = function (id, value, options) {
|
||||
//Convert the value to a compiled templated if necessary.
|
||||
if (typeof value === 'string') {
|
||||
value = jig.compile(value, options);
|
||||
}
|
||||
|
||||
//If value is not an array, then a get operation, likely an options.
|
||||
if (!isArray(value)) {
|
||||
options = value;
|
||||
value = undefined;
|
||||
}
|
||||
|
||||
var cache = (options && options.templates) || templateCache;
|
||||
if (value !== undefined) {
|
||||
cache[id] = value;
|
||||
}
|
||||
|
||||
//Return the value. For get use, the template may not be in
|
||||
//the local options.templates, but in the global cache, so
|
||||
//be sure to check both.
|
||||
return cache[id] || templateCache[id];
|
||||
};
|
||||
|
||||
function addToJQuery(jQuery) {
|
||||
//Only handles queries where it is by a node ID, '#something'.
|
||||
jQuery.fn.jig = function (data, options) {
|
||||
//Convert this, which is a DOM node into a string of data
|
||||
options = options || {};
|
||||
|
||||
var id = this.selector,
|
||||
compiled;
|
||||
|
||||
if (id.charAt(0) !== '#') {
|
||||
throw new Error('blade/jig: only ID selectors, like "#something" are allowed with jig()');
|
||||
}
|
||||
id = id.substring(1, id.length);
|
||||
|
||||
//See if the template is already compiled.
|
||||
compiled = (options.templates || templateCache)[id];
|
||||
|
||||
if (!compiled) {
|
||||
compiled = nodeToCompiled(this[0]);
|
||||
}
|
||||
|
||||
return jQuery(jig.render(compiled, data, options));
|
||||
};
|
||||
}
|
||||
|
||||
//Set up the plugin with a RequireJS-aware jQuery module but also
|
||||
//if there is a global jQuery.
|
||||
//require.modify('jquery', 'jquery-jig', ['jquery'], addToJQuery);
|
||||
if (typeof jQuery !== 'undefined') {
|
||||
addToJQuery(jQuery);
|
||||
}
|
||||
|
||||
return jig;
|
||||
});
|
|
@ -0,0 +1,128 @@
|
|||
/**
|
||||
* @license blade/object Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
|
||||
* Available via the MIT, GPL or new BSD license.
|
||||
* see: http://github.com/jrburke/blade for details
|
||||
*/
|
||||
/*jslint plusplus: false */
|
||||
/*global define: false */
|
||||
|
||||
'use strict';
|
||||
|
||||
define(['./fn'], function (fn) {
|
||||
|
||||
var empty = {},
|
||||
|
||||
/**
|
||||
* Creates a new constructor function for generating objects of a certain type.
|
||||
*
|
||||
* @param {Object} base the base object to inherit from in the
|
||||
* prototype chain. Pass null if no parent desired.
|
||||
*
|
||||
* @param {Array} mixins an array of objects to use to mix in their
|
||||
* properties into the new object. Pass null if no mixins desired.
|
||||
*
|
||||
* @param {Function} objPropertyFunc, a function that returns an object
|
||||
* whose properties should be part of this new object's prototype.
|
||||
* The function will be passed the function used to call methods
|
||||
* on the parent prototype used for this object. The function expects
|
||||
* three arguments:
|
||||
* - obj: pass the this object for this arg
|
||||
* - funcName: the function name to call on the prototype object (a string)
|
||||
* - args: an array of arguments. Normally just pass the arguments object.
|
||||
* The parent prototype will be a combination of the base object
|
||||
* with all mixins applied.
|
||||
*
|
||||
* @returns {Function} a constructor function.
|
||||
*/
|
||||
object = function (base, mixins, objPropertyFunc) {
|
||||
base = base || {};
|
||||
var constructor,
|
||||
|
||||
//Create the parent and its parentFunc calling wrapper.
|
||||
//The parent function just makes it easier to call the parent
|
||||
parent = object.create(base.prototype, mixins),
|
||||
parentFunc = function (obj, funcName, args) {
|
||||
return parent[funcName].apply(obj, args);
|
||||
},
|
||||
|
||||
//Create a different object for the prototype instead of using
|
||||
//parent, so that parent can still refer to parent object
|
||||
//without the curren object's properties mixed in
|
||||
//(via the objPropertyFunc) with the mixed in properties taking
|
||||
//priority over the parent's properties.
|
||||
proto = object.create(parent);
|
||||
|
||||
object.mixin(proto, (fn.is(objPropertyFunc) ? objPropertyFunc(parentFunc) : objPropertyFunc), true);
|
||||
|
||||
//Create the constructor function. Calls init if it is defined
|
||||
//on the prototype (proto)
|
||||
constructor = function () {
|
||||
//Protect against a missing new
|
||||
if (!(this instanceof constructor)) {
|
||||
throw new Error('blade/object: constructor function called without "new" in front');
|
||||
}
|
||||
|
||||
//Call initializer if present.
|
||||
if (this.init) {
|
||||
this.init.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
//Set the prototype for this constructor
|
||||
constructor.prototype = proto;
|
||||
|
||||
return constructor;
|
||||
};
|
||||
|
||||
/**
|
||||
* Similar to ES5 create, but instead of setting property attributes
|
||||
* for the second arg, allow an array of mixins to mix in properties
|
||||
* to the newly created object.
|
||||
* A copy of dojo.delegate
|
||||
* @param {Object} parent the parent object to use as the prototype.
|
||||
* @param {Array} [mixins] array of mixin objects to mix in to the new object.
|
||||
*/
|
||||
function Temp() {}
|
||||
|
||||
object.create = function (obj, mixins) {
|
||||
Temp.prototype = obj;
|
||||
var temp = new Temp(), i, mixin;
|
||||
|
||||
//Avoid any extra memory hanging around
|
||||
Temp.prototype = null;
|
||||
|
||||
if (mixins) {
|
||||
for (i = 0; (mixin = mixins[i]); i++) {
|
||||
object.mixin(temp, mixin);
|
||||
}
|
||||
}
|
||||
return temp; // Object
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple function to mix in properties from source into target,
|
||||
* but only if target does not already have a property of the same name,
|
||||
* unless override is set to true. Borrowed from Dojo.
|
||||
*
|
||||
* To extend a prototype on a given object, pass in the prototype property
|
||||
* to mixin. For example: object.mixin(func.prototype, {a: 'b'});
|
||||
*
|
||||
* @param {Object} target the object receiving the mixed in properties.
|
||||
*
|
||||
* @param {Object} source the object that contains the properties to mix in.
|
||||
*
|
||||
* @param {Boolean} [override] if set to true, then the source's properties
|
||||
* will be mixed in even if a property of the same name already exists on
|
||||
* the target.
|
||||
*/
|
||||
object.mixin = function (target, source, override) {
|
||||
//TODO: consider ES5 getters and setters in here.
|
||||
for (var prop in source) {
|
||||
if (!(prop in empty) && (!(prop in target) || override)) {
|
||||
target[prop] = source[prop];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return object;
|
||||
});
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* @license blade/url Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
|
||||
* Available via the MIT, GPL or new BSD license.
|
||||
* see: http://github.com/jrburke/blade for details
|
||||
*/
|
||||
/*jslint nomen: false, plusplus: false */
|
||||
/*global define: false */
|
||||
|
||||
'use strict';
|
||||
|
||||
define(['./array'], function (array) {
|
||||
var ostring = Object.prototype.toString;
|
||||
|
||||
return {
|
||||
objectToQuery: function (/*Object*/ map) {
|
||||
// summary:
|
||||
// takes a name/value mapping object and returns a string representing
|
||||
// a URL-encoded version of that object.
|
||||
// example:
|
||||
// this object:
|
||||
//
|
||||
// | {
|
||||
// | blah: "blah",
|
||||
// | multi: [
|
||||
// | "thud",
|
||||
// | "thonk"
|
||||
// | ]
|
||||
// | };
|
||||
//
|
||||
// yields the following query string:
|
||||
//
|
||||
// | "blah=blah&multi=thud&multi=thonk"
|
||||
|
||||
// FIXME: need to implement encodeAscii!!
|
||||
var enc = encodeURIComponent,
|
||||
pairs = [],
|
||||
backstop = {},
|
||||
name, value, assign, i;
|
||||
for (name in map) {
|
||||
if (map.hasOwnProperty(name)) {
|
||||
value = map[name];
|
||||
if (value !== backstop[name]) {
|
||||
assign = enc(name) + "=";
|
||||
if (array.is(value)) {
|
||||
for (i = 0; i < value.length; i++) {
|
||||
pairs.push(assign + enc(value[i]));
|
||||
}
|
||||
} else {
|
||||
pairs.push(assign + enc(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pairs.join("&"); // String
|
||||
},
|
||||
|
||||
queryToObject: function (/*String*/ str) {
|
||||
// summary:
|
||||
// Create an object representing a de-serialized query section of a
|
||||
// URL. Query keys with multiple values are returned in an array.
|
||||
//
|
||||
// example:
|
||||
// This string:
|
||||
//
|
||||
// | "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&"
|
||||
//
|
||||
// results in this object structure:
|
||||
//
|
||||
// | {
|
||||
// | foo: [ "bar", "baz" ],
|
||||
// | thinger: " spaces =blah",
|
||||
// | zonk: "blarg"
|
||||
// | }
|
||||
//
|
||||
// Note that spaces and other urlencoded entities are correctly
|
||||
// handled.
|
||||
var ret = {},
|
||||
qp = str.split('&'),
|
||||
dec = decodeURIComponent,
|
||||
parts, name, val;
|
||||
|
||||
qp.forEach(function (item) {
|
||||
if (item.length) {
|
||||
parts = item.split('=');
|
||||
name = dec(parts.shift());
|
||||
val = dec(parts.join('='));
|
||||
if (typeof ret[name] === 'string') {
|
||||
ret[name] = [ret[name]];
|
||||
}
|
||||
|
||||
if (ostring.call(ret[name]) === '[object Array]') {
|
||||
ret[name].push(val);
|
||||
} else {
|
||||
ret[name] = val;
|
||||
}
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
});
|
|
@ -0,0 +1,173 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
/*jslint */
|
||||
/*global require: false, define: false, window: false, document: false, cards: true */
|
||||
'use strict';
|
||||
|
||||
define([ 'jquery', 'text!templates/cardsHeader.html'],
|
||||
function ($, headerTemplate) {
|
||||
var header, display, back, nlCards,
|
||||
cardPosition = 0,
|
||||
headerText = '',
|
||||
cardTitles = [];
|
||||
|
||||
function adjustCardSizes() {
|
||||
var cardWidth = display.outerWidth(),
|
||||
cardList = $('.card'),
|
||||
totalWidth = cardWidth * cardList.length,
|
||||
height = window.innerHeight - header.outerHeight();
|
||||
|
||||
//Set height
|
||||
display.css('height', height + 'px');
|
||||
|
||||
//Set widths and heights of cards. Need to set the heights
|
||||
//explicitly so any card using iscroll will get updated correctly.
|
||||
nlCards.css({
|
||||
width: totalWidth + 'px',
|
||||
height: height + 'px'
|
||||
});
|
||||
|
||||
cardList.css({
|
||||
width: cardWidth + 'px',
|
||||
height: height + 'px'
|
||||
});
|
||||
|
||||
//Reset the scroll correctly.
|
||||
cards.scroll();
|
||||
}
|
||||
|
||||
function cards(nl, options) {
|
||||
nl = nl.jquery ? nl : $(nl);
|
||||
|
||||
$(function () {
|
||||
//Insert the header before the cards
|
||||
header = $(headerTemplate).insertBefore(nl);
|
||||
headerText = $('#headerText');
|
||||
|
||||
back = $('#back');
|
||||
back.css('display', 'none');
|
||||
back.click((options && options.onBack) || cards.back);
|
||||
|
||||
display = nl;
|
||||
nlCards = display.find('#cards');
|
||||
|
||||
adjustCardSizes();
|
||||
cards.setTitle(options && options.title);
|
||||
|
||||
//Detect orientation changes and size the card container size accordingly.
|
||||
if ('onorientationchange' in window) {
|
||||
window.addEventListener('orientationchange', adjustCardSizes, false);
|
||||
}
|
||||
window.addEventListener('resize', adjustCardSizes, false);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
cards.adjustCardSizes = adjustCardSizes;
|
||||
|
||||
/**
|
||||
* Adds a new card to the list of cards, at the end of the cards.
|
||||
* Only adds the card, does not navigate to it. Only adds the card
|
||||
* if a DOM element with the info.id does not already exist in the page.
|
||||
*
|
||||
* @param {Object} info the info about the card. It must have the following
|
||||
* properties:
|
||||
* @param {String} info.id the ID to use for the new card's DOM element.
|
||||
* @param {String} info.title the text title to use for the card.
|
||||
* @param {String} info.content a string of HTML to use for the content.
|
||||
*/
|
||||
cards.add = function (info) {
|
||||
var existing = $('#' + info.id),
|
||||
title = info.title;
|
||||
|
||||
if (!title) {
|
||||
title = info.content.match(/<h1>([^<]+)<\/h1>/);
|
||||
title = (title && title[1]) || '';
|
||||
}
|
||||
|
||||
if (!existing.length) {
|
||||
existing = $('<div id="' + info.id + '" class="card" title="' + title + '">' + info.content + '</div>')
|
||||
.appendTo('#cards');
|
||||
cards.adjustCardSizes();
|
||||
}
|
||||
|
||||
return existing[0];
|
||||
};
|
||||
|
||||
cards.back = function () {
|
||||
cardPosition -= 1;
|
||||
if (cardPosition < 0) {
|
||||
cardPosition = 0;
|
||||
}
|
||||
cards.scroll();
|
||||
};
|
||||
|
||||
cards.moveTo = function (id) {
|
||||
cardPosition = $('.card').index(document.getElementById(id));
|
||||
if (cardPosition < 0) {
|
||||
cardPosition = 0;
|
||||
}
|
||||
cards.scroll();
|
||||
};
|
||||
|
||||
cards.forward = function (title) {
|
||||
cardPosition += 1;
|
||||
cards.scroll(title);
|
||||
};
|
||||
|
||||
cards.scroll = function (title) {
|
||||
if (title) {
|
||||
cardTitles[cardPosition] = title;
|
||||
}
|
||||
|
||||
cards.setTitle(title);
|
||||
|
||||
var left = display.outerWidth() * cardPosition;
|
||||
|
||||
nlCards.animate(
|
||||
{
|
||||
left: '-' + left + 'px'
|
||||
}, {
|
||||
duration: 300,
|
||||
easing: 'linear'
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
Was used for CSS -webkit-transition
|
||||
nlCards.css({
|
||||
left: '-' + left + 'px'
|
||||
});
|
||||
*/
|
||||
//Hide/Show back button as appropriate
|
||||
back.css('display', !cardPosition ? 'none' : '');
|
||||
};
|
||||
|
||||
cards.setTitle = function (title) {
|
||||
title = title || cardTitles[cardPosition] || nlCards.find('.card').eq(cardPosition).attr('title') || '';
|
||||
headerText.html(title);
|
||||
};
|
||||
|
||||
return cards;
|
||||
});
|
|
@ -0,0 +1,81 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Raindrop.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Messaging, Inc..
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* */
|
||||
|
||||
/*jslint plusplus: false, indent: 2 */
|
||||
/*global require: false, define: false, location: false, window: false */
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* A module that handles dispatching pub/sub topics, where the underlying
|
||||
* dispatch is done by postMessage. This allows for chrome extensions
|
||||
* to participate in the pub/sub via postMessage without having to
|
||||
* participate in this particular module.
|
||||
*/
|
||||
define(['jquery'], function ($) {
|
||||
|
||||
var origin = location.protocol + "//" + location.host;
|
||||
|
||||
return {
|
||||
sub: function (topic, callback, win, targetOrigin) {
|
||||
win = win || window;
|
||||
targetOrigin = targetOrigin || origin;
|
||||
|
||||
var func = function (evt) {
|
||||
//Make sure message is from this page, or from the browser extension
|
||||
//that wants to communicate information back to the page.
|
||||
if (evt.origin === targetOrigin || evt.origin === 'chrome://browser') {
|
||||
//Assume pub/sub has JSON data with properties named
|
||||
//'topic' and 'data'.
|
||||
try {
|
||||
var message = JSON.parse(evt.data),
|
||||
pubTopic = message.topic;
|
||||
if (pubTopic && pubTopic === topic) {
|
||||
callback(message.data);
|
||||
}
|
||||
} catch (e) {
|
||||
//Just ignore messages that are not JSON. There are some, like
|
||||
//the oauth_success messages
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
win.addEventListener('message', func, false);
|
||||
|
||||
//return the created function to allow unsubscribing
|
||||
return func;
|
||||
},
|
||||
|
||||
unsub: function (func, win) {
|
||||
win = win || window;
|
||||
win.removeEventListener('message', func, false);
|
||||
},
|
||||
|
||||
pub: function (topic, data, win) {
|
||||
win = win || window;
|
||||
win.postMessage(JSON.stringify({
|
||||
topic: topic,
|
||||
data: data
|
||||
}), origin);
|
||||
}
|
||||
};
|
||||
});
|