Merge branch 'develop' into feature/metrics

This commit is contained in:
Mark Hammond 2011-02-14 16:58:31 +11:00
Родитель 2cf99032a5 1473d94307
Коммит ed6997f96a
402 изменённых файлов: 28487 добавлений и 5932 удалений

Просмотреть файл

@ -1,27 +1,17 @@
version := 0.1.8
ifeq ($(TOPSRCDIR),) ifeq ($(TOPSRCDIR),)
export TOPSRCDIR = $(shell pwd) export TOPSRCDIR = $(shell pwd)
endif endif
srcdir=$(TOPSRCDIR)/extensions/firefox-share/src/ srcdir=$(TOPSRCDIR)/extensions/firefox-share/src/
objdir=$(TOPSRCDIR)/extensions/firefox-share/dist/ objdir=$(TOPSRCDIR)/extensions/firefox-share/dist/
stage_dir=$(objdir)/stage stage_dir=$(objdir)/stage
xpi_dir=$(TOPSRCDIR)/web xpi_dir=$(TOPSRCDIR)/web/dev
web_dir=$(TOPSRCDIR)/web web_dir=$(TOPSRCDIR)/web/dev
static_dir=$(TOPSRCDIR)/web-static static_dir=$(TOPSRCDIR)/web/$(version)
webbuild_dir=$(TOPSRCDIR)/tools/webbuild webbuild_dir=$(TOPSRCDIR)/tools/webbuild
requirejs_dir=$(webbuild_dir)/requirejs requirejs_dir=$(webbuild_dir)/requirejs
version := 0.7.3 xpi_name := ffshare.xpi
ifeq ($(release_build),)
xpi_type := dev
update_url :=
else
xpi_type := rel
update_url :=
endif
xpi_name := share-$(version)-$(xpi_type).xpi
xpi_files := chrome.manifest chrome install.rdf defaults components modules xpi_files := chrome.manifest chrome install.rdf defaults components modules
dep_files := Makefile $(shell find $(srcdir) -type f) dep_files := Makefile $(shell find $(srcdir) -type f)
@ -71,10 +61,16 @@ web: $(static_dir)
$(static_dir): $(static_dir):
rsync -av $(web_dir)/ $(static_dir)/ rsync -av $(web_dir)/ $(static_dir)/
cd $(webbuild_dir) && $(requirejs_dir)/build/build.sh share.build.js
cd $(webbuild_dir) && $(requirejs_dir)/build/build.sh frontpage.build.js
cd $(webbuild_dir) && $(requirejs_dir)/build/build.sh settings.build.js
perl -i -pe "s:version='[^']+':version='$(version)':" $(TOPSRCDIR)/setup.py
find $(static_dir) -name \*.html | xargs perl -i -pe 's:/dev/:/$(version)/:go'
cd $(static_dir) && $(requirejs_dir)/build/build.sh build.js
cd $(static_dir)/settings && $(requirejs_dir)/build/build.sh build.js
cd $(static_dir)/share && $(requirejs_dir)/build/build.sh build.js
cd $(static_dir)/share/panel && $(requirejs_dir)/build/build.sh build.js
cd $(static_dir)/.. && ln -n -f -s $(version) current
clean: clean:
rm -rf $(objdir) rm -rf $(objdir)
rm -rf $(static_dir) rm -rf $(static_dir)

Просмотреть файл

@ -47,14 +47,14 @@ Run the web server. 'reload' is useful for development, the webserver restarts o
paster serve --reload development.ini paster serve --reload development.ini
Then visit: http://127.0.0.1:5000/ for an index of api examples Then visit: [http://127.0.0.1:5000/](http://127.0.0.1:5000/) for an index of api examples
## Setting up a valid Google domain for OpenID+OAuth ## Setting up a valid Google domain for OpenID+OAuth
You have to have access to a valid domain that google can get to and where you can install an html file. You have to have access to a valid domain that google can get to and where you can install an html file.
Visit: https://www.google.com/accounts/ManageDomains Visit: [https://www.google.com/accounts/ManageDomains](https://www.google.com/accounts/ManageDomains)
Add your domain, follow the rest of their instructions. Add your domain, follow the rest of their instructions.

Просмотреть файл

@ -28,7 +28,7 @@ oauth.twitter.com.authorize = https://twitter.com/oauth/authenticate
# below for this server. # below for this server.
oauth.facebook.com.app_id = 163981616966631 oauth.facebook.com.app_id = 163981616966631
oauth.facebook.com.app_secret = 78e3bd4ab991ccf50fb9220452eb30b4 oauth.facebook.com.app_secret = 78e3bd4ab991ccf50fb9220452eb30b4
oauth.facebook.com.scope = publish_stream,offline_access oauth.facebook.com.scope = publish_stream,offline_access,user_groups
oauth.facebook.com.authorize = https://graph.facebook.com/oauth/authorize oauth.facebook.com.authorize = https://graph.facebook.com/oauth/authorize
oauth.facebook.com.access = https://graph.facebook.com/oauth/access_token oauth.facebook.com.access = https://graph.facebook.com/oauth/access_token
@ -44,10 +44,16 @@ oauth.google.com.scope = https://mail.google.com/ http://www.google.com/m8/feeds
# also set verified = 1 # also set verified = 1
oauth.yahoo.com.consumer_key = dj0yJmk9TjFpSlVBcmY2Q2pnJmQ9WVdrOWQwUjVVVFJKTkdVbWNHbzlNVEF6TnpZME1ERTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD1hZg-- oauth.yahoo.com.consumer_key = dj0yJmk9TjFpSlVBcmY2Q2pnJmQ9WVdrOWQwUjVVVFJKTkdVbWNHbzlNVEF6TnpZME1ERTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD1hZg--
oauth.yahoo.com.consumer_secret = a47367578f07e3ea1ddb045b3003a9c7d95a5f69 oauth.yahoo.com.consumer_secret = a47367578f07e3ea1ddb045b3003a9c7d95a5f69
oauth.yahoo.com.app_id = wDyQ4I4e oauth.yahoo.com.app_id = wDyQ4I4e
# set to true if you have completed domain verification with Yahoo # set to true if you have completed domain verification with Yahoo
oauth.yahoo.com.verified = 1 oauth.yahoo.com.verified = 1
oauth.linkedin.com.consumer_key = sz-cmZ24vIXHAK_3NCsNTsF57F3wrgi0uT0vr5NC6hmXWAdmVSFrGcKUNBqDgjP5
oauth.linkedin.com.consumer_secret = RfvZProhTuRAjuOA8EBm7PVfhZO31W2QdLHGd12nfh7hpAwc7VuZiG15pEwFhRRh
oauth.linkedin.com.request = https://api.linkedin.com/uas/oauth/requestToken
oauth.linkedin.com.access = https://api.linkedin.com/uas/oauth/accessToken
oauth.linkedin.com.authorize = https://api.linkedin.com/uas/oauth/authorize
[server:main] [server:main]
use = egg:Paste#http use = egg:Paste#http
host = 127.0.0.1 host = 127.0.0.1
@ -89,7 +95,7 @@ use = egg:Paste#urlmap
/api = api /api = api
[app:home] [app:home]
use = egg:Paste#static use = egg:linkdrop#static
document_root = %(here)s/web document_root = %(here)s/web
[app:api] [app:api]

Просмотреть файл

@ -27,6 +27,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<title>F1 not available</title> <title>F1 not available</title>
<style type="text/css"> <style type="text/css">
* { * {
margin: 0; margin: 0;
@ -40,59 +41,57 @@
font-style: inherit; font-style: inherit;
font-size: 100%; font-size: 100%;
vertical-align: top; vertical-align: top;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
list-style-type: none; list-style-type: none;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
} }
body { body {
font-size: 11px; font-size: 11px;
font-family: "Lucida Grande", Verdana, sans-serif; font-family: "Lucida Grande", Verdana, sans-serif;
max-height: 113px;
overflow: hidden;
background-color: #fff;
background-position: bottom center;
background-repeat: no-repeat;
background-color: #fff;
} }
div.status { div.status {
min-height: 113px; width: 400px;
padding: 0 10px; height: 180px;
overflow: hidden;
border-bottom: 1px solid #777;
}
div.status {
position: absolute;
width: 100%;
height: 113px;
line-height: 113px;
top: 0;
left: 0;
color: #0a0a0a; color: #0a0a0a;
font-size: 14px; font-size: 14px;
text-align: center; text-align: center;
position: relative;
} }
div.status.intermediate.error { div.status.intermediate.error {
background-color: rgba(255,115,0,0.75); background-color: rgba(255,115,0,0.75);
color: #FFFFFF; color: #FFFFFF;
-webkit-box-shadow: 0 0 200px rgba(0, 0, 0, 0.25) inset;
-moz-box-shadow: 0 0 200px rgba(0, 0, 0, 0.25) inset;
box-shadow: 0 0 200px rgba(0, 0, 0, 0.25) inset;
} }
#statusErrorMessage { table {
display: inline-block; width: 100%;
margin-top: 3px; height: 100%;
padding: 10px;
} }
#statusServerError { table td {
line-height: 20px; vertical-align: middle;
} }
</style> </style>
</head> </head>
<body> <body>
<div class="status intermediate error"> <div class="status intermediate error">
Sorry, the F1 service is not available at the moment. Please try later. <table>
<tr>
<td>
Sorry, the F1 service is not available at the moment.<br>Please try later.
</td>
</tr>
</table>
</div> </div>
</body> </body>
</html> </html>

Просмотреть файл

@ -77,6 +77,7 @@
accesskey="&ffshareContext.accesskey;" accesskey="&ffshareContext.accesskey;"
command="cmd_openSharePage"/> command="cmd_openSharePage"/>
</popup> </popup>
</popupset> </popupset>
@ -118,6 +119,7 @@
class="toolbarbutton-1 chromeclass-toolbar-additional" class="toolbarbutton-1 chromeclass-toolbar-additional"
label="&ffshareToolbarButton.label;" label="&ffshareToolbarButton.label;"
tooltiptext="&ffshareToolbarButton.tooltip;" tooltiptext="&ffshareToolbarButton.tooltip;"
type="checkbox"
command="cmd_openSharePage"/> command="cmd_openSharePage"/>
<tabbrowser id="content"/> <tabbrowser id="content"/>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -2,5 +2,5 @@
<!ENTITY ffshareContext.accesskey "S"> <!ENTITY ffshareContext.accesskey "S">
<!ENTITY ffshareMenu.label "Share Page…"> <!ENTITY ffshareMenu.label "Share Page…">
<!ENTITY ffshareMenu.accesskey "h"> <!ENTITY ffshareMenu.accesskey "h">
<!ENTITY ffshareToolbarButton.label "Share This Page"> <!ENTITY ffshareToolbarButton.label "F1">
<!ENTITY ffshareToolbarButton.tooltip "Use F1 to share the current page via Twitter, Facebook, and more."> <!ENTITY ffshareToolbarButton.tooltip "Use F1 to share the current page via Twitter, Facebook, and more.">

Просмотреть файл

@ -21,52 +21,17 @@
* Contributor(s): * Contributor(s):
* */ * */
.ffshare-frame { #ffshare-toolbar-button > label {
-moz-transition: height 0.2s ease-in; display: none;
} }
#ffshare-toolbar-button
{
list-style-image: url("chrome://ffshare/skin/toolbar-button.png");
}
#ffshare-toolbar-button > image { #ffshare-toolbar-button > image {
list-style-image: url("chrome://ffshare/skin/toolbar-button.png");
width: auto; width: auto;
height: auto; height: auto;
} }
#ffshare-popup { #ffshare-toolbar-button[firstRun] > image {
-moz-appearance: none; list-style-image: url("chrome://ffshare/skin/toolbar-button-glow.png");
-moz-window-shadow: none;
background-color: transparent;
margin-top: -4px;
margin-left: -13px;
padding-right: 35px; /* not quite 50px but looks very close */
min-width: 380px !important;
-moz-border-image: url(chrome://browser/skin/hud-panel.png) 26 18 22 50 / 26px 18px 22px 50px repeat;
color: lightgrey;
}
/* factory reset */
#ffshare-popup * {
border: none;
outline: none;
margin: 0;
padding: 0;
-moz-padding-start: 0px;
-moz-padding-end: 0px;
-moz-margin-start: 0px;
-moz-margin-end: 0px;
-moz-border-radius: 0px;
font-family: sans-serif;
font-weight: inherit;
font-style: inherit;
font-size: 100%;
vertical-align: middle;
-moz-box-sizing: border-box;
list-style-type: none;
}
#ffshare-popup description {
margin: 5px 0;
} }
/* Styles to style the autocomplete results */ /* Styles to style the autocomplete results */
@ -74,3 +39,7 @@
.autocomplete-richlistitem[type="ffshare"] .ac-url-box { .autocomplete-richlistitem[type="ffshare"] .ac-url-box {
display: none !important; display: none !important;
} }
.ffshare-panel .panel-inner-arrowcontent {
padding: 0;
}

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 10 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 615 B

После

Ширина:  |  Высота:  |  Размер: 403 B

Просмотреть файл

@ -21,52 +21,17 @@
* Contributor(s): * Contributor(s):
* */ * */
.ffshare-frame { #ffshare-toolbar-button > label {
-moz-transition: height 0.2s ease-in; display: none;
} }
#ffshare-toolbar-button
{
list-style-image: url("chrome://ffshare/skin/toolbar-button.png");
}
#ffshare-toolbar-button > image { #ffshare-toolbar-button > image {
list-style-image: url("chrome://ffshare/skin/toolbar-button.png");
width: auto; width: auto;
height: auto; height: auto;
} }
#ffshare-popup { #ffshare-toolbar-button[firstRun] > image {
-moz-appearance: none; list-style-image: url("chrome://ffshare/skin/toolbar-button-glow.png");
-moz-window-shadow: none;
background-color: transparent;
margin-top: -4px;
margin-left: -13px;
padding-right: 35px; /* not quite 50px but looks very close */
min-width: 380px !important;
-moz-border-image: url(chrome://browser/skin/hud-panel.png) 26 18 22 50 / 26px 18px 22px 50px repeat;
color: lightgrey;
}
/* factory reset */
#ffshare-popup * {
border: none;
outline: none;
margin: 0;
padding: 0;
-moz-padding-start: 0px;
-moz-padding-end: 0px;
-moz-margin-start: 0px;
-moz-margin-end: 0px;
-moz-border-radius: 0px;
font-family: sans-serif;
font-weight: inherit;
font-style: inherit;
font-size: 100%;
vertical-align: middle;
-moz-box-sizing: border-box;
list-style-type: none;
}
#ffshare-popup description {
margin: 5px 0;
} }
/* Styles to style the autocomplete results */ /* Styles to style the autocomplete results */

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 10 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 390 B

После

Ширина:  |  Высота:  |  Размер: 412 B

Просмотреть файл

@ -1,80 +1,92 @@
/* ***** BEGIN LICENSE BLOCK ***** /* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1 * Version: MPL 1.1
* *
* The contents of this file are subject to the Mozilla Public License Version * 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 * 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 * the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/ * http://www.mozilla.org/MPL/
* *
* Software distributed under the License is distributed on an "AS IS" basis, * Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the * for the specific language governing rights and limitations under the
* License. * License.
* *
* The Original Code is Raindrop. * The Original Code is Raindrop.
* *
* The Initial Developer of the Original Code is * The Initial Developer of the Original Code is
* Mozilla Messaging, Inc.. * Mozilla Messaging, Inc..
* Portions created by the Initial Developer are Copyright (C) 2009 * Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved. * the Initial Developer. All Rights Reserved.
* *
* Contributor(s): * Contributor(s):
* */ * */
#ffshare-toolbar-button #ffshare-toolbar-button {
{ list-style-image: url("chrome://ffshare/skin/toolbar-button.png");
list-style-image: url("chrome://ffshare/skin/toolbar-button.png"); -moz-image-region: rect(0px, 35px, 23px, 0px);
-moz-image-region: rect(0px, 35px, 23px, 0px); }
} #ffshare-toolbar-button[disabled="true"],
#ffshare-toolbar-button[disabled="true"], #ffshare-toolbar-button[disabled="true"]:active {
#ffshare-toolbar-button[disabled="true"]:active -moz-image-region: rect(23px, 35px, 46px, 0px);
{ }
-moz-image-region: rect(23px, 35px, 46px, 0px); #ffshare-toolbar-button:active {
} -moz-image-region: rect(46px, 35px, 69px, 0px);
#ffshare-toolbar-button:active }
{ #ffshare-toolbar-button[checked="true"] {
-moz-image-region: rect(46px, 35px, 69px, 0px); background: none;
} border-color: transparent;
#ffshare-popup { -moz-image-region: rect(46px, 35px, 69px, 0px);
-moz-appearance: none; }
-moz-window-shadow: none; #ffshare-toolbar-button[firstRun] {
background-color: transparent; list-style-image: url("chrome://ffshare/skin/toolbar-button-glow.png");
margin-top: -4px; -moz-image-region: rect(0px, 35px, 23px, 0px);
margin-left: -13px; }
padding-right: 35px; /* not quite 50px but looks very close */
min-width: 380px !important; /* Styles to style the autocomplete results */
-moz-border-image: url(chrome://browser/skin/hud-panel.png) 26 18 22 50 / 26px 18px 22px 50px repeat; .autocomplete-richlistitem[type="ffshare"] .ac-site-icon,
color: lightgrey; .autocomplete-richlistitem[type="ffshare"] .ac-url-box {
} display: none !important;
}
/* factory reset */
#ffshare-popup * { .ffshare-panel {
border: none; width: 441px; /* note this value hard-coded in overlay.js */
outline: none; min-width: 441px !important;
margin: 0; min-height: 234px !important;
padding: 0; }
-moz-padding-start: 0px;
-moz-padding-end: 0px; .ffshare-browser {
-moz-margin-start: 0px; width: 400px; /* note this value tied to ffshare-panel width as well */
-moz-margin-end: 0px; height: 100%;
-moz-border-radius: 0px; }
font-family: sans-serif;
font-weight: inherit; /* Popup Bounding Box */
font-style: inherit;
font-size: 100%; .doorhanger-rtl {
vertical-align: middle; -moz-appearance: none;
-moz-box-sizing: border-box; -moz-window-shadow: none;
list-style-type: none; background-color: transparent;
} margin-top: -10px;
margin-left: -16px;
#ffshare-popup description { min-width: 280px;
margin: 5px 0; -moz-border-image: url(chrome://browser/skin/hud-panel.png) 26 10 22 50 / 26px 18px 22px 50px repeat;
font-size: 150%; }
font-weight: bold;
} .doorhanger-ltr {
-moz-appearance: none;
/* Styles to style the autocomplete results */ -moz-window-shadow: none;
.autocomplete-richlistitem[type="ffshare"] .ac-site-icon, background-color: transparent;
.autocomplete-richlistitem[type="ffshare"] .ac-url-box { margin-top: -10px;
display: none !important; margin-right: -16px;
} min-width: 280px;
-moz-border-image: url(chrome://browser/skin/hud-panel.png) 26 50 22 10 / 26px 50px 22px 18px repeat;
}
.doorhanger-rtl .doorhanger-inner {
margin: 4px 6px 2px -30px;
color: #fff;
}
.doorhanger-ltr .doorhanger-inner {
margin: 4px -33px 2px 6px;
color: #fff;
}

Двоичные данные
extensions/firefox-share/src/chrome/skin/toolbar-button-glow.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 22 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.9 KiB

После

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Просмотреть файл

@ -35,7 +35,6 @@ function _() {
_("?loaded"); _("?loaded");
__defineGetter__("acDataStorage", function() { __defineGetter__("acDataStorage", function() {
delete this.ffshareAutoCompleteData;
Cu.import("resource://ffshare/modules/ffshareAutoCompleteData.js"); Cu.import("resource://ffshare/modules/ffshareAutoCompleteData.js");
return ffshareAutoCompleteData; return ffshareAutoCompleteData;
}); });
@ -64,13 +63,16 @@ FFShareAutoComplete.prototype = {
return false; return false;
}, },
findEmails: function findEmails(query) { findEmails: function findEmails(query, field) {
_("findEmails", Array.slice(arguments)); _("findEmails", Array.slice(arguments));
let result = Cc["@mozilla.org/autocomplete/simple-result;1"]. let result = Cc["@mozilla.org/autocomplete/simple-result;1"].
createInstance(Ci.nsIAutoCompleteSimpleResult); createInstance(Ci.nsIAutoCompleteSimpleResult);
result.setSearchString(query); result.setSearchString(query);
let datadomain = field.getAttribute('autocompletestore');
if (!datadomain)
return result;
//convert the query to only be for things after the comma. //convert the query to only be for things after the comma.
var parts = query.split(','), previousMatch = ''; var parts = query.split(','), previousMatch = '';
@ -83,18 +85,19 @@ FFShareAutoComplete.prototype = {
_("query is now: [" + query + "]"); _("query is now: [" + query + "]");
_("previousMatch is now: " + previousMatch); _("previousMatch is now: " + previousMatch);
_("data domain is: "+datadomain);
let data = acDataStorage.get(); let data = acDataStorage.get(datadomain) || {};
for (let name in data) {
data.forEach(function (item) { var displayNameLower = name.toLowerCase(),
var displayNameLower = item.displayName.toLowerCase(), emailLower = data[name].email.toLowerCase();
emailLower = item.email.toLowerCase();
if (displayNameLower.indexOf(query) !== -1 || emailLower.indexOf(query) !== -1) { if (displayNameLower.indexOf(query) !== -1 || emailLower.indexOf(query) !== -1) {
result.appendMatch(previousMatch + item.email + ', ', if (emailLower)
(displayNameLower === emailLower ? item.email : item.displayName + '<' + item.email + '>'), null, 'ffshare'); addr = (displayNameLower === emailLower ? data[name].email : name + '<' + data[name].email + '>');
else
addr = name;
result.appendMatch(previousMatch + addr + ', ', addr , null, 'ffshare');
} }
}); }
let resultCode = result.matchCount ? "RESULT_SUCCESS" : "RESULT_NOMATCH"; let resultCode = result.matchCount ? "RESULT_SUCCESS" : "RESULT_NOMATCH";
_("returning autocomplete " +resultCode+ " result with " + result.matchCount + " items"); _("returning autocomplete " +resultCode+ " result with " + result.matchCount + " items");
@ -106,7 +109,7 @@ _("previousMatch is now: " + previousMatch);
_("FFShareAutoComplete search", Array.slice(arguments)); _("FFShareAutoComplete search", Array.slice(arguments));
if (this.isShareType(name, field)) if (this.isShareType(name, field))
return this.findEmails(query); return this.findEmails(query, field);
return null; return null;
} }
}; };

Просмотреть файл

@ -4,7 +4,7 @@
<em:id>ffshare@mozilla.org</em:id> <em:id>ffshare@mozilla.org</em:id>
<em:type>2</em:type> <em:type>2</em:type>
<em:name>F1 by Mozilla Labs</em:name> <em:name>F1 by Mozilla Labs</em:name>
<em:version>0.7.3</em:version> <em:version>0.7.4</em:version>
<em:creator>Mozilla</em:creator> <em:creator>Mozilla</em:creator>
<em:contributor></em:contributor> <em:contributor></em:contributor>
<em:homepageURL>http://f1.mozillamessaging.com/</em:homepageURL> <em:homepageURL>http://f1.mozillamessaging.com/</em:homepageURL>
@ -13,8 +13,8 @@
<em:targetApplication> <em:targetApplication>
<Description> <Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- Firefox --> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- Firefox -->
<em:minVersion>3.6</em:minVersion> <em:minVersion>3.6.6</em:minVersion>
<em:maxVersion>4.0b9pre</em:maxVersion> <em:maxVersion>4.0b12pre</em:maxVersion>
</Description> </Description>
</em:targetApplication> </em:targetApplication>
</Description> </Description>

Просмотреть файл

@ -20,16 +20,26 @@
* *
* Contributor(s): * Contributor(s):
* */ * */
const Cu = Components.utils;
let EXPORTED_SYMBOLS = ["ffshareAutoCompleteData"]; let EXPORTED_SYMBOLS = ["ffshareAutoCompleteData"];
let data = []; let data = {};
function _() {
return; // comment out for verbose debugging
let msg = Array.join(arguments, " ");
dump(msg + "\n");
Cu.reportError(msg);
}
let ffshareAutoCompleteData = { let ffshareAutoCompleteData = {
get: function () { get: function (domain) {
return data; _("XXX getting data for "+domain);
return data[domain];
}, },
set: function (newData) { set: function (acdata) {
data = (newData || []); _("XXX setting "+ (acdata.contacts ? acdata.contacts.length : "none") +" contacts for "+acdata.domain);
data[acdata.domain] = (acdata.contacts || []);
} }
}; };

Просмотреть файл

@ -21,6 +21,7 @@
* Shane Caraveo <shane@caraveo.com> * Shane Caraveo <shane@caraveo.com>
* Myk Melez <myk@mozilla.org> * Myk Melez <myk@mozilla.org>
* Justin Dolske <dolske@mozilla.com> * Justin Dolske <dolske@mozilla.com>
* Erik Vold <erikvvold@gmail.com>
* *
* Alternatively, the contents of this file may be used under the terms of * Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or * either the GNU General Public License Version 2 or later (the "GPL"), or
@ -39,9 +40,7 @@
/* Inject the People content API into window.navigator objects. */ /* Inject the People content API into window.navigator objects. */
/* Partly based on code in the Geode extension. */ /* Partly based on code in the Geode extension. */
const Cc = Components.classes; const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm");
let EXPORTED_SYMBOLS = ["InjectorInit"]; let EXPORTED_SYMBOLS = ["InjectorInit"];
@ -127,20 +126,20 @@ let Injector = {
}; };
// hook up a seperate listener for each xul window // hook up a separate listener for each xul window
function InjectorInit(window) { function InjectorInit(window) {
if (window.injector) return; if (window.injector) return;
window.injector = { window.injector = {
providers: [], providers: [],
onLoad: function() { onLoad: function() {
var obs = Components.classes["@mozilla.org/observer-service;1"]. var obs = Cc["@mozilla.org/observer-service;1"].
getService(Components.interfaces.nsIObserverService); getService(Ci.nsIObserverService);
obs.addObserver(this, 'content-document-global-created', false); obs.addObserver(this, 'content-document-global-created', false);
}, },
onUnload: function() { onUnload: function() {
var obs = Components.classes["@mozilla.org/observer-service;1"]. var obs = Cc["@mozilla.org/observer-service;1"].
getService(Components.interfaces.nsIObserverService); getService(Ci.nsIObserverService);
obs.removeObserver(this, 'content-document-global-created'); obs.removeObserver(this, 'content-document-global-created');
}, },
@ -152,12 +151,12 @@ function InjectorInit(window) {
observe: function(aSubject, aTopic, aData) { observe: function(aSubject, aTopic, aData) {
if (!aSubject.location.href) return; if (!aSubject.location.href) return;
// is this window a child of OUR XUL window? // is this window a child of OUR XUL window?
var mainWindow = aSubject.QueryInterface(Components.interfaces.nsIInterfaceRequestor) var mainWindow = aSubject.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation) .getInterface(Ci.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem) .QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem .rootTreeItem
.QueryInterface(Components.interfaces.nsIInterfaceRequestor) .QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow); .getInterface(Ci.nsIDOMWindow);
if (mainWindow != window) { if (mainWindow != window) {
return; return;
} }

Просмотреть файл

@ -99,6 +99,9 @@ Subject line for emails, not supported by all services.
"""), """),
api_arg('picture', 'string', False, None, None, """ api_arg('picture', 'string', False, None, None, """
URL to publicly available thumbnail, not supported by all services. URL to publicly available thumbnail, not supported by all services.
"""),
api_arg('picture_base64', 'string', False, None, None, """
Base 64 encoded PNG version of the picture used for attaching to emails.
"""), """),
api_arg('description', 'string', False, None, None, """ api_arg('description', 'string', False, None, None, """
Site provided description of the shared item, not supported by all services. Site provided description of the shared item, not supported by all services.

Просмотреть файл

@ -27,6 +27,7 @@ from linkdrop.lib.oauth import google_
#from linkdrop.lib.oauth.openidconsumer import OpenIDResponder #from linkdrop.lib.oauth.openidconsumer import OpenIDResponder
from linkdrop.lib.oauth import twitter_ from linkdrop.lib.oauth import twitter_
from linkdrop.lib.oauth import yahoo_ from linkdrop.lib.oauth import yahoo_
from linkdrop.lib.oauth import linkedin_
__all__ = ['get_provider'] __all__ = ['get_provider']
@ -36,7 +37,8 @@ _providers = {
facebook_.domain: facebook_, facebook_.domain: facebook_,
google_.domain: google_, google_.domain: google_,
"googleapps.com": google_, "googleapps.com": google_,
yahoo_.domain: yahoo_ yahoo_.domain: yahoo_,
linkedin_.domain: linkedin_
} }
def get_provider(provider): def get_provider(provider):

Просмотреть файл

@ -33,13 +33,14 @@ import httplib2
import urllib import urllib
import random import random
import copy import copy
import logging
from pylons import config, request, response, session, tmpl_context as c, url from pylons import config, request, response, session, tmpl_context as c, url
from pylons.controllers.util import abort, redirect from pylons.controllers.util import abort, redirect
from linkdrop.lib.oauth.base import OAuth2 from linkdrop.lib.oauth.base import OAuth2
domain = 'facebook.com' domain = 'facebook.com'
log = logging.getLogger(domain)
# this function is a derivative of: # this function is a derivative of:
# http://code.activestate.com/recipes/146306-http-client-to-post-using-multipartform-data/ # http://code.activestate.com/recipes/146306-http-client-to-post-using-multipartform-data/
@ -210,36 +211,76 @@ class api():
'status': status}) 'status': status})
return error return error
def rawcall(self, url, body): def rawcall(self, url, body=None, method="GET"):
url = url +"?"+urllib.urlencode(dict(access_token=self.access_token)) url = url +"?"+urllib.urlencode(dict(access_token=self.access_token))
headers = None
content_type, body = encode_multipart_formdata(body) if body:
headers = { content_type, body = encode_multipart_formdata(body)
'Content-type': content_type, headers = {
'Content-Length': str(len(body)) 'Content-type': content_type,
} 'Content-Length': str(len(body))
resp, content = httplib2.Http().request(url, 'POST', headers=headers, body=body) }
resp, content = httplib2.Http().request(url, method=method, headers=headers, body=body)
data = json.loads(content) data = json.loads(content)
result = error = None result = error = None
if 'id' in data: if 'id' in data:
result = data result = data
result[domain] = data['id'] result[domain] = data['id']
elif 'data' in data:
result = data
result[domain] = None
else: else:
error = self._make_error(data, resp) error = self._make_error(data, resp)
return result, error return result, error
# feed supports message, picture, link, name, caption, description, source
# map our stuff to theirs
post_map = {
'link': 'link',
'title': 'name',
'description': 'description',
'picture': 'picture',
'caption': 'caption',
'source': 'source'
}
def sendmessage(self, message, options={}): def sendmessage(self, message, options={}):
url = config.get("oauth.facebook.com.feed", "https://graph.facebook.com/me/feed") direct = options.get('to', None)
if direct:
url = "https://graph.facebook.com/%s/feed" % (direct,)
else:
url = config.get("oauth.facebook.com.feed", "https://graph.facebook.com/me/feed")
body = { body = {
"message": message "message": message
} }
for ours, yours in self.post_map.items():
if ours in options:
body[yours] = options[ours]
for arg in ['link', 'name', 'description', 'picture']: return self.rawcall(url, body, "POST")
if arg in options:
body[arg] = options[arg]
return self.rawcall(url, body)
def getcontacts(self, start=0, page=25, group=None):
# for twitter we get only those people who we follow and who follow us
# since this data is used for direct messaging
url = "https://graph.facebook.com/me/groups"
result, error = self.rawcall(url)
if error:
return result, error
groups = []
for group in result['data']:
groups.append({
'displayName': group.get('name'),
'accounts': [{'userid': group.get('id'), 'username': None, 'domain': domain}]
})
connectedto = {
'entry': groups,
'itemsPerPage': len(groups),
'startIndex': 0,
'totalResults': len(groups),
}
return connectedto, None

Просмотреть файл

@ -45,6 +45,7 @@ import gdata.contacts
from email.mime.multipart import MIMEMultipart from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.header import Header from email.header import Header
from pylons import config, request, response, session, tmpl_context as c, url from pylons import config, request, response, session, tmpl_context as c, url
@ -193,7 +194,6 @@ class responder(OpenIDResponder):
profile = result_data['profile'] profile = result_data['profile']
provider = domain provider = domain
import sys; print >> sys.stderr, "credential provider is ", profile.get('providerName')
if profile.get('providerName').lower() == 'openid': if profile.get('providerName').lower() == 'openid':
provider = 'googleapps.com' provider = 'googleapps.com'
userid = profile.get('verifiedEmail','') userid = profile.get('verifiedEmail','')
@ -285,8 +285,25 @@ class api():
c.description = description c.description = description
c.message = message c.message = message
part2 = MIMEText(render('/html_email.mako').encode('utf-8'), 'html') c.thumbnail = (options.get('picture_base64', "") != "")
part2.set_charset('utf-8')
if c.thumbnail:
part2 = MIMEMultipart('related')
html = MIMEText(render('/html_email.mako').encode('utf-8'), 'html')
html.set_charset('utf-8')
# FIXME: we decode the base64 data just so MIMEImage can re-encode it as base64
image = MIMEImage(base64.b64decode(options.get('picture_base64')), 'png')
image.add_header('Content-Id', '<thumbnail>')
image.add_header('Content-Disposition', 'inline; filename=thumbnail.png')
part2.attach(html)
part2.attach(image)
else:
part2 = MIMEText(render('/html_email.mako').encode('utf-8'), 'html')
part2.set_charset('utf-8')
# get the title, or the long url or the short url or nothing # get the title, or the long url or the short url or nothing
# wrap these in literal for text email # wrap these in literal for text email
@ -333,7 +350,7 @@ class api():
return result, error return result, error
def getgroup_id(self, group): def getgroup_id(self, group):
url = 'http://www.google.com/m8/feeds/groups/default/full?v=2' url = 'https://www.google.com/m8/feeds/groups/default/full?v=2'
method = 'GET' method = 'GET'
client = oauth.Client(self.consumer, self.oauth_token) client = oauth.Client(self.consumer, self.oauth_token)
resp, content = client.request(url, method) resp, content = client.request(url, method)
@ -347,7 +364,13 @@ class api():
def getcontacts(self, start=0, page=25, group=None): def getcontacts(self, start=0, page=25, group=None):
contacts = [] contacts = []
url = 'http://www.google.com/m8/feeds/contacts/default/full?v=1&max-results=%d' % (page,) profile = self.account.get('profile', {})
accounts = profile.get('accounts', [{}])
userdomain = 'default'
if accounts[0].get('domain') == 'googleapps.com':
userdomain = accounts[0].get('userid').split('@')[-1]
url = 'http://www.google.com/m8/feeds/contacts/%s/full?v=1&max-results=%d' % (userdomain, page,)
method = 'GET' method = 'GET'
if start > 0: if start > 0:
url = url + "&start-index=%d" % (start,) url = url + "&start-index=%d" % (start,)
@ -363,6 +386,7 @@ class api():
# itemsPerPage, startIndex, totalResults # itemsPerPage, startIndex, totalResults
client = oauth.Client(self.consumer, self.oauth_token) client = oauth.Client(self.consumer, self.oauth_token)
resp, content = client.request(url, method) resp, content = client.request(url, method)
if int(resp.status) != 200: if int(resp.status) != 200:
error={"provider": domain, error={"provider": domain,
"message": content, "message": content,
@ -371,7 +395,6 @@ class api():
return None, error return None, error
feed = gdata.contacts.ContactsFeedFromString(content) feed = gdata.contacts.ContactsFeedFromString(content)
from pprint import pprint
for entry in feed.entry: for entry in feed.entry:
#print entry.group_membership_info #print entry.group_membership_info
p = { p = {

Просмотреть файл

@ -0,0 +1,191 @@
import urlparse
import json
import httplib2
import oauth2 as oauth
import logging
from rfc822 import AddressList
from pylons import config, request, response, session, tmpl_context as c, url
from pylons.controllers.util import abort, redirect
from paste.deploy.converters import asbool
from linkdrop.lib.oauth.base import OAuth1, get_oauth_config
from linkdrop.lib.base import render
from linkdrop.lib.helpers import safeHTML, literal
domain = 'linkedin.com'
log = logging.getLogger(domain)
def extract_li_data(user):
poco = {
'displayName': "%s %s" % (user.get('firstName'), user.get('lastName'),),
}
if user.get('publicProfileUrl', False):
poco['urls'] = [ { 'type': u'profile', "primary" : False, "value" : user['publicProfileUrl'] }]
if user.get('siteStandardProfileRequest', False):
poco['urls'] = [ { 'type': u'profile', "primary" : True, "value" : user['siteStandardProfileRequest']['url'] }]
if user.get('pictureUrl', False):
poco['photos'] = [ { 'type': u'profile', "value" : user['pictureUrl'] }]
account = {'domain': domain,
'userid': user.get("id"),
'username': "" }
poco['accounts'] = [account]
return poco
class responder(OAuth1):
"""Handle LinkedId OAuth login/authentication"""
domain = 'linkedin.com'
def __init__(self):
OAuth1.__init__(self, domain)
def _get_credentials(self, access_token):
fields = 'id,first-name,last-name,picture-url,public-profile-url,site-standard-profile-request'
profile_url = "http://api.linkedin.com/v1/people/~:(%s)" % (fields,)
consumer = oauth.Consumer(self.consumer_key, self.consumer_secret)
token = oauth.Token(access_token['oauth_token'], access_token['oauth_token_secret'])
client = oauth.Client(consumer, token)
oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=token, http_url=profile_url)
oauth_request.sign_request(self.sigmethod, self.consumer, token)
headers = oauth_request.to_header()
headers['x-li-format'] = 'json'
resp, content = httplib2.Http.request(client, profile_url, method='GET', headers=headers)
if resp['status'] != '200':
raise Exception("Error status: %r", resp['status'])
li_profile = json.loads(content)
profile = extract_li_data(li_profile)
result_data = {'profile': profile,
'oauth_token': access_token['oauth_token'],
'oauth_token_secret': access_token['oauth_token_secret']}
return result_data
class api():
def __init__(self, account):
self.config = get_oauth_config(domain)
self.account = account
self.oauth_token = oauth.Token(key=account.get('oauth_token'), secret=account.get('oauth_token_secret'))
self.consumer_key = self.config.get('consumer_key')
self.consumer_secret = self.config.get('consumer_secret')
self.consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret)
self.sigmethod = oauth.SignatureMethod_HMAC_SHA1()
def rawcall(self, url, body=None, method="GET"):
client = oauth.Client(self.consumer, self.oauth_token)
oauth_request = oauth.Request.from_consumer_and_token(self.consumer, token=self.oauth_token, http_url=url, http_method=method)
oauth_request.sign_request(self.sigmethod, self.consumer, self.oauth_token)
headers = oauth_request.to_header()
headers['x-li-format'] = 'json'
body = json.dumps(body)
headers['Content-type'] = 'application/json'
headers['Content-Length'] = str(len(body))
resp, content = httplib2.Http.request(client, url, method=method, headers=headers, body=body)
data = content and json.loads(content) or resp
result = error = None
status = int(resp['status'])
if status < 200 or status >= 300:
error = data
else:
result = data
return result, error
def sendmessage(self, message, options={}):
direct = options.get('to', 'anyone')
if direct in ('anyone', 'connections-only'):
url = "http://api.linkedin.com/v1/people/~/shares"
body = {
"comment": message,
"content": {
"title": options.get('subject', ''),
"submitted-url": options.get('link', ''),
"submitted-image-url": options.get('picture', ''),
"description": options.get('description', ''),
},
"visibility": {
"code": direct
}
}
else:
# we have to do a direct message, different api
url = "http://api.linkedin.com/v1/people/~/mailbox"
profile = self.account.get('profile', {})
from_email = from_ = profile.get('verifiedEmail')
fullname = profile.get('displayName', None)
to_addrs = AddressList(options['to'])
subject = options.get('subject', config.get('share_subject', 'A web link has been shared with you'))
title = options.get('title', options.get('link', options.get('shorturl', '')))
description = options.get('description', '')[:280]
to_ = []
for a in to_addrs.addresslist:
to_.append({'person': {'_path': '/people/'+a[1] }})
c.safeHTML = safeHTML
c.options = options
# insert the url if it is not already in the message
c.longurl = options.get('link')
c.shorturl = options.get('shorturl')
# get the title, or the long url or the short url or nothing
# wrap these in literal for text email
c.from_name = literal(fullname)
c.subject = literal(subject)
c.from_header = literal(from_)
c.to_header = literal(to_)
c.title = literal(title)
c.description = literal(description)
c.message = literal(message)
text_message = render('/text_email.mako').encode('utf-8')
body = {
'recipients': {'values': to_},
'subject': subject,
'body': text_message
}
return self.rawcall(url, body, method="POST")
def getcontacts(self, start=0, page=25, group=None):
contacts = []
url = 'http://api.linkedin.com/v1/people/~/connections?count=%d' % (page,)
method = 'GET'
if start > 0:
url = url + "&start=%d" % (start,)
result, error = self.rawcall(url, method="GET")
if error:
return result, error
# poco-ize the results
entries = result.get('values')
contacts = []
for entry in entries:
contacts.append(extract_li_data(entry))
connectedto = {
'entry': contacts,
'itemsPerPage': result.get('_count', result.get('_total', 0)),
'startIndex': result.get('_start', 0),
'totalResults': result.get('_total'),
}
return connectedto, error

Просмотреть файл

@ -80,6 +80,12 @@ def twitter_to_poco(user):
poco['photos'] = [ { 'type': u'profile', "value" : user['profile_image_url'] }] poco['photos'] = [ { 'type': u'profile', "value" : user['profile_image_url'] }]
if user.get('created_at', None): if user.get('created_at', None):
poco['published'] = user['created_at'] poco['published'] = user['created_at']
account = {'domain': 'twitter.com',
'userid': user['id'],
'username': user['screen_name'] }
poco['accounts'] = [account]
return poco return poco
class responder(OAuth1): class responder(OAuth1):
@ -157,7 +163,11 @@ class api():
# some reason we dont have a short url, add the long url # some reason we dont have a short url, add the long url
message += " %s" % longurl message += " %s" % longurl
result = self.api().statuses.update(status=message) direct = options.get('to', None)
if direct:
result = self.api().direct_messages.new(text=message, user_id=direct)
else:
result = self.api().statuses.update(status=message)
result[domain] = result['id'] result[domain] = result['id']
except TwitterHTTPError, exc: except TwitterHTTPError, exc:
try: try:
@ -195,4 +205,35 @@ class api():
'status': exc.e.code 'status': exc.e.code
} }
return result, error return result, error
def getcontacts(self, start=0, page=25, group=None):
# for twitter we get only those people who we follow and who follow us
# since this data is used for direct messaging
contacts = []
result = error = None
try:
followers = self.api().statuses.followers()
for follower in followers:
contacts.append(twitter_to_poco(follower))
connectedto = {
'entry': contacts,
'itemsPerPage': len(contacts),
'startIndex': 0,
'totalResults': len(contacts),
}
return connectedto, None
except TwitterHTTPError, exc:
details = "TwitterHTTPError %d" % (exc.e.code)
if exc.e.code != 404:
details = json.load(exc.e)
if 'error' in details:
msg = details['error']
else:
msg = str(details)
error = {'provider': domain,
'message': msg,
'status': exc.e.code
}
return result, error

Просмотреть файл

@ -29,6 +29,7 @@ import httplib2
import json import json
import copy import copy
from rfc822 import AddressList from rfc822 import AddressList
import logging
from pylons import config, request, response, session, tmpl_context as c, url from pylons import config, request, response, session, tmpl_context as c, url
from pylons.controllers.util import abort, redirect from pylons.controllers.util import abort, redirect
@ -46,6 +47,7 @@ from linkdrop.lib.oauth.base import get_oauth_config
YAHOO_OAUTH = 'https://api.login.yahoo.com/oauth/v2/get_token' YAHOO_OAUTH = 'https://api.login.yahoo.com/oauth/v2/get_token'
domain = 'yahoo.com' domain = 'yahoo.com'
log = logging.getLogger(domain)
class responder(OpenIDResponder): class responder(OpenIDResponder):
def __init__(self, consumer=None, oauth_key=None, oauth_secret=None, request_attributes=None, *args, def __init__(self, consumer=None, oauth_key=None, oauth_secret=None, request_attributes=None, *args,
@ -100,12 +102,14 @@ class responder(OpenIDResponder):
'userid': userid, 'userid': userid,
'username': username } 'username': username }
profile['accounts'] = [account] profile['accounts'] = [account]
profile['xoauth_yahoo_guid'] = result_data['xoauth_yahoo_guid']
return result_data return result_data
class api(): class api():
endpoints = { endpoints = {
"mail":"http://mail.yahooapis.com/ws/mail/v1.1/jsonrpc" "mail":"http://mail.yahooapis.com/ws/mail/v1.1/jsonrpc",
"contacts":"http://social.yahooapis.com/v1/user/%s/contacts"
} }
def __init__(self, account): def __init__(self, account):
@ -117,7 +121,7 @@ class api():
self.consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret) self.consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret)
self.sigmethod = oauth.SignatureMethod_HMAC_SHA1() self.sigmethod = oauth.SignatureMethod_HMAC_SHA1()
def rawcall(self, url, method, args, options={}): def jsonrpc(self, url, method, args, options={}):
headers = { headers = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Accept': 'application/json' 'Accept': 'application/json'
@ -161,6 +165,31 @@ class api():
return result, error return result, error
def restcall(self, url, method="GET", body=None):
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
oauth_request = oauth.Request.from_consumer_and_token(self.consumer,
token=self.oauth_token,
http_method=method,
http_url=url)
oauth_request.sign_request(self.sigmethod, self.consumer, self.oauth_token)
headers.update(oauth_request.to_header())
resp, content = httplib2.Http().request(url, method, headers=headers, body=body)
data = content and json.loads(content) or resp
result = error = None
status = int(resp['status'])
if status < 200 or status >= 300:
error = data
else:
result = data
return result, error
def sendmessage(self, message, options={}): def sendmessage(self, message, options={}):
result = error = None result = error = None
@ -194,6 +223,7 @@ class api():
c.title = title c.title = title
c.description = description c.description = description
c.message = message c.message = message
c.thumbnail = False
html_message = render('/html_email.mako').encode('utf-8') html_message = render('/html_email.mako').encode('utf-8')
@ -222,6 +252,42 @@ class api():
"savecopy":1 "savecopy":1
}] }]
return self.rawcall(self.endpoints['mail'], 'SendMessage', params, options) return self.jsonrpc(self.endpoints['mail'], 'SendMessage', params, options)
def getcontacts(self, start=0, page=25, group=None):
profile = self.account.get('profile', {})
guid = profile.get('xoauth_yahoo_guid')
result, error = self.restcall(self.endpoints['contacts'] % (guid,))
if error:
return result, error
ycontacts = result.get('contacts')
people = ycontacts.get('contact', [])
contacts = []
# convert yahoo contacts to poco
for person in people:
poco = {}
for f in person.get('fields', []):
field = f.get('type')
value = f.get('value')
if field == 'name':
if value.get('middleName'):
poco['displayName'] = "%s %s %s" % (value.get('givenName'), value.get('middleName'), value.get('familyName'),)
else:
poco['displayName'] = "%s %s" % (value.get('givenName'), value.get('familyName'),)
elif field == 'email':
poco.setdefault('emails',[]).append({ 'value': value, 'primary': False })
elif field == 'nickname':
poco['nickname'] = value
contacts.append(poco)
connectedto = {
'entry': contacts,
'itemsPerPage': ycontacts.get('count', 0),
'startIndex': ycontacts.get('start', 0),
'totalResults': ycontacts.get('total', 0),
}
return connectedto, None

119
linkdrop/static.py Normal file
Просмотреть файл

@ -0,0 +1,119 @@
import os
import sys
import re
from paste import request
from paste import fileapp
from paste import httpexceptions
from paste.httpheaders import ETAG
version_re = re.compile("/\d+.\d+.\d+/", re.U)
class StaticURLParser(object):
"""
based on Paste.urlparser.StaticURLParser, however we handle an internal
redirect for versioning of static files. This is only intended for
development work, as we serve production from apache/mod_wsgi.
"""
# @@: Should URLParser subclass from this?
def __init__(self, directory, root_directory=None,
cache_max_age=None, version="/dev/"):
self.directory = self.normpath(directory)
self.root_directory = self.normpath(root_directory or directory)
self.cache_max_age = cache_max_age
self.version = version
def normpath(path):
return os.path.normcase(os.path.abspath(path))
normpath = staticmethod(normpath)
def __call__(self, environ, start_response):
path_info = environ.get('PATH_INFO', '')
if not path_info:
return self.add_slash(environ, start_response)
directory = "%s" % self.directory
if not path_info.startswith('/%s/' % self.version) and version_re.match(path_info) is None and directory == self.root_directory:
directory = os.path.join(directory, self.version)
if path_info == '/':
# @@: This should obviously be configurable
filename = 'index.html'
else:
filename = request.path_info_pop(environ)
full = self.normpath(os.path.join(directory, filename))
if not full.startswith(self.root_directory):
# Out of bounds
return self.not_found(environ, start_response)
if not os.path.exists(full):
return self.not_found(environ, start_response)
if os.path.isdir(full):
# @@: Cache?
return self.__class__(full, root_directory=self.root_directory,
version=self.version,
cache_max_age=self.cache_max_age)(environ,
start_response)
if environ.get('PATH_INFO') and environ.get('PATH_INFO') != '/':
return self.error_extra_path(environ, start_response)
if_none_match = environ.get('HTTP_IF_NONE_MATCH')
if if_none_match:
mytime = os.stat(full).st_mtime
if str(mytime) == if_none_match:
headers = []
## FIXME: probably should be
## ETAG.update(headers, '"%s"' % mytime)
ETAG.update(headers, mytime)
start_response('304 Not Modified', headers)
return [''] # empty body
fa = self.make_app(full)
if self.cache_max_age:
fa.cache_control(max_age=self.cache_max_age)
return fa(environ, start_response)
def make_app(self, filename):
return fileapp.FileApp(filename)
def add_slash(self, environ, start_response):
"""
This happens when you try to get to a directory
without a trailing /
"""
url = request.construct_url(environ, with_query_string=False)
url += '/'
if environ.get('QUERY_STRING'):
url += '?' + environ['QUERY_STRING']
exc = httpexceptions.HTTPMovedPermanently(
'The resource has moved to %s - you should be redirected '
'automatically.' % url,
headers=[('location', url)])
return exc.wsgi_application(environ, start_response)
def not_found(self, environ, start_response, debug_message=None):
exc = httpexceptions.HTTPNotFound(
'The resource at %s could not be found'
% request.construct_url(environ),
comment='SCRIPT_NAME=%r; PATH_INFO=%r; looking in %r; debug: %s'
% (environ.get('SCRIPT_NAME'), environ.get('PATH_INFO'),
self.directory, debug_message or '(none)'))
return exc.wsgi_application(environ, start_response)
def error_extra_path(self, environ, start_response):
exc = httpexceptions.HTTPNotFound(
'The trailing path %r is not allowed' % environ['PATH_INFO'])
return exc.wsgi_application(environ, start_response)
def __repr__(self):
return '<%s %r>' % (self.__class__.__name__, self.directory)
def make_static(global_conf, document_root, cache_max_age=None, version="dev"):
"""
Return a WSGI application that serves a directory (configured
with document_root)
cache_max_age - integer specifies CACHE_CONTROL max_age in seconds
"""
if cache_max_age is not None:
cache_max_age = int(cache_max_age)
return StaticURLParser(
document_root, cache_max_age=cache_max_age, version=version)

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -16,11 +16,27 @@
<a target="_blank" style="color:#00A0FF;font-size:16px;" href="${c.longurl}">${c.title}</a> <a target="_blank" style="color:#00A0FF;font-size:16px;" href="${c.longurl}">${c.title}</a>
% endif % endif
</div> </div>
<table style="border:none;border-collapse:collapse;margin:10px 0;width:100%;">
<tbody><tr>
<td style="border-left: 1px solid #666;vertical-align:top;">
% if c.description: % if c.description:
<div class="description" style="font-size:12px;color:#666;margin:7px 0;font-style:italic;padding:0 0 0 15px;border-left:1px solid #666;"> <div class="description" style="font-size:12px;color:#666;font-style:italic;padding:0 0 0 10px;">
${context.write(c.safeHTML(c.description))} ${context.write(c.safeHTML(c.description))}
</div> </div>
% endif % endif
</td>
% if c.thumbnail:
<td style="width:1%">
% if c.shorturl:
<a target="_blank" style="color:#00A0FF;font-size:16px;" href="${c.shorturl}">
% elif c.longurl:
<a target="_blank" style="color:#00A0FF;font-size:16px;" href="${c.longurl}">
% endif
<img src="cid:thumbnail" style="padding:1px;border:1px solid #ccc;margin:5px;"/></a>
</td>
% endif
</tr></tbody>
</table>
</div> </div>
<div class="footer" style="font-size:12px;color:#444;"> <div class="footer" style="font-size:12px;color:#444;">
shared via <a target="_blank" style="color:#006AAA;font-weight:bold;text-decoration:none;" title="Share links with the people that matter to you" href="http://f1.mozillamessaging.com/">Mozilla F1</a> for Firefox &mdash; <span style="color:#666;">"share links with the people that matter to you"</span> shared via <a target="_blank" style="color:#006AAA;font-weight:bold;text-decoration:none;" title="Share links with the people that matter to you" href="http://f1.mozillamessaging.com/">Mozilla F1</a> for Firefox &mdash; <span style="color:#666;">"share links with the people that matter to you"</span>

Просмотреть файл

@ -30,7 +30,7 @@ except ImportError:
setup( setup(
name='linkdrop', name='linkdrop',
version='0.1.6.1', version='0.1.8',
description='', description='',
author='', author='',
author_email='', author_email='',
@ -45,9 +45,9 @@ setup(
"python-dateutil", "python-dateutil",
"python-openid", "python-openid",
"python-memcached", "python-memcached",
"twitter",
"gdata", # google api support "gdata", # google api support
"sqlalchemy-migrate>=0.5.4", "sqlalchemy-migrate>=0.5.4",
"twitter>=1.4.2"
], ],
setup_requires=["PasteScript>=1.6.3"], setup_requires=["PasteScript>=1.6.3"],
packages=find_packages(exclude=['ez_setup']), packages=find_packages(exclude=['ez_setup']),
@ -63,6 +63,7 @@ setup(
entry_points=""" entry_points="""
[paste.app_factory] [paste.app_factory]
main = linkdrop.config.middleware:make_app main = linkdrop.config.middleware:make_app
static = linkdrop.static:make_static
[paste.filter_app_factory] [paste.filter_app_factory]
csrf = linkdrop.csrf:make_csrf_filter_app csrf = linkdrop.csrf:make_csrf_filter_app

Просмотреть файл

@ -1,10 +0,0 @@
{
baseUrl: "../../web-static/scripts/",
paths: {
"index": "../index",
"jquery": "requireplugins-jquery-1.4.2"
},
name: "index",
exclude: ['jquery'],
out: '../../web-static/index.js'
}

Просмотреть файл

@ -1,6 +1,6 @@
/** /**
* @license Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. * @license Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */

Просмотреть файл

@ -1,4 +1,4 @@
#!/bin/sh #!/bin/sh
MYDIR=$(cd $(dirname "$0"); pwd) MYDIR=`cd \`dirname "$0"\`; pwd`
java -classpath $MYDIR/lib/rhino/js.jar:$MYDIR/lib/closure/compiler.jar org.mozilla.javascript.tools.shell.Main $MYDIR/build.js $MYDIR "$@" java -classpath $MYDIR/lib/rhino/js.jar:$MYDIR/lib/closure/compiler.jar org.mozilla.javascript.tools.shell.Main $MYDIR/build.js $MYDIR "$@"

Просмотреть файл

@ -1,4 +1,4 @@
#!/bin/sh #!/bin/sh
MYDIR=$(cd $(dirname "$0"); pwd) MYDIR=`cd \`dirname "$0"\`; pwd`
java -classpath $MYDIR/lib/rhino/js.jar:$MYDIR/lib/closure/compiler.jar org.mozilla.javascript.tools.debugger.Main $MYDIR/build.js $MYDIR "$@" java -classpath $MYDIR/lib/rhino/js.jar:$MYDIR/lib/closure/compiler.jar org.mozilla.javascript.tools.debugger.Main $MYDIR/build.js $MYDIR "$@"

Просмотреть файл

@ -5,10 +5,10 @@
* THIS BUILD FILE WILL NOT WORK. It is referencing paths that probably * THIS BUILD FILE WILL NOT WORK. It is referencing paths that probably
* do not exist on your machine. Just use it as a guide. * do not exist on your machine. Just use it as a guide.
* *
* *
*/ */
{ ({
//The top level directory that contains your app. If this option is used //The top level directory that contains your app. If this option is used
//then it assumed your scripts are in a subdirectory under this path. //then it assumed your scripts are in a subdirectory under this path.
//This option is not required. If it is not specified, then baseUrl //This option is not required. If it is not specified, then baseUrl
@ -75,8 +75,8 @@
useStrict: false, useStrict: false,
//Specify build pragmas. If the source files contain comments like so: //Specify build pragmas. If the source files contain comments like so:
//>>excludeStart("requireExcludeModify", pragmas.requireExcludeModify); //>>excludeStart("fooExclude", pragmas.fooExclude);
//>>excludeEnd("requireExcludeModify"); //>>excludeEnd("fooExclude");
//Then the comments that start with //>> are the build pragmas. //Then the comments that start with //>> are the build pragmas.
//excludeStart/excludeEnd and includeStart/includeEnd work, and the //excludeStart/excludeEnd and includeStart/includeEnd work, and the
//the pragmas value to the includeStart or excludeStart lines //the pragmas value to the includeStart or excludeStart lines
@ -84,27 +84,12 @@
//lines should be included or excluded. //lines should be included or excluded.
pragmas: { pragmas: {
//Indicates require will be included with jquery. //Indicates require will be included with jquery.
jquery: true, jquery: true
//Remove require.modify() code
requireExcludeModify: true,
//Remove plugin support from require. The i18n! jsonp! order! and
//text! extensions will not work.
requireExcludePlugin: true,
//Remove the page loaded detection.
requireExcludePageLoad: true
}, },
//Skip processing for pragmas. //Skip processing for pragmas.
skipPragmas: false, skipPragmas: false,
//If execModules is true, each script is execute in
//full to find the require calls/dependencies, but the code is executed
//in the Rhino JavaScript environment. Set this value to true only
//if the code follows the strict require pattern of wrapping all
//code in a require callback. If you are using jQuery, Prototype or MooTools
//you should not set this value to true. Default is false.
execModules: false,
//If skipModuleInsertion is false, then files that do not use require.def //If skipModuleInsertion is false, then files that do not use require.def
//to define modules will get a require.def() placeholder inserted for them. //to define modules will get a require.def() placeholder inserted for them.
//Also, require.pause/resume calls will be inserted. //Also, require.pause/resume calls will be inserted.
@ -125,7 +110,7 @@
//built file unless the locale: section is set above. //built file unless the locale: section is set above.
{ {
name: "foo/bar/bop", name: "foo/bar/bop",
//Should the contents of require.js be included in the optimized module. //Should the contents of require.js be included in the optimized module.
//Defaults to false. //Defaults to false.
includeRequire: true, includeRequire: true,
@ -137,7 +122,7 @@
//contain any of the other build options in this file. //contain any of the other build options in this file.
override: { override: {
pragmas: { pragmas: {
requireExcludeModify: true fooExclude: true
} }
} }
}, },
@ -174,5 +159,4 @@
] ]
} }
] ]
} })

259
tools/webbuild/requirejs/build/jslib/build.js Normal file → Executable file
Просмотреть файл

@ -1,13 +1,13 @@
/** /**
* @license Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. * @license Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
/*jslint regexp: false, plusplus: false, nomen: false */ /*jslint regexp: false, plusplus: false, nomen: false */
/*global java: false, lang: false, fileUtil: false, optimize: false, /*global java: false, lang: false, fileUtil: false, optimize: false,
load: false, quit: false, print: false, logger: false, require: false, load: false, quit: false, print: false, logger: false, require: false,
pragma: false */ pragma: false, parse: false */
"use strict"; "use strict";
@ -21,16 +21,16 @@ var build, buildBaseConfig;
optimize: "closure", optimize: "closure",
optimizeCss: "standard.keepLines", optimizeCss: "standard.keepLines",
inlineText: true, inlineText: true,
execModules: false isBuild: true
}; };
build = function (args) { build = function (args) {
var requireBuildPath, buildFile, baseUrlFile, buildPaths, deps, fileName, fileNames, var requireBuildPath, buildFile, baseUrlFile, buildPaths, deps, fileName, fileNames,
prop, props, paths, path, i, fileContents, buildFileContents = "", prop, props, paths, path, i, fileContents, buildFileContents = "",
doClosure, requireContents, pluginContents, pluginBuildFileContents, doClosure, requireContents, pluginBuildFileContents,
baseConfig, override, builtRequirePath, cmdConfig, config, baseConfig, override, builtRequirePath, cmdConfig, config,
modules, module, moduleName, builtModule; modules, module, moduleName, builtModule, srcPath, buildContext;
if (!args || args.length < 2) { if (!args || args.length < 2) {
print("java -jar path/to/js.jar build.js directory/containing/build.js/ build.js\n" + print("java -jar path/to/js.jar build.js directory/containing/build.js/ build.js\n" +
"where build.js is the name of the build file (see example.build.js for hints on how to make a build file."); "where build.js is the name of the build file (see example.build.js for hints on how to make a build file.");
@ -43,11 +43,11 @@ var build, buildBaseConfig;
if (requireBuildPath.charAt(requireBuildPath.length - 1) !== "/") { if (requireBuildPath.charAt(requireBuildPath.length - 1) !== "/") {
requireBuildPath += "/"; requireBuildPath += "/";
} }
["lang", "logger", "fileUtil", "parse", "optimize", "pragma", "build"].forEach(function (path) { ["lang", "logger", "fileUtil", "parse", "optimize", "pragma", "build"].forEach(function (path) {
load(requireBuildPath + "jslib/" + path + ".js"); load(requireBuildPath + "jslib/" + path + ".js");
}); });
//Next args can include a build file path as well as other build args. //Next args can include a build file path as well as other build args.
//build file path comes first. If it does not contain an = then it is //build file path comes first. If it does not contain an = then it is
//a build file path. Otherwise, just all build args. //a build file path. Otherwise, just all build args.
@ -57,42 +57,47 @@ var build, buildBaseConfig;
} else { } else {
args.splice(0, 1); args.splice(0, 1);
} }
//Remaining args are options to the build //Remaining args are options to the build
cmdConfig = build.convertArrayToObject(args); cmdConfig = build.convertArrayToObject(args);
cmdConfig.buildFile = buildFile; cmdConfig.buildFile = buildFile;
cmdConfig.requireBuildPath = requireBuildPath; cmdConfig.requireBuildPath = requireBuildPath;
config = build.createConfig(cmdConfig); config = build.createConfig(cmdConfig);
paths = config.paths; paths = config.paths;
//Load require.js with the build patches. //Load require.js with the build patches.
load(config.requireUrl); load(config.requireUrl);
load(requireBuildPath + "jslib/requirePatch.js"); load(requireBuildPath + "jslib/requirePatch.js");
if (!config.out && !config.cssIn) { if (!config.out && !config.cssIn) {
//This is not just a one-off file build but a full build profile, with //This is not just a one-off file build but a full build profile, with
//lots of files to process. //lots of files to process.
//First copy all the baseUrl content //First copy all the baseUrl content
fileUtil.copyDir((config.appDir || config.baseUrl), config.dir, /\w/, true); fileUtil.copyDir((config.appDir || config.baseUrl), config.dir, /\w/, true);
//Adjust baseUrl if config.appDir is in play, and set up build output paths. //Adjust baseUrl if config.appDir is in play, and set up build output paths.
buildPaths = {}; buildPaths = {};
if (config.appDir) { if (config.appDir) {
config.dirBaseUrl = config.dir + config.baseUrl;
config.baseUrl = config.appDir + config.baseUrl;
//All the paths should be inside the appDir //All the paths should be inside the appDir
buildPaths = paths; buildPaths = paths;
} else { } else {
config.dirBaseUrl = config.dir;
//If no appDir, then make sure to copy the other paths to this directory. //If no appDir, then make sure to copy the other paths to this directory.
for (prop in paths) { for (prop in paths) {
if (paths.hasOwnProperty(prop)) { if (paths.hasOwnProperty(prop)) {
//Set up build path for each path prefix. //Set up build path for each path prefix.
buildPaths[prop] = prop.replace(/\./g, "/"); buildPaths[prop] = prop.replace(/\./g, "/");
//Make sure source path is fully formed with baseUrl,
//if it is a relative URL.
srcPath = paths[prop];
if (srcPath.indexOf('/') !== 0 && srcPath.indexOf(':') === -1) {
srcPath = config.baseUrl + srcPath;
}
//Copy files to build area. Copy all files (the /\w/ regexp) //Copy files to build area. Copy all files (the /\w/ regexp)
fileUtil.copyDir(paths[prop], config.dirBaseUrl + buildPaths[prop], /\w/, true); fileUtil.copyDir(srcPath, config.dirBaseUrl + buildPaths[prop], /\w/, true);
} }
} }
} }
@ -106,12 +111,13 @@ var build, buildBaseConfig;
baseUrl: config.baseUrl, baseUrl: config.baseUrl,
paths: paths paths: paths
}); });
buildContext = require.s.contexts._;
modules = config.modules; modules = config.modules;
if (modules) { if (modules) {
modules.forEach(function (module) { modules.forEach(function (module) {
if (module.name) { if (module.name) {
module._sourcePath = require.nameToUrl(module.name, null, require.s.ctxName); module._sourcePath = buildContext.nameToUrl(module.name);
//If the module does not exist, and this is not a "new" module layer, //If the module does not exist, and this is not a "new" module layer,
//as indicated by a true "create" property on the module, then throw an error. //as indicated by a true "create" property on the module, then throw an error.
if (!(new java.io.File(module._sourcePath)).exists() && !module.create) { if (!(new java.io.File(module._sourcePath)).exists() && !module.create) {
@ -138,11 +144,11 @@ var build, buildBaseConfig;
}; };
lang.mixin(baseConfig, config); lang.mixin(baseConfig, config);
require(baseConfig); require(baseConfig);
if (modules) { if (modules) {
modules.forEach(function (module) { modules.forEach(function (module) {
if (module.name) { if (module.name) {
module._buildPath = require.nameToUrl(module.name, null, require.s.ctxName); module._buildPath = buildContext.nameToUrl(module.name, null);
if (!module.create) { if (!module.create) {
fileUtil.copyFile(module._sourcePath, module._buildPath); fileUtil.copyFile(module._sourcePath, module._buildPath);
} }
@ -214,16 +220,16 @@ var build, buildBaseConfig;
//Normal optimizations across modules. //Normal optimizations across modules.
//JS optimizations. //JS optimizations.
fileNames = fileUtil.getFilteredFileList(config.dir, /\.js$/, true); fileNames = fileUtil.getFilteredFileList(config.dir, /\.js$/, true);
for (i = 0; (fileName = fileNames[i]); i++) { for (i = 0; (fileName = fileNames[i]); i++) {
optimize.jsFile(fileName, fileName, config); optimize.jsFile(fileName, fileName, config);
} }
//CSS optimizations //CSS optimizations
if (config.optimizeCss && config.optimizeCss !== "none") { if (config.optimizeCss && config.optimizeCss !== "none") {
optimize.css(config.dir, config); optimize.css(config.dir, config);
} }
//All module layers are done, write out the build.txt file. //All module layers are done, write out the build.txt file.
fileUtil.saveUtf8File(config.dir + "build.txt", buildFileContents); fileUtil.saveUtf8File(config.dir + "build.txt", buildFileContents);
} }
@ -237,7 +243,7 @@ var build, buildBaseConfig;
if (buildFileContents) { if (buildFileContents) {
print(buildFileContents); print(buildFileContents);
} }
}; };
/** /**
@ -281,6 +287,17 @@ var build, buildBaseConfig;
return result; //Object return result; //Object
}; };
build.makeAbsPath = function (path, absFilePath) {
//Add abspath if necessary. If path starts with a slash or has a colon,
//then already is an abolute path.
if (path.indexOf('/') !== 0 && path.indexOf(':') === -1) {
path = absFilePath +
(absFilePath.charAt(absFilePath.length - 1) === '/' ? '' : '/') +
path;
}
return path;
};
/** /**
* Creates a config object for an optimization build. * Creates a config object for an optimization build.
* It will also read the build profile if it is available, to create * It will also read the build profile if it is available, to create
@ -295,7 +312,7 @@ var build, buildBaseConfig;
build.createConfig = function (cfg) { build.createConfig = function (cfg) {
/*jslint evil: true */ /*jslint evil: true */
var config = {}, baseUrl, buildFileContents, buildFileConfig, var config = {}, baseUrl, buildFileContents, buildFileConfig,
paths, props, i, prop; paths, props, i, prop, buildFile, absFilePath, originalBaseUrl;
lang.mixin(config, buildBaseConfig); lang.mixin(config, buildBaseConfig);
lang.mixin(config, cfg, true); lang.mixin(config, cfg, true);
@ -313,20 +330,19 @@ var build, buildBaseConfig;
if (config.buildFile) { if (config.buildFile) {
//A build file exists, load it to get more config. //A build file exists, load it to get more config.
config.buildFile = new java.io.File(config.buildFile).getAbsoluteFile(); buildFile = new java.io.File(config.buildFile).getAbsoluteFile();
//Find the build file, and make sure it exists, if this is a build //Find the build file, and make sure it exists, if this is a build
//that has a build profile, and not just command line args with an in=path //that has a build profile, and not just command line args with an in=path
if (!config.buildFile.exists()) { if (!buildFile.exists()) {
throw new Error("ERROR: build file does not exist: " + config.buildFile.getAbsolutePath()); throw new Error("ERROR: build file does not exist: " + buildFile.getAbsolutePath());
} }
config.baseUrl = fileUtil.absPath(config.buildFile.getParentFile()); absFilePath = config.baseUrl = fileUtil.absPath(buildFile.getParentFile()).replace(lang.backSlashRegExp, '/');
config.buildFile = fileUtil.absPath(config.buildFile);
config.dir = config.baseUrl + "/build/"; config.dir = config.baseUrl + "/build/";
//Load build file options. //Load build file options.
buildFileContents = fileUtil.readFile(config.buildFile); buildFileContents = fileUtil.readFile(buildFile);
buildFileConfig = eval("(" + buildFileContents + ")"); buildFileConfig = eval("(" + buildFileContents + ")");
lang.mixin(config, buildFileConfig, true); lang.mixin(config, buildFileConfig, true);
@ -334,7 +350,6 @@ var build, buildBaseConfig;
//args should take precedence over build file values. //args should take precedence over build file values.
lang.mixin(config, cfg, true); lang.mixin(config, cfg, true);
} else { } else {
//Base URL is relative to the in file.
if (!config.out && !config.cssIn) { if (!config.out && !config.cssIn) {
throw new Error("ERROR: 'out' or 'cssIn' option missing."); throw new Error("ERROR: 'out' or 'cssIn' option missing.");
} }
@ -347,6 +362,9 @@ var build, buildBaseConfig;
if (!config.cssIn && !cfg.baseUrl) { if (!config.cssIn && !cfg.baseUrl) {
throw new Error("ERROR: 'baseUrl' option missing."); throw new Error("ERROR: 'baseUrl' option missing.");
} }
//In this scenario, the absFile path is current directory
absFilePath = (String((new java.io.File('.')).getAbsolutePath())).replace(lang.backSlashRegExp, '/');
} }
if (config.out && !config.cssIn) { if (config.out && !config.cssIn) {
@ -377,7 +395,8 @@ var build, buildBaseConfig;
} }
//Adjust the path properties as appropriate. //Adjust the path properties as appropriate.
//First make sure build paths use front slashes and end in a slash //First make sure build paths use front slashes and end in a slash,
//and make sure they are aboslute paths.
props = ["appDir", "dir", "baseUrl"]; props = ["appDir", "dir", "baseUrl"];
for (i = 0; (prop = props[i]); i++) { for (i = 0; (prop = props[i]); i++) {
if (config[prop]) { if (config[prop]) {
@ -385,6 +404,34 @@ var build, buildBaseConfig;
if (config[prop].charAt(config[prop].length - 1) !== "/") { if (config[prop].charAt(config[prop].length - 1) !== "/") {
config[prop] += "/"; config[prop] += "/";
} }
//Add abspath if necessary.
if (prop === "baseUrl") {
originalBaseUrl = config.baseUrl;
if (config.appDir) {
//If baseUrl with an appDir, the baseUrl is relative to
//the appDir, *not* the absFilePath. appDir and dir are
//made absolute before baseUrl, so this will work.
config.baseUrl = build.makeAbsPath(originalBaseUrl, config.appDir);
//Set up dir output baseUrl.
config.dirBaseUrl = build.makeAbsPath(originalBaseUrl, config.dir);
} else {
//The dir output baseUrl is same as regular baseUrl, both
//relative to the absFilePath.
config.baseUrl = build.makeAbsPath(config[prop], absFilePath);
config.dirBaseUrl = config.dir;
}
} else {
config[prop] = build.makeAbsPath(config[prop], absFilePath);
}
}
}
//Make sure some other paths are absolute.
props = ["out", "cssIn"];
for (i = 0; (prop = props[i]); i++) {
if (config[prop]) {
config[prop] = build.makeAbsPath(config[prop], absFilePath);
} }
} }
@ -436,7 +483,7 @@ var build, buildBaseConfig;
/** /**
* Uses the module build config object to trace the dependencies for the * Uses the module build config object to trace the dependencies for the
* given module. * given module.
* *
* @param {Object} module the module object from the build config info. * @param {Object} module the module object from the build config info.
* @param {Object} the build config object. * @param {Object} the build config object.
* *
@ -445,7 +492,7 @@ var build, buildBaseConfig;
*/ */
build.traceDependencies = function (module, config) { build.traceDependencies = function (module, config) {
var include, override, url, layer, prop, var include, override, url, layer, prop,
context = require.s.contexts[require.s.ctxName], context = require.s.contexts._,
baseConfig = context.config; baseConfig = context.config;
//Reset some state set up in requirePatch.js, and clean up require's //Reset some state set up in requirePatch.js, and clean up require's
@ -475,45 +522,24 @@ var build, buildBaseConfig;
//but grab the latest value from inside require() since it was reset //but grab the latest value from inside require() since it was reset
//since our last context reference. //since our last context reference.
layer = require._layer; layer = require._layer;
layer.specified = require.s.contexts[require.s.ctxName].specified; layer.specified = context.specified;
//Add any other files that did not have an explicit name on them.
//These are files that do not call back into require when loaded.
for (prop in layer.buildPathMap) {
if (layer.buildPathMap.hasOwnProperty(prop)) {
url = layer.buildPathMap[prop];
//Always store the url to module name mapping for use later,
//particularly for anonymous modules and tracking down files that
//did not call require.def to define a module
layer.buildFileToModule[url] = prop;
if (!layer.loadedFiles[url]) {
//Do not add plugins to build file paths since they will
//be added later, near the top of the module layer.
if (prop.indexOf("require/") !== 0) {
layer.buildFilePaths.push(url);
}
layer.loadedFiles[url] = true;
}
}
}
//Reset config //Reset config
if (module.override) { if (module.override) {
require(baseConfig); require(baseConfig);
} }
return layer; return layer;
}; };
/** /**
* Uses the module build config object to create an flattened version * Uses the module build config object to create an flattened version
* of the module, with deep dependencies included. * of the module, with deep dependencies included.
* *
* @param {Object} module the module object from the build config info. * @param {Object} module the module object from the build config info.
* *
* @param {Object} layer the layer object returned from build.traceDependencies. * @param {Object} layer the layer object returned from build.traceDependencies.
* *
* @param {Object} the build config object. * @param {Object} the build config object.
* *
* @returns {Object} with two properties: "text", the text of the flattened * @returns {Object} with two properties: "text", the text of the flattened
@ -522,10 +548,15 @@ var build, buildBaseConfig;
*/ */
build.flattenModule = function (module, layer, config) { build.flattenModule = function (module, layer, config) {
var buildFileContents = "", requireContents = "", var buildFileContents = "", requireContents = "",
pluginContents = "", pluginBuildFileContents = "", includeRequire, context = require.s.contexts._,
anonDefRegExp = /require\s*\.\s*def\s*\(\s*(\[|f|\{)/, //This regexp is not bullet-proof, and it has one optional part to
//avoid issues with some Dojo transition modules that use a
//define(\n//begin v1.x content
//for a comment.
anonDefRegExp = /(require\s*\.\s*def|define)\s*\(\s*(\/\/[^\n\r]*[\r\n])?(\[|f|\{)/,
prop, path, reqIndex, fileContents, currContents, prop, path, reqIndex, fileContents, currContents,
i, moduleName, specified, deps; i, moduleName, specified, deps, includeRequire,
parts, builder;
//Use override settings, particularly for pragmas //Use override settings, particularly for pragmas
if (module.override) { if (module.override) {
@ -540,8 +571,6 @@ var build, buildBaseConfig;
//If the file wants require.js added to the module, add it now //If the file wants require.js added to the module, add it now
requireContents = ""; requireContents = "";
pluginContents = "";
pluginBuildFileContents = "";
includeRequire = false; includeRequire = false;
if ("includeRequire" in module) { if ("includeRequire" in module) {
includeRequire = module.includeRequire; includeRequire = module.includeRequire;
@ -551,25 +580,6 @@ var build, buildBaseConfig;
buildFileContents += "require.js\n"; buildFileContents += "require.js\n";
} }
//Check for any plugins loaded, and hoist to the top, but below
//the require() definition.
specified = layer.specified;
for (prop in specified) {
if (specified.hasOwnProperty(prop)) {
if (prop.indexOf("require/") === 0) {
path = layer.buildPathMap[prop];
if (path) {
pluginBuildFileContents += path.replace(config.dir, "") + "\n";
pluginContents += pragma.process(path, fileUtil.readFile(path), config);
}
}
}
}
if (includeRequire) {
//require.js will be included so the plugins will appear right after it.
buildFileContents += pluginBuildFileContents;
}
//If there was an existing file with require in it, hoist to the top. //If there was an existing file with require in it, hoist to the top.
if (!includeRequire && layer.existingRequireUrl) { if (!includeRequire && layer.existingRequireUrl) {
reqIndex = layer.buildFilePaths.indexOf(layer.existingRequireUrl); reqIndex = layer.buildFilePaths.indexOf(layer.existingRequireUrl);
@ -584,41 +594,46 @@ var build, buildBaseConfig;
for (i = 0; (path = layer.buildFilePaths[i]); i++) { for (i = 0; (path = layer.buildFilePaths[i]); i++) {
moduleName = layer.buildFileToModule[path]; moduleName = layer.buildFileToModule[path];
//Add the contents but remove any pragmas. //Figure out if the module is a result of a build plugin, and if so,
currContents = pragma.process(path, fileUtil.readFile(path), config); //then delegate to that plugin.
parts = context.makeModuleMap(moduleName);
//If anonymous module, insert the module name. builder = parts.prefix && require.pluginBuilders[parts.prefix];
currContents = currContents.replace(anonDefRegExp, function (match, suffix) { if (builder) {
layer.modulesWithNames[moduleName] = true; if (builder.write) {
builder.write(parts.prefix, parts.name, function (input) {
//Look for CommonJS require calls inside the function if this is fileContents += input;
//an anonymous require.def call that just has a function registered. });
deps = null;
if (suffix.indexOf('f') !== -1) {
deps = parse.getAnonDeps(path, currContents);
if (deps.length) {
deps = deps.map(function (dep) {
return "'" + dep + "'";
});
} else {
deps = null;
}
} }
} else {
//Add the contents but remove any pragmas.
currContents = pragma.process(path, fileUtil.readFile(path), config);
//Adust module name if it is for a plugin //If anonymous module, insert the module name.
if (require.s.contexts._.defPlugin[moduleName]) { currContents = currContents.replace(anonDefRegExp, function (match, callName, possibleComment, suffix) {
moduleName = require.s.contexts._.defPlugin[moduleName] + '!' + moduleName;
//Mark that it is a module with a name so do not need
//a stub name insertion for it later.
layer.modulesWithNames[moduleName] = true; layer.modulesWithNames[moduleName] = true;
}
return "require.def('" + moduleName + "'," + //Look for CommonJS require calls inside the function if this is
(deps ? ('[' + deps.toString() + '],') : '') + //an anonymous define/require.def call that just has a function registered.
suffix; deps = null;
}); if (suffix.indexOf('f') !== -1) {
deps = parse.getAnonDeps(path, currContents);
fileContents += currContents; if (deps.length) {
deps = deps.map(function (dep) {
return "'" + dep + "'";
});
} else {
deps = null;
}
}
return "define('" + moduleName + "'," +
(deps ? ('[' + deps.toString() + '],') : '') +
suffix;
});
fileContents += currContents;
}
buildFileContents += path.replace(config.dir, "") + "\n"; buildFileContents += path.replace(config.dir, "") + "\n";
//Some files may not have declared a require module, and if so, //Some files may not have declared a require module, and if so,
@ -626,22 +641,12 @@ var build, buildBaseConfig;
//after the module is processed. //after the module is processed.
//If we have a name, but no defined module, then add in the placeholder. //If we have a name, but no defined module, then add in the placeholder.
if (moduleName && !layer.modulesWithNames[moduleName] && !config.skipModuleInsertion) { if (moduleName && !layer.modulesWithNames[moduleName] && !config.skipModuleInsertion) {
fileContents += 'require.def("' + moduleName + '", function(){});\n'; fileContents += 'define("' + moduleName + '", function(){});\n';
}
//If we have plugins but are not injecting require.js,
//then need to place the plugins after the require definition,
//if it was found.
if (layer.existingRequireUrl === path && !includeRequire) {
fileContents += pluginContents;
buildFileContents += pluginBuildFileContents;
pluginContents = "";
} }
} }
//Add the require file contents to the head of the file. //Add the require file contents to the head of the file.
fileContents = (requireContents ? requireContents + "\n" : "") + fileContents = (requireContents ? requireContents + "\n" : "") +
(pluginContents ? pluginContents + "\n" : "") +
fileContents; fileContents;
return { return {

Просмотреть файл

@ -1,6 +1,6 @@
/** /**
* @license RequireJS Copyright (c) 2010, The Dojo Foundation All Rights Reserved. * @license RequireJS Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */

Просмотреть файл

@ -1,6 +1,6 @@
/** /**
* @license RequireJS Copyright (c) 2010, The Dojo Foundation All Rights Reserved. * @license RequireJS Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
@ -34,7 +34,7 @@ var commonJs = {
//Get list of files to convert. //Get list of files to convert.
fileList = fileUtil.getFilteredFileList(commonJsPath, /\w/, true); fileList = fileUtil.getFilteredFileList(commonJsPath, /\w/, true);
//Normalize on front slashes and make sure the paths do not end in a slash. //Normalize on front slashes and make sure the paths do not end in a slash.
commonJsPath = commonJsPath.replace(/\\/g, "/"); commonJsPath = commonJsPath.replace(/\\/g, "/");
savePath = savePath.replace(/\\/g, "/"); savePath = savePath.replace(/\\/g, "/");
@ -60,7 +60,7 @@ var commonJs = {
//Handle JS files. //Handle JS files.
if (jsFileRegExp.test(fileName)) { if (jsFileRegExp.test(fileName)) {
moduleName = fileName.replace(commonJsPath + "/", "").replace(/\.js$/, ""); moduleName = fileName.replace(commonJsPath + "/", "").replace(/\.js$/, "");
fileContents = fileUtil.readFile(fileName); fileContents = fileUtil.readFile(fileName);
fileContents = commonJs.convert(prefix + moduleName, fileName, fileContents); fileContents = commonJs.convert(prefix + moduleName, fileName, fileContents);
fileUtil.saveUtf8File(convertedFileName, fileContents); fileUtil.saveUtf8File(convertedFileName, fileContents);
@ -77,10 +77,10 @@ var commonJs = {
* Rhino is available, otherwise a cruder regexp is used. If the regexp * Rhino is available, otherwise a cruder regexp is used. If the regexp
* is used, then the contents may not be executable, but hopefully good * is used, then the contents may not be executable, but hopefully good
* enough to use to find require() calls. * enough to use to find require() calls.
* *
* @param {String} fileContents * @param {String} fileContents
* @param {String} fileName mostly used for informative reasons if an error. * @param {String} fileName mostly used for informative reasons if an error.
* *
* @returns {String} a string of JS with comments removed. * @returns {String} a string of JS with comments removed.
*/ */
removeComments: function (fileContents, fileName) { removeComments: function (fileContents, fileName) {
@ -98,7 +98,7 @@ var commonJs = {
* Regexp for testing if there is already a require.def call in the file, * Regexp for testing if there is already a require.def call in the file,
* in which case do not try to convert it. * in which case do not try to convert it.
*/ */
defRegExp: /require\s*\.\s*def\s*\(/, defRegExp: /(require\s*\.\s*def|define)\s*\(/,
/** /**
* Regexp for testing if there is a require([]) or require(function(){}) * Regexp for testing if there is a require([]) or require(function(){})
@ -110,22 +110,24 @@ var commonJs = {
* Does the actual file conversion. * Does the actual file conversion.
* *
* @param {String} moduleName the name of the module to use for the * @param {String} moduleName the name of the module to use for the
* require.def call. * define() call.
* *
* @param {String} fileName the name of the file. * @param {String} fileName the name of the file.
* *
* @param {String} fileContents the contents of a file :) * @param {String} fileContents the contents of a file :)
* *
* @param {Boolean} skipDeps if true, require("") dependencies
* will not be searched, but the contents will just be wrapped in the
* standard require, exports, module dependencies. Only usable in sync
* environments like Node where the require("") calls can be resolved on
* the fly.
*
* @returns {String} the converted contents * @returns {String} the converted contents
*/ */
convert: function (moduleName, fileName, fileContents) { convert: function (moduleName, fileName, fileContents, skipDeps) {
//Strip out comments. //Strip out comments.
if (commonJs.useLog) {
logger.trace("fileName: " + fileName);
}
try { try {
var i, deps = [], depName, origDepName, part, pathConverted = {}, var deps = [], depName, match,
prop, reqRegExp, match,
//Remove comments //Remove comments
tempContents = commonJs.removeComments(fileContents, fileName), tempContents = commonJs.removeComments(fileContents, fileName),
baseName = moduleName.split("/"); baseName = moduleName.split("/");
@ -137,24 +139,26 @@ var commonJs = {
//Set baseName to be one directory higher than moduleName. //Set baseName to be one directory higher than moduleName.
baseName.pop(); baseName.pop();
//Reset the regexp to start at beginning of file. Do this //Reset the regexp to start at beginning of file. Do this
//since the regexp is reused across files. //since the regexp is reused across files.
commonJs.depRegExp.lastIndex = 0; commonJs.depRegExp.lastIndex = 0;
//Find dependencies in the code that was not in comments. if (!skipDeps) {
while ((match = commonJs.depRegExp.exec(tempContents))) { //Find dependencies in the code that was not in comments.
depName = match[1]; while ((match = commonJs.depRegExp.exec(tempContents))) {
if (commonJs.useLog) { depName = match[1];
logger.trace(" " + depName); if (commonJs.useLog) {
} logger.trace(" " + depName);
if (depName) { }
deps.push('"' + depName + '"'); if (depName) {
deps.push('"' + depName + '"');
}
} }
} }
//Construct the wrapper boilerplate. //Construct the wrapper boilerplate.
fileContents = 'require.def(["require", "exports", "module"' + fileContents = 'define(["require", "exports", "module"' +
(deps.length ? ', ' + deps.join(",") : '') + '], ' + (deps.length ? ', ' + deps.join(",") : '') + '], ' +
'function(require, exports, module) {\n' + 'function(require, exports, module) {\n' +
(commonJs.logConverted ? 'global._requirejs_logger.trace("Evaluating module: ' + moduleName + '");\n' : "") + (commonJs.logConverted ? 'global._requirejs_logger.trace("Evaluating module: ' + moduleName + '");\n' : "") +

Просмотреть файл

@ -1,6 +1,6 @@
/** /**
* @license RequireJS Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. * @license RequireJS Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
//Helper functions to deal with file I/O. //Helper functions to deal with file I/O.
@ -27,187 +27,187 @@ fileUtil.absPath = function (file) {
}; };
fileUtil.getFilteredFileList = function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths, /*boolean?*/startDirIsJavaObject) { fileUtil.getFilteredFileList = function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths, /*boolean?*/startDirIsJavaObject) {
//summary: Recurses startDir and finds matches to the files that match regExpFilters.include //summary: Recurses startDir and finds matches to the files that match regExpFilters.include
//and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters, //and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters,
//and it will be treated as the "include" case. //and it will be treated as the "include" case.
//Ignores files/directories that start with a period (.). //Ignores files/directories that start with a period (.).
var files = [], topDir, regExpInclude, regExpExclude, dirFileArray, var files = [], topDir, regExpInclude, regExpExclude, dirFileArray,
i, file, filePath, ok, dirFiles; i, file, filePath, ok, dirFiles;
topDir = startDir; topDir = startDir;
if (!startDirIsJavaObject) { if (!startDirIsJavaObject) {
topDir = new java.io.File(startDir); topDir = new java.io.File(startDir);
} }
regExpInclude = regExpFilters.include || regExpFilters; regExpInclude = regExpFilters.include || regExpFilters;
regExpExclude = regExpFilters.exclude || null; regExpExclude = regExpFilters.exclude || null;
if (topDir.exists()) { if (topDir.exists()) {
dirFileArray = topDir.listFiles(); dirFileArray = topDir.listFiles();
for (i = 0; i < dirFileArray.length; i++) { for (i = 0; i < dirFileArray.length; i++) {
file = dirFileArray[i]; file = dirFileArray[i];
if (file.isFile()) { if (file.isFile()) {
filePath = file.getPath(); filePath = file.getPath();
if (makeUnixPaths) { if (makeUnixPaths) {
//Make sure we have a JS string. //Make sure we have a JS string.
filePath = String(filePath); filePath = String(filePath);
if (filePath.indexOf("/") === -1) { if (filePath.indexOf("/") === -1) {
filePath = filePath.replace(/\\/g, "/"); filePath = filePath.replace(/\\/g, "/");
} }
} }
ok = true;
if (regExpInclude) {
ok = filePath.match(regExpInclude);
}
if (ok && regExpExclude) {
ok = !filePath.match(regExpExclude);
}
if (ok && !file.getName().match(/^\./)) { ok = true;
files.push(filePath); if (regExpInclude) {
} ok = filePath.match(regExpInclude);
} else if (file.isDirectory() && !file.getName().match(/^\./)) { }
dirFiles = this.getFilteredFileList(file, regExpFilters, makeUnixPaths, true); if (ok && regExpExclude) {
files.push.apply(files, dirFiles); ok = !filePath.match(regExpExclude);
} }
}
}
return files; //Array if (ok && !file.getName().match(/^\./)) {
files.push(filePath);
}
} else if (file.isDirectory() && !file.getName().match(/^\./)) {
dirFiles = this.getFilteredFileList(file, regExpFilters, makeUnixPaths, true);
files.push.apply(files, dirFiles);
}
}
}
return files; //Array
}; };
fileUtil.copyDir = function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) { fileUtil.copyDir = function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) {
//summary: copies files from srcDir to destDir using the regExpFilter to determine if the //summary: copies files from srcDir to destDir using the regExpFilter to determine if the
//file should be copied. Returns a list file name strings of the destinations that were copied. //file should be copied. Returns a list file name strings of the destinations that were copied.
regExpFilter |= /\w/; regExpFilter = regExpFilter || /\w/;
var fileNames = fileUtil.getFilteredFileList(srcDir, regExpFilter, true), var fileNames = fileUtil.getFilteredFileList(srcDir, regExpFilter, true),
copiedFiles = [], i, srcFileName, destFileName; copiedFiles = [], i, srcFileName, destFileName;
for (i = 0; i < fileNames.length; i++) { for (i = 0; i < fileNames.length; i++) {
srcFileName = fileNames[i]; srcFileName = fileNames[i];
destFileName = srcFileName.replace(srcDir, destDir); destFileName = srcFileName.replace(srcDir, destDir);
if (fileUtil.copyFile(srcFileName, destFileName, onlyCopyNew)) { if (fileUtil.copyFile(srcFileName, destFileName, onlyCopyNew)) {
copiedFiles.push(destFileName); copiedFiles.push(destFileName);
} }
} }
return copiedFiles.length ? copiedFiles : null; //Array or null return copiedFiles.length ? copiedFiles : null; //Array or null
}; };
fileUtil.copyFile = function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) { fileUtil.copyFile = function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) {
//summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if //summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if
//srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred. //srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred.
var destFile = new java.io.File(destFileName), srcFile, parentDir, var destFile = new java.io.File(destFileName), srcFile, parentDir,
srcChannel, destChannel; srcChannel, destChannel;
//logger.trace("Src filename: " + srcFileName); //logger.trace("Src filename: " + srcFileName);
//logger.trace("Dest filename: " + destFileName); //logger.trace("Dest filename: " + destFileName);
//If onlyCopyNew is true, then compare dates and only copy if the src is newer //If onlyCopyNew is true, then compare dates and only copy if the src is newer
//than dest. //than dest.
if (onlyCopyNew) { if (onlyCopyNew) {
srcFile = new java.io.File(srcFileName); srcFile = new java.io.File(srcFileName);
if (destFile.exists() && destFile.lastModified() >= srcFile.lastModified()) { if (destFile.exists() && destFile.lastModified() >= srcFile.lastModified()) {
return false; //Boolean return false; //Boolean
} }
} }
//Make sure destination dir exists. //Make sure destination dir exists.
parentDir = destFile.getParentFile(); parentDir = destFile.getParentFile();
if (!parentDir.exists()) { if (!parentDir.exists()) {
if (!parentDir.mkdirs()) { if (!parentDir.mkdirs()) {
throw "Could not create directory: " + parentDir.getAbsolutePath(); throw "Could not create directory: " + parentDir.getAbsolutePath();
} }
} }
//Java's version of copy file. //Java's version of copy file.
srcChannel = new java.io.FileInputStream(srcFileName).getChannel(); srcChannel = new java.io.FileInputStream(srcFileName).getChannel();
destChannel = new java.io.FileOutputStream(destFileName).getChannel(); destChannel = new java.io.FileOutputStream(destFileName).getChannel();
destChannel.transferFrom(srcChannel, 0, srcChannel.size()); destChannel.transferFrom(srcChannel, 0, srcChannel.size());
srcChannel.close(); srcChannel.close();
destChannel.close(); destChannel.close();
return true; //Boolean return true; //Boolean
}; };
fileUtil.readFile = function (/*String*/path, /*String?*/encoding) { fileUtil.readFile = function (/*String*/path, /*String?*/encoding) {
//summary: reads a file and returns a string //summary: reads a file and returns a string
encoding = encoding || "utf-8"; encoding = encoding || "utf-8";
var file = new java.io.File(path), var file = new java.io.File(path),
lineSeparator = fileUtil.getLineSeparator(), lineSeparator = fileUtil.getLineSeparator(),
input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
stringBuffer, line; stringBuffer, line;
try { try {
stringBuffer = new java.lang.StringBuffer(); stringBuffer = new java.lang.StringBuffer();
line = input.readLine(); line = input.readLine();
// Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
// http://www.unicode.org/faq/utf_bom.html // http://www.unicode.org/faq/utf_bom.html
// Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
if (line && line.length() && line.charAt(0) === 0xfeff) { if (line && line.length() && line.charAt(0) === 0xfeff) {
// Eat the BOM, since we've already found the encoding on this file, // Eat the BOM, since we've already found the encoding on this file,
// and we plan to concatenating this buffer with others; the BOM should // and we plan to concatenating this buffer with others; the BOM should
// only appear at the top of a file. // only appear at the top of a file.
line = line.substring(1); line = line.substring(1);
} }
while (line !== null) { while (line !== null) {
stringBuffer.append(line); stringBuffer.append(line);
stringBuffer.append(lineSeparator); stringBuffer.append(lineSeparator);
line = input.readLine(); line = input.readLine();
} }
//Make sure we return a JavaScript string and not a Java string. //Make sure we return a JavaScript string and not a Java string.
return String(stringBuffer.toString()); //String return String(stringBuffer.toString()); //String
} finally { } finally {
input.close(); input.close();
} }
}; };
fileUtil.saveUtf8File = function (/*String*/fileName, /*String*/fileContents) { fileUtil.saveUtf8File = function (/*String*/fileName, /*String*/fileContents) {
//summary: saves a file using UTF-8 encoding. //summary: saves a file using UTF-8 encoding.
fileUtil.saveFile(fileName, fileContents, "utf-8"); fileUtil.saveFile(fileName, fileContents, "utf-8");
}; };
fileUtil.saveFile = function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) { fileUtil.saveFile = function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) {
//summary: saves a file. //summary: saves a file.
var outFile = new java.io.File(fileName), outWriter, parentDir, os; var outFile = new java.io.File(fileName), outWriter, parentDir, os;
parentDir = outFile.getAbsoluteFile().getParentFile();
if (!parentDir.exists()) {
if (!parentDir.mkdirs()) {
throw "Could not create directory: " + parentDir.getAbsolutePath();
}
}
if (encoding) {
outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile), encoding);
} else {
outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile));
}
os = new java.io.BufferedWriter(outWriter); parentDir = outFile.getAbsoluteFile().getParentFile();
try { if (!parentDir.exists()) {
os.write(fileContents); if (!parentDir.mkdirs()) {
} finally { throw "Could not create directory: " + parentDir.getAbsolutePath();
os.close(); }
} }
if (encoding) {
outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile), encoding);
} else {
outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile));
}
os = new java.io.BufferedWriter(outWriter);
try {
os.write(fileContents);
} finally {
os.close();
}
}; };
fileUtil.deleteFile = function (/*String*/fileName) { fileUtil.deleteFile = function (/*String*/fileName) {
//summary: deletes a file or directory if it exists. //summary: deletes a file or directory if it exists.
var file = new java.io.File(fileName), files, i; var file = new java.io.File(fileName), files, i;
if (file.exists()) { if (file.exists()) {
if (file.isDirectory()) { if (file.isDirectory()) {
files = file.listFiles(); files = file.listFiles();
for (i = 0; i < files.length; i++) { for (i = 0; i < files.length; i++) {
this.deleteFile(files[i]); this.deleteFile(files[i]);
} }
} }
file["delete"](); file["delete"]();
} }
}; };

Просмотреть файл

@ -1,6 +1,6 @@
/** /**
* @license Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. * @license Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */

Просмотреть файл

@ -1,6 +1,6 @@
/** /**
* @license RequireJS Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. * @license RequireJS Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
var logger = { var logger = {

Просмотреть файл

@ -1,10 +1,10 @@
/** /**
* @license Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. * @license Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
/*jslint plusplus: false */ /*jslint plusplus: false, nomen: false, regexp: false */
/*global require: false, java: false, Packages: false, logger: false, fileUtil: false, /*global require: false, java: false, Packages: false, logger: false, fileUtil: false,
readFile: false, lang: false */ readFile: false, lang: false */
@ -14,8 +14,6 @@ var optimize;
(function () { (function () {
var JSSourceFilefromCode, var JSSourceFilefromCode,
textDepRegExp = /["'](text)\!([^"']+)["']/g,
relativeDefRegExp = /require\s*\.\s*def\s*\(\s*['"]([^'"]+)['"]/g,
cssImportRegExp = /\@import\s+(url\()?\s*([^);]+)\s*(\))?([\w, ]*)(;)?/g, cssImportRegExp = /\@import\s+(url\()?\s*([^);]+)\s*(\))?([\w, ]*)(;)?/g,
cssUrlRegExp = /\url\(\s*([^\)]+)\s*\)?/g; cssUrlRegExp = /\url\(\s*([^\)]+)\s*\)?/g;
@ -30,18 +28,6 @@ var optimize;
return JSSourceFilefromCode.invoke(null, [filename, content]); return JSSourceFilefromCode.invoke(null, [filename, content]);
} }
//Adds escape sequences for non-visual characters, double quote and backslash
//and surrounds with double quotes to form a valid string literal.
//Assumes the string will be in a single quote string value.
function jsEscape(text) {
return text.replace(/(['\\])/g, '\\$1')
.replace(/[\f]/g, "\\f")
.replace(/[\b]/g, "\\b")
.replace(/[\n]/g, "\\n")
.replace(/[\t]/g, "\\t")
.replace(/[\r]/g, "\\r");
}
/** /**
* If an URL from a CSS url value contains start/end quotes, remove them. * If an URL from a CSS url value contains start/end quotes, remove them.
* This is not done in the regexp, since my regexp fu is not that strong, * This is not done in the regexp, since my regexp fu is not that strong,
@ -85,9 +71,9 @@ var optimize;
if (mediaTypes && ((mediaTypes.replace(/^\s\s*/, '').replace(/\s\s*$/, '')) !== "all")) { if (mediaTypes && ((mediaTypes.replace(/^\s\s*/, '').replace(/\s\s*$/, '')) !== "all")) {
return fullMatch; return fullMatch;
} }
importFileName = cleanCssUrlQuotes(importFileName); importFileName = cleanCssUrlQuotes(importFileName);
//Ignore the file import if it is part of an ignore list. //Ignore the file import if it is part of an ignore list.
if (cssImportIgnore && cssImportIgnore.indexOf(importFileName + ",") !== -1) { if (cssImportIgnore && cssImportIgnore.indexOf(importFileName + ",") !== -1) {
return fullMatch; return fullMatch;
@ -95,7 +81,7 @@ var optimize;
//Make sure we have a unix path for the rest of the operation. //Make sure we have a unix path for the rest of the operation.
importFileName = importFileName.replace(lang.backSlashRegExp, "/"); importFileName = importFileName.replace(lang.backSlashRegExp, "/");
try { try {
//if a relative path, then tack on the filePath. //if a relative path, then tack on the filePath.
//If it is not a relative path, then the readFile below will fail, //If it is not a relative path, then the readFile below will fail,
@ -118,7 +104,7 @@ var optimize;
importContents = importContents.replace(cssUrlRegExp, function (fullMatch, urlMatch) { importContents = importContents.replace(cssUrlRegExp, function (fullMatch, urlMatch) {
fixedUrlMatch = cleanCssUrlQuotes(urlMatch); fixedUrlMatch = cleanCssUrlQuotes(urlMatch);
fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/"); fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/");
//Only do the work for relative URLs. Skip things that start with / or have //Only do the work for relative URLs. Skip things that start with / or have
//a protocol. //a protocol.
colonIndex = fixedUrlMatch.indexOf(":"); colonIndex = fixedUrlMatch.indexOf(":");
@ -141,10 +127,10 @@ var optimize;
} }
} }
} }
return "url(" + parts.join("/") + ")"; return "url(" + parts.join("/") + ")";
}); });
return importContents; return importContents;
} catch (e) { } catch (e) {
logger.trace(fileName + "\n Cannot inline css import, skipping: " + importFileName); logger.trace(fileName + "\n Cannot inline css import, skipping: " + importFileName);
@ -154,101 +140,38 @@ var optimize;
} }
optimize = { optimize = {
closure: function (fileName, fileContents, keepLines) { closure: function (fileName, fileContents, keepLines, config) {
config = config || {};
var jscomp = Packages.com.google.javascript.jscomp, var jscomp = Packages.com.google.javascript.jscomp,
flags = Packages.com.google.common.flags, flags = Packages.com.google.common.flags,
//Fake extern //Fake extern
externSourceFile = closurefromCode("fakeextern.js", " "), externSourceFile = closurefromCode("fakeextern.js", " "),
//Set up source input //Set up source input
jsSourceFile = closurefromCode(String(fileName), String(fileContents)), jsSourceFile = closurefromCode(String(fileName), String(fileContents)),
options, FLAG_compilation_level, compiler, options, option, FLAG_compilation_level, compiler,
Compiler = Packages.com.google.javascript.jscomp.Compiler; Compiler = Packages.com.google.javascript.jscomp.Compiler;
logger.trace("Minifying file: " + fileName); logger.trace("Minifying file: " + fileName);
//Set up options //Set up options
options = new jscomp.CompilerOptions(); options = new jscomp.CompilerOptions();
options.prettyPrint = keepLines; for (option in config.CompilerOptions) {
// options are false by default and jslint wanted an if statement in this for loop
if (config.CompilerOptions[option]) {
options[option] = config.CompilerOptions[option];
}
FLAG_compilation_level = flags.Flag.value(jscomp.CompilationLevel.SIMPLE_OPTIMIZATIONS); }
options.prettyPrint = keepLines || options.prettyPrint;
FLAG_compilation_level = flags.Flag.value(jscomp.CompilationLevel[config.CompilationLevel || 'SIMPLE_OPTIMIZATIONS']);
FLAG_compilation_level.get().setOptionsForCompilationLevel(options); FLAG_compilation_level.get().setOptionsForCompilationLevel(options);
//Trigger the compiler //Trigger the compiler
Compiler.setLoggingLevel(Packages.java.util.logging.Level.WARNING); Compiler.setLoggingLevel(Packages.java.util.logging.Level[config.loggingLevel || 'WARNING']);
compiler = new Compiler(); compiler = new Compiler();
compiler.compile(externSourceFile, jsSourceFile, options); compiler.compile(externSourceFile, jsSourceFile, options);
return compiler.toSource(); return compiler.toSource();
},
//Inlines text! dependencies.
inlineText: function (fileName, fileContents) {
return fileContents.replace(textDepRegExp, function (match, prefix, dep, offset) {
var parts, modName, ext, strip, content, normalizedName, index,
defSegment, defStart, defMatch, tempMatch, defName;
parts = dep.split("!");
modName = parts[0];
ext = "";
strip = parts[1];
content = parts[2];
//Extension is part of modName
index = modName.lastIndexOf(".");
if (index !== -1) {
ext = modName.substring(index + 1, modName.length);
modName = modName.substring(0, index);
}
//Adjust the text path to be a full name, not a relative
//one, if needed.
normalizedName = modName;
if (modName.charAt(0) === ".") {
//Need to backtrack an arbitrary amount in the file
//to find the require.def call
//that includes this relative name, to find what path to use
//for the relative part.
defStart = offset - 1000;
if (defStart < 0) {
defStart = 0;
}
defSegment = fileContents.substring(defStart, offset);
//Take the last match, the one closest to current text! string.
relativeDefRegExp.lastIndex = 0;
while ((tempMatch = relativeDefRegExp.exec(defSegment)) !== null) {
defMatch = tempMatch;
}
if (!defMatch) {
throw new Error("Cannot resolve relative dependency: " + dep + " in file: " + fileName);
}
//Take the last match, the one closest to current text! string.
defName = defMatch[1];
normalizedName = require.normalizeName(modName, defName);
}
if (strip !== "strip") {
content = strip;
strip = null;
}
if (content) {
//Already an inlined resource, return.
return match;
} else {
content = readFile(require.nameToUrl(normalizedName, "." + ext, require.s.ctxName));
if (strip) {
content = require.textStrip(content);
}
return "'" + prefix +
"!" + modName +
(ext ? "." + ext : "") +
(strip ? "!strip" : "") +
"!" + jsEscape(content) + "'";
}
});
}, },
/** /**
@ -265,24 +188,14 @@ var optimize;
var doClosure = (config.optimize + "").indexOf("closure") === 0, var doClosure = (config.optimize + "").indexOf("closure") === 0,
fileContents; fileContents;
if (config.inlineText && !optimize.textLoaded) {
//Make sure text extension is loaded.
require(["require/text"]);
optimize.textLoaded = true;
}
fileContents = fileUtil.readFile(fileName); fileContents = fileUtil.readFile(fileName);
//Inline text files.
if (config.inlineText) {
fileContents = optimize.inlineText(fileName, fileContents);
}
//Optimize the JS files if asked. //Optimize the JS files if asked.
if (doClosure) { if (doClosure) {
fileContents = optimize.closure(fileName, fileContents = optimize.closure(fileName,
fileContents, fileContents,
(config.optimize.indexOf(".keepLines") !== -1)); (config.optimize.indexOf(".keepLines") !== -1),
config.closure);
} }
fileUtil.saveUtf8File(outFileName, fileContents); fileUtil.saveUtf8File(outFileName, fileContents);
@ -341,7 +254,7 @@ var optimize;
*/ */
css: function (startDir, config) { css: function (startDir, config) {
if (config.optimizeCss.indexOf("standard") !== -1) { if (config.optimizeCss.indexOf("standard") !== -1) {
var i, fileName, startIndex, endIndex, originalFileContents, fileContents, var i, fileName,
fileList = fileUtil.getFilteredFileList(startDir, /\.css$/, true); fileList = fileUtil.getFilteredFileList(startDir, /\.css$/, true);
if (fileList) { if (fileList) {
for (i = 0; i < fileList.length; i++) { for (i = 0; i < fileList.length; i++) {

Просмотреть файл

@ -1,6 +1,6 @@
/** /**
* @license Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. * @license Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
@ -47,6 +47,26 @@ var parse;
return String(node.getString()); return String(node.getString());
} }
/**
* Calls compiler.parse, and if any errors, throws.
*/
function compilerParse(jsSourceFile, fileName) {
var result = compiler.parse(jsSourceFile),
errorManager = compiler.getErrorManager(),
errorMsg = '', errors, i;
if (errorManager.getErrorCount() > 0) {
errorMsg += 'ERROR(S) in file: ' + fileName + ':\n';
errors = errorManager.getErrors();
for (i = 0; i < errors.length; i++) {
errorMsg += errors[i].toString() + '\n';
}
throw new Error(errorMsg);
}
return result;
}
/** /**
* Validates a node as being an object literal (like for i18n bundles) * Validates a node as being an object literal (like for i18n bundles)
* or an array literal with just string members. * or an array literal with just string members.
@ -60,7 +80,7 @@ var parse;
return true; return true;
} }
//Dependencies can be an object literal or an array. //Dependencies can be an object literal or an array.
if (type !== ARRAYLIT) { if (type !== ARRAYLIT) {
return false; return false;
} }
@ -74,18 +94,18 @@ var parse;
} }
/** /**
* Main parse function. Returns a string of any valid require or require.def * Main parse function. Returns a string of any valid require or define/require.def
* calls as part of one JavaScript source string. * calls as part of one JavaScript source string.
* @param {String} fileName * @param {String} fileName
* @param {String} fileContents * @param {String} fileContents
* @returns {String} JS source string or null, if no require or require.def * @returns {String} JS source string or null, if no require or define/require.def
* calls are found. * calls are found.
*/ */
parse = function (fileName, fileContents) { parse = function (fileName, fileContents) {
//Set up source input //Set up source input
var matches = [], result = null, var matches = [], result = null,
jsSourceFile = closurefromCode(String(fileName), String(fileContents)), jsSourceFile = closurefromCode(String(fileName), String(fileContents)),
astRoot = compiler.parse(jsSourceFile); astRoot = compilerParse(jsSourceFile, fileName);
parse.recurse(astRoot, matches); parse.recurse(astRoot, matches);
@ -109,7 +129,7 @@ var parse;
matches.push(parsed); matches.push(parsed);
} }
parse.recurse(node, matches); parse.recurse(node, matches);
} }
}; };
/** /**
@ -120,15 +140,15 @@ var parse;
*/ */
parse.definesRequire = function (fileName, fileContents) { parse.definesRequire = function (fileName, fileContents) {
var jsSourceFile = closurefromCode(String(fileName), String(fileContents)), var jsSourceFile = closurefromCode(String(fileName), String(fileContents)),
astRoot = compiler.parse(jsSourceFile); astRoot = compilerParse(jsSourceFile, fileName);
return parse.nodeHasRequire(astRoot); return parse.nodeHasRequire(astRoot);
}; };
/** /**
* Finds require("") calls inside a CommonJS anonymous module wrapped in a * Finds require("") calls inside a CommonJS anonymous module wrapped in a
* require.def(function(require, exports, module){}) wrapper. These dependencies * define/require.def(function(require, exports, module){}) wrapper. These dependencies
* will be added to a modified require.def call that lists the dependencies * will be added to a modified define() call that lists the dependencies
* on the outside of the function. * on the outside of the function.
* @param {String} fileName * @param {String} fileName
* @param {String} fileContents * @param {String} fileContents
@ -137,10 +157,10 @@ var parse;
*/ */
parse.getAnonDeps = function (fileName, fileContents) { parse.getAnonDeps = function (fileName, fileContents) {
var jsSourceFile = closurefromCode(String(fileName), String(fileContents)), var jsSourceFile = closurefromCode(String(fileName), String(fileContents)),
astRoot = compiler.parse(jsSourceFile), astRoot = compilerParse(jsSourceFile, fileName),
deps = [], deps = [],
defFunc = parse.findAnonRequireDefCallback(astRoot); defFunc = parse.findAnonRequireDefCallback(astRoot);
//Now look inside the def call's function for require calls. //Now look inside the def call's function for require calls.
if (defFunc) { if (defFunc) {
parse.findRequireDepNames(defFunc, deps); parse.findRequireDepNames(defFunc, deps);
@ -174,6 +194,16 @@ var parse;
return func; return func;
} }
} }
} else if (node.getType() === EXPR_RESULT &&
node.getFirstChild().getType() === CALL &&
node.getFirstChild().getFirstChild().getType() === NAME &&
nodeString(node.getFirstChild().getFirstChild()) === "define") {
func = node.getFirstChild().getFirstChild().getLastSibling();
if (func.getType() === FUNCTION) {
//Bingo.
return func;
}
} }
//Check child nodes //Check child nodes
@ -253,28 +283,95 @@ var parse;
return false; return false;
}; };
function optionalString(node) {
var str = null;
if (node) {
str = parse.nodeToString(node);
//Need to trim off trailing ; that is added by nodeToString too.
if (str.charAt(str.length - 1) === ';') {
str = str.slice(0, str.length - 1);
}
}
return str;
}
/** /**
* Determines if a specific node is a valid require or require.def call. * Convert a require/require.def/define call to a string if it is a valid
* call via static analysis of dependencies.
* @param {String} callName the name of call (require or define)
* @param {Packages.com.google.javascript.rhino.Node} the config node inside the call
* @param {Packages.com.google.javascript.rhino.Node} the name node inside the call
* @param {Packages.com.google.javascript.rhino.Node} the deps node inside the call
*/
parse.callToString = function (callName, config, name, deps) {
//If name is an array, it means it is an anonymous module,
//so adjust args appropriately. An anonymous module could
//have a FUNCTION as the name type, but just ignore those
//since we just want to find dependencies.
//TODO: CHANGE THIS if/when support using a tostring
//on function to find CommonJS dependencies.
var configString, nameString, depString;
if (name) {
if (name.getType() === ARRAYLIT) {
deps = name;
}
}
if (deps && !validateDeps(deps)) {
return null;
}
//Only serialize the call name, config, module name and dependencies,
//otherwise could get local variable names for module value.
configString = config && config.getType() === OBJECTLIT && optionalString(config);
nameString = optionalString(name);
depString = optionalString(deps);
return callName + "(" +
(configString ? configString : "") +
(nameString ? (configString ? "," : "") + nameString : "") +
(depString ? (configString || nameString ? "," : "") + depString : "") +
");";
};
/**
* Determines if a specific node is a valid require or define/require.def call.
* @param {Packages.com.google.javascript.rhino.Node} node * @param {Packages.com.google.javascript.rhino.Node} node
* *
* @returns {String} a JS source string with the valid require call. * @returns {String} a JS source string with the valid require/define call.
* Otherwise null. * Otherwise null.
*/ */
parse.parseNode = function (node) { parse.parseNode = function (node) {
var call, methodName, targetName, name, deps, callChildCount; var call, methodName, targetName, name, config, deps, callChildCount;
if (node.getType() === EXPR_RESULT && node.getFirstChild().getType() === CALL) { if (node.getType() === EXPR_RESULT && node.getFirstChild().getType() === CALL) {
call = node.getFirstChild(); call = node.getFirstChild();
if (call.getFirstChild().getType() === NAME && if (call.getFirstChild().getType() === NAME &&
nodeString(call.getFirstChild()) === "require") { nodeString(call.getFirstChild()) === "require") {
//It is a plain require() call. //It is a plain require() call.
deps = call.getChildAtIndex(1); config = call.getChildAtIndex(1);
if (!validateDeps(deps)) { deps = call.getChildAtIndex(2);
if (config.getType() === ARRAYLIT) {
deps = config;
config = null;
}
if (!deps || !validateDeps(deps)) {
return null; return null;
} }
return parse.nodeToString(call);
return parse.callToString("require", null, null, deps);
} else if (call.getType() === CALL &&
call.getFirstChild().getType() === NAME &&
nodeString(call.getFirstChild()) === "define") {
//A define call
name = call.getChildAtIndex(1);
deps = call.getChildAtIndex(2);
return parse.callToString("define", null, name, deps);
} else if (call.getFirstChild().getType() === GETPROP && } else if (call.getFirstChild().getType() === GETPROP &&
call.getFirstChild().getFirstChild().getType() === NAME && call.getFirstChild().getFirstChild().getType() === NAME &&
@ -289,21 +386,7 @@ var parse;
name = call.getChildAtIndex(1); name = call.getChildAtIndex(1);
deps = call.getChildAtIndex(2); deps = call.getChildAtIndex(2);
//If name is an array, it means it is an anonymous module, return parse.callToString("define", null, name, deps);
//so adjust args appropriately. An anonymous module could
//have a FUNCTION as the name type, but just ignore those
//since we just want to find dependencies.
//TODO: CHANGE THIS if/when support using a tostring
//on function to find CommonJS dependencies.
if (name.getType() === ARRAYLIT) {
deps = name;
}
if (deps && !validateDeps(deps)) {
return null;
}
return parse.nodeToString(call);
} else if (methodName === "modify") { } else if (methodName === "modify") {
//A require.modify() call //A require.modify() call

Просмотреть файл

@ -1,6 +1,6 @@
/** /**
* @license Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. * @license Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
@ -12,6 +12,7 @@
var pragma = { var pragma = {
conditionalRegExp: /(exclude|include)Start\s*\(\s*["'](\w+)["']\s*,(.*)\)/, conditionalRegExp: /(exclude|include)Start\s*\(\s*["'](\w+)["']\s*,(.*)\)/,
useStrictRegExp: /['"]use strict['"];/g, useStrictRegExp: /['"]use strict['"];/g,
hasRegExp: /has\s*\(\s*['"]([^'"]+)['"]\)/g,
removeStrict: function (contents, config) { removeStrict: function (contents, config) {
return config.useStrict ? contents : contents.replace(pragma.useStrictRegExp, ''); return config.useStrict ? contents : contents.replace(pragma.useStrictRegExp, '');
@ -27,11 +28,17 @@ var pragma = {
endMarkerIndex, shouldInclude, startLength, pragmas = config.pragmas, endMarkerIndex, shouldInclude, startLength, pragmas = config.pragmas,
//Legacy arg defined to help in dojo conversion script. Remove later //Legacy arg defined to help in dojo conversion script. Remove later
//when dojo no longer needs conversion: //when dojo no longer needs conversion:
kwArgs = { kwArgs = pragmas;
profileProperties: {
hostenvType: "browser" //Replace has references if desired
if (config.has) {
fileContents = fileContents.replace(pragma.hasRegExp, function (match, test) {
if (test in config.has) {
return !!config.has[test];
} }
}; return match;
});
}
//If pragma work is not desired, skip it. //If pragma work is not desired, skip it.
if (config.skipPragmas) { if (config.skipPragmas) {
@ -44,10 +51,10 @@ var pragma = {
if (lineEndIndex === -1) { if (lineEndIndex === -1) {
lineEndIndex = fileContents.length - 1; lineEndIndex = fileContents.length - 1;
} }
//Increment startIndex past the line so the next conditional search can be done. //Increment startIndex past the line so the next conditional search can be done.
startIndex = lineEndIndex + 1; startIndex = lineEndIndex + 1;
//Break apart the conditional. //Break apart the conditional.
conditionLine = fileContents.substring(foundIndex, lineEndIndex + 1); conditionLine = fileContents.substring(foundIndex, lineEndIndex + 1);
matches = conditionLine.match(pragma.conditionalRegExp); matches = conditionLine.match(pragma.conditionalRegExp);
@ -66,29 +73,29 @@ var pragma = {
conditionLine + conditionLine +
" failed with this error: " + e; " failed with this error: " + e;
} }
//Find the endpoint marker. //Find the endpoint marker.
endRegExp = new RegExp('\\/\\/\\>\\>\\s*' + type + 'End\\(\\s*[\'"]' + marker + '[\'"]\\s*\\)', "g"); endRegExp = new RegExp('\\/\\/\\>\\>\\s*' + type + 'End\\(\\s*[\'"]' + marker + '[\'"]\\s*\\)', "g");
endMatches = endRegExp.exec(fileContents.substring(startIndex, fileContents.length)); endMatches = endRegExp.exec(fileContents.substring(startIndex, fileContents.length));
if (endMatches) { if (endMatches) {
endMarkerIndex = startIndex + endRegExp.lastIndex - endMatches[0].length; endMarkerIndex = startIndex + endRegExp.lastIndex - endMatches[0].length;
//Find the next line return based on the match position. //Find the next line return based on the match position.
lineEndIndex = fileContents.indexOf("\n", endMarkerIndex); lineEndIndex = fileContents.indexOf("\n", endMarkerIndex);
if (lineEndIndex === -1) { if (lineEndIndex === -1) {
lineEndIndex = fileContents.length - 1; lineEndIndex = fileContents.length - 1;
} }
//Should we include the segment? //Should we include the segment?
shouldInclude = ((type === "exclude" && !isTrue) || (type === "include" && isTrue)); shouldInclude = ((type === "exclude" && !isTrue) || (type === "include" && isTrue));
//Remove the conditional comments, and optionally remove the content inside //Remove the conditional comments, and optionally remove the content inside
//the conditional comments. //the conditional comments.
startLength = startIndex - foundIndex; startLength = startIndex - foundIndex;
fileContents = fileContents.substring(0, foundIndex) + fileContents = fileContents.substring(0, foundIndex) +
(shouldInclude ? fileContents.substring(startIndex, endMarkerIndex) : "") + (shouldInclude ? fileContents.substring(startIndex, endMarkerIndex) : "") +
fileContents.substring(lineEndIndex + 1, fileContents.length); fileContents.substring(lineEndIndex + 1, fileContents.length);
//Move startIndex to foundIndex, since that is the new position in the file //Move startIndex to foundIndex, since that is the new position in the file
//where we need to look for more conditionals in the next while loop pass. //where we need to look for more conditionals in the next while loop pass.
startIndex = foundIndex; startIndex = foundIndex;
@ -97,7 +104,7 @@ var pragma = {
fileName + fileName +
". Cannot find end marker for conditional comment: " + ". Cannot find end marker for conditional comment: " +
conditionLine; conditionLine;
} }
} }
} }

110
tools/webbuild/requirejs/build/jslib/requirePatch.js Normal file → Executable file
Просмотреть файл

@ -1,6 +1,6 @@
/** /**
* @license RequireJS Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. * @license RequireJS Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
/* /*
@ -9,12 +9,13 @@
/*jslint nomen: false, plusplus: false, regexp: false */ /*jslint nomen: false, plusplus: false, regexp: false */
/*global load: false, require: false, logger: false, setTimeout: true, /*global load: false, require: false, logger: false, setTimeout: true,
pragma: false, Packages: false, parse: false, java: true */ pragma: false, Packages: false, parse: false, java: true, define: true */
"use strict"; "use strict";
(function () { (function () {
var layer, var layer,
lineSeparator = java.lang.System.getProperty("line.separator"), lineSeparator = java.lang.System.getProperty("line.separator"),
pluginBuilderRegExp = /(["']?)pluginBuilder(["']?)\s*[=\:]\s*["']([^'"\s]+)["']/,
oldDef; oldDef;
//A file read function that can deal with BOMs //A file read function that can deal with BOMs
@ -26,10 +27,10 @@
try { try {
stringBuffer = new java.lang.StringBuffer(); stringBuffer = new java.lang.StringBuffer();
line = input.readLine(); line = input.readLine();
// Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
// http://www.unicode.org/faq/utf_bom.html // http://www.unicode.org/faq/utf_bom.html
// Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
if (line && line.length() && line.charAt(0) === 0xfeff) { if (line && line.length() && line.charAt(0) === 0xfeff) {
@ -53,7 +54,7 @@
/** Reset state for each build layer pass. */ /** Reset state for each build layer pass. */
require._buildReset = function () { require._buildReset = function () {
//Clear up the existing context. //Clear up the existing context.
delete require.s.contexts[require.s.ctxName]; delete require.s.contexts._;
//These variables are not contextName-aware since the build should //These variables are not contextName-aware since the build should
//only have one context. //only have one context.
@ -77,8 +78,11 @@
*/ */
require._isSupportedBuildUrl = function (url) { require._isSupportedBuildUrl = function (url) {
//Ignore URLs with protocols or question marks, means either network //Ignore URLs with protocols or question marks, means either network
//access is needed to fetch it or it is too dynamic. //access is needed to fetch it or it is too dynamic. Note that
return url.indexOf(":") === -1 && url.indexOf("?") === -1; //on Windows, full paths are used for some urls, which include
//the drive, like c:/something, so need to test for something other
//than just a colon.
return url.indexOf("://") === -1 && url.indexOf("?") === -1;
}; };
//Override require.def to catch modules that just define an object, so that //Override require.def to catch modules that just define an object, so that
@ -89,33 +93,48 @@
//This function signature does not have to be exact, just match what we //This function signature does not have to be exact, just match what we
//are looking for. //are looking for.
require.def = function (name, obj) { define = require.def = function (name, obj) {
if (typeof name === "string" && !require.isArray(obj) && !require.isFunction(obj)) { if (typeof name === "string") {
layer.modulesWithNames[name] = true; layer.modulesWithNames[name] = true;
} }
return oldDef.apply(require, arguments); return oldDef.apply(require, arguments);
}; };
//Add some utilities for plugins/pluginBuilders
require._readFile = _readFile;
require._fileExists = function (path) {
return (new java.io.File(path)).exists();
};
require.pluginBuilders = {};
//Override load so that the file paths can be collected. //Override load so that the file paths can be collected.
require.load = function (moduleName, contextName) { require.load = function (context, moduleName, url) {
/*jslint evil: true */ /*jslint evil: true */
var url = require.nameToUrl(moduleName, null, contextName), map, var isPlugin = false,
contents, contents, pluginBuilderMatch, builderName;
context = require.s.contexts[contextName];
//Adjust the URL if it was not transformed to use baseUrl.
if (require.jsExtRegExp.test(moduleName)) {
url = context.config.dirBaseUrl + url;
}
context.loaded[moduleName] = false; context.loaded[moduleName] = false;
context.scriptCount += 1;
//Only handle urls that can be inlined, so that means avoiding some //Only handle urls that can be inlined, so that means avoiding some
//URLs like ones that require network access or may be too dynamic, //URLs like ones that require network access or may be too dynamic,
//like JSONP //like JSONP
if (require._isSupportedBuildUrl(url)) { if (require._isSupportedBuildUrl(url)) {
//Save the module name to path mapping. //Save the module name to path and path to module name mappings.
map = layer.buildPathMap[moduleName] = url; layer.buildPathMap[moduleName] = url;
layer.buildFileToModule[url] = moduleName;
//Load the file contents, process for conditionals, then //Load the file contents, process for conditionals, then
//evaluate it. //evaluate it.
contents = _readFile(url); contents = _readFile(url);
contents = pragma.process(url, contents, context.config); contents = pragma.process(url, contents, context.config);
//Find out if the file contains a require() definition. Need to know //Find out if the file contains a require() definition. Need to know
//this so we can inject plugins right after it, but before they are needed, //this so we can inject plugins right after it, but before they are needed,
//and to make sure this file is first, so that require.def calls work. //and to make sure this file is first, so that require.def calls work.
@ -124,29 +143,55 @@
if (!layer.existingRequireUrl && parse.definesRequire(url, contents)) { if (!layer.existingRequireUrl && parse.definesRequire(url, contents)) {
layer.existingRequireUrl = url; layer.existingRequireUrl = url;
} }
//Only eval complete contents if asked, or if it is a require extension. if (moduleName in context.plugins) {
//Otherwise, treat the module as not safe for execution and parse out //This is a loader plugin, check to see if it has a build extension,
//the require calls. //otherwise the plugin will act as the plugin builder too.
if (!context.config.execModules && moduleName !== "require/text" && moduleName !== "require/i18n") { pluginBuilderMatch = pluginBuilderRegExp.exec(contents);
//Only find the require parts with [] dependencies and if (pluginBuilderMatch) {
//evaluate those. This path is useful when the code //Load the plugin builder for the plugin contents.
//does not follow the strict require pattern of wrapping all builderName = context.normalize(pluginBuilderMatch[3], moduleName);
//code in a require callback. contents = _readFile(context.nameToUrl(builderName));
}
//plugins need to have their source evaled as-is.
isPlugin = true;
}
//Parse out the require and define calls.
//Do this even for plugins in case they have their own
//dependencies that may be separate to how the pluginBuilder works.
if (!isPlugin) {
contents = parse(url, contents); contents = parse(url, contents);
} }
if (contents) { if (contents) {
eval(contents); eval(contents);
//Support anonymous modules. //Support anonymous modules.
require.completeLoad(moduleName, context); context.completeLoad(moduleName);
} }
// remember the list of dependencies for this layer.O
layer.buildFilePaths.push(url);
} }
//Mark the module loaded. //Mark the module loaded.
context.loaded[moduleName] = true; context.loaded[moduleName] = true;
require.checkLoaded(contextName);
//Get a handle on the pluginBuilder
if (isPlugin) {
require.pluginBuilders[moduleName] = context.defined[moduleName];
}
};
//This method is called when a plugin specifies a loaded value. Use
//this to track dependencies that do not go through require.load.
require.onPluginLoad = function (context, pluginName, name, value) {
var registeredName = pluginName + '!' + name;
layer.buildFilePaths.push(registeredName);
layer.buildFileToModule[registeredName] = registeredName;
layer.modulesWithNames[registeredName] = true;
}; };
//Override a method provided by require/text.js for loading text files as //Override a method provided by require/text.js for loading text files as
@ -162,9 +207,12 @@
require.execCb = function (name, cb, args) { require.execCb = function (name, cb, args) {
var url = name && layer.buildPathMap[name]; var url = name && layer.buildPathMap[name];
if (url && !layer.loadedFiles[url]) { if (url && !layer.loadedFiles[url]) {
layer.buildFilePaths.push(url);
layer.loadedFiles[url] = true; layer.loadedFiles[url] = true;
layer.modulesWithNames[name] = true; layer.modulesWithNames[name] = true;
} }
if (cb.__requireJsBuild) {
return cb.apply(null, args);
}
return undefined;
}; };
}()); }());

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,10 +1,10 @@
/** /**
* @license RequireJS i18n Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. * @license RequireJS i18n Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
/*jslint regexp: false, nomen: false, plusplus: false */ /*jslint regexp: false, nomen: false, plusplus: false */
/*global require: false, navigator: false */ /*global require: false, navigator: false, define: false */
"use strict"; "use strict";
/** /**
@ -42,284 +42,101 @@
//nlsRegExp.exec("foo/bar/baz/nls/foo") gives: //nlsRegExp.exec("foo/bar/baz/nls/foo") gives:
//["foo/bar/baz/nls/foo", "foo/bar/baz/nls/", "/", "/", "foo", ""] //["foo/bar/baz/nls/foo", "foo/bar/baz/nls/", "/", "/", "foo", ""]
//so, if match[5] is blank, it means this is the top bundle definition. //so, if match[5] is blank, it means this is the top bundle definition.
var nlsRegExp = /(^.*(^|\/)nls(\/|$))([^\/]*)\/?([^\/]*)/, var nlsRegExp = /(^.*(^|\/)nls(\/|$))([^\/]*)\/?([^\/]*)/;
empty = {};
function getWaiting(name, context) { //Helper function to avoid repeating code. Lots of arguments in the
var nlswAry = context.nlsWaiting; //desire to stay functional and support RequireJS contexts without having
return nlswAry[name] || //to know about the RequireJS contexts.
//Push a new waiting object on the nlsWaiting array, but also put function addPart(locale, master, needed, toLoad, prefix, suffix) {
//a shortcut lookup by name to the object on the array. if (master[locale]) {
(nlswAry[name] = nlswAry[(nlswAry.push({ _name: name}) - 1)]); needed.push(locale);
} if (master[locale] === true || master[locale] === 1) {
toLoad.push(prefix + locale + '/' + suffix);
/**
* Makes sure all the locale pieces are loaded, and finds the best match
* for the requested locale.
*/
function resolveLocale(masterName, bundle, locale, context) {
//Break apart the locale to get the parts.
var i, parts, toLoad, nlsw, loc, val, bestLoc = "root";
parts = locale.split("-");
//Now see what bundles exist for each country/locale.
//Want to walk up the chain, so if locale is en-us-foo,
//look for en-us-foo, en-us, en, then root.
toLoad = [];
nlsw = getWaiting(masterName, context);
for (i = parts.length; i > -1; i--) {
loc = i ? parts.slice(0, i).join("-") : "root";
val = bundle[loc];
if (val) {
//Store which bundle to use for the default bundle definition.
if (locale === context.config.locale && !nlsw._match) {
nlsw._match = loc;
}
//Store the best match for the target locale
if (bestLoc === "root") {
bestLoc = loc;
}
//Track that the locale needs to be resolved with its parts.
//Mark what locale should be used when resolving.
nlsw[loc] = loc;
//If locale value is true, it means it is a resource that
//needs to be loaded. Track it to load if it has not already
//been asked for.
if (val === true) {
//split off the bundl name from master name and insert the
//locale before the bundle name. So, if masterName is
//some/path/nls/colors, then the locale fr-fr's bundle name should
//be some/path/nls/fr-fr/colors
val = masterName.split("/");
val.splice(-1, 0, loc);
val = val.join("/");
if (!context.specified[val] && !(val in context.loaded) && !context.defined[val]) {
context.defPlugin[val] = 'i18n';
toLoad.push(val);
}
}
} }
} }
//If locale was not an exact match, store the closest match for it.
if (bestLoc !== locale) {
if (context.defined[bestLoc]) {
//Already got it. Easy peasy lemon squeezy.
context.defined[locale] = context.defined[bestLoc];
} else {
//Need to wait for things to load then define it.
nlsw[locale] = bestLoc;
}
}
//Load any bundles that are still needed.
if (toLoad.length) {
require(toLoad, context.contextName);
}
} }
require.plugin({ function addIfExists(req, locale, toLoad, prefix, suffix) {
prefix: "i18n", var fullName = prefix + locale + '/' + suffix;
if (require._fileExists(req.nameToUrl(fullName, null))) {
/** toLoad.push(fullName);
* This callback is prefix-specific, only gets called for this prefix }
*/ }
require: function (name, deps, callback, context) {
var i, match, nlsw, bundle, master, toLoad, obj = context.defined[name];
//All i18n modules must match the nls module name structure.
match = nlsRegExp.exec(name);
//If match[5] is blank, it means this is the top bundle definition,
//so it does not have to be handled. Only deal with ones that have a locale
//(a match[4] value but no match[5])
if (match[5]) {
master = match[1] + match[5];
//Track what locale bundle need to be generated once all the modules load.
nlsw = getWaiting(master, context);
nlsw[match[4]] = match[4];
bundle = context.nls[master];
if (!bundle) {
//No master bundle yet, ask for it.
context.defPlugin[master] = 'i18n';
require([master], context.contextName);
bundle = context.nls[master] = {};
}
//For nls modules, the callback is just a regular object,
//so save it off in the bundle now.
bundle[match[4]] = callback;
} else {
//Integrate bundle into the nls area.
bundle = context.nls[name];
if (bundle) {
//A specific locale already started the bundle object.
//Do a mixin (which will not overwrite the locale property
//on the bundle that has the previously loaded locale's info)
require.mixin(bundle, obj);
} else {
bundle = context.nls[name] = obj;
}
context.nlsRootLoaded[name] = true;
//Make sure there are no locales waiting to be resolved.
toLoad = context.nlsToLoad[name];
if (toLoad) {
delete context.nlsToLoad[name];
for (i = 0; i < toLoad.length; i++) {
resolveLocale(name, bundle, toLoad[i], context);
}
}
resolveLocale(name, bundle, context.config.locale, context);
}
},
/**
* Called when a new context is defined. Use this to store
* context-specific info on it.
*/
newContext: function (context) {
require.mixin(context, {
nlsWaiting: [],
nls: {},
nlsRootLoaded: {},
nlsToLoad: {}
});
if (!context.config.locale) {
context.config.locale = typeof navigator === "undefined" ? "root" :
(navigator.language || navigator.userLanguage || "root").toLowerCase();
}
},
define({
/** /**
* Called when a dependency needs to be loaded. * Called when a dependency needs to be loaded.
*/ */
load: function (name, contextName) { load: function (name, req, onLoad, config) {
//Make sure the root bundle is loaded, to check if we can support config = config || {};
//loading the requested locale, or if a different one needs
//to be chosen. var masterName,
var masterName, context = require.s.contexts[contextName], bundle, match = nlsRegExp.exec(name),
match = nlsRegExp.exec(name), locale = match[4]; prefix = match[1],
locale = match[4],
suffix = match[5],
parts = locale.split("-"),
toLoad = [],
value = {},
i, part, current = "";
//If match[5] is blank, it means this is the top bundle definition, //If match[5] is blank, it means this is the top bundle definition,
//so it does not have to be handled. Only deal with ones that have a locale //so it does not have to be handled. Locale-specific requests
//(a match[4] value but no match[5]) //will have a match[4] value but no match[5]
if (match[5]) { if (match[5]) {
//locale-specific bundle //locale-specific bundle
masterName = match[1] + match[5]; prefix = match[1];
bundle = context.nls[masterName]; masterName = prefix + suffix;
if (context.nlsRootLoaded[masterName] && bundle) {
resolveLocale(masterName, bundle, locale, context);
} else {
//Store this locale to figure out after masterName is loaded and load masterName.
(context.nlsToLoad[masterName] || (context.nlsToLoad[masterName] = [])).push(locale);
context.defPlugin[masterName] = 'i18n';
require([masterName], contextName);
}
} else { } else {
//Top-level bundle. Just call regular load, if not already loaded //Top-level bundle.
if (!context.nlsRootLoaded[name]) { masterName = name;
context.defPlugin[name] = 'i18n'; suffix = match[4];
require.load(name, contextName); locale = config.locale || (config.locale =
} typeof navigator === "undefined" ? "root" :
(navigator.language ||
navigator.userLanguage || "root").toLowerCase());
parts = locale.split("-");
} }
},
/** if (config.isBuild) {
* Called when the dependencies of a module are checked. //Check for existence of all locale possible files and
*/ //require them if exist.
checkDeps: function (name, deps, context) { toLoad.push(masterName);
//i18n bundles are always defined as objects for their "dependencies", addIfExists(req, "root", toLoad, prefix, suffix);
//and that object is already processed in the require method, no need to for (i = 0; (part = parts[i]); i++) {
//do work in here. current += (current ? "-" : "") + part;
}, addIfExists(req, current, toLoad, prefix, suffix);
/**
* Called to determine if a module is waiting to load.
*/
isWaiting: function (context) {
return !!context.nlsWaiting.length;
},
/**
* Called when all modules have been loaded.
*/
orderDeps: function (context) {
//Clear up state since further processing could
//add more things to fetch.
var i, j, master, msWaiting, bundle, parts, moduleSuffix, mixed,
modulePrefix, loc, defLoc, locPart, nlsWaiting = context.nlsWaiting,
bestFit;
context.nlsWaiting = [];
context.nlsToLoad = {};
//First, properly mix in any nls bundles waiting to happen.
for (i = 0; (msWaiting = nlsWaiting[i]); i++) {
//Each property is a master bundle name.
master = msWaiting._name;
bundle = context.nls[master];
defLoc = null;
//Create the module name parts from the master name. So, if master
//is foo/nls/bar, then the parts should be prefix: "foo/nls",
// suffix: "bar", and the final locale's module name will be foo/nls/locale/bar
parts = master.split("/");
modulePrefix = parts.slice(0, parts.length - 1).join("/");
moduleSuffix = parts[parts.length - 1];
//Cycle through the locale props on the waiting object and combine
//the locales together.
for (loc in msWaiting) {
if (loc !== "_name" && !(loc in empty)) {
if (loc === "_match") {
//Found default locale to use for the top-level bundle name.
defLoc = msWaiting[loc];
} else if (msWaiting[loc] !== loc) {
//A "best fit" locale, store it off to the end and handle
//it at the end by just assigning the best fit value, since
//after this for loop, the best fit locale will be defined.
(bestFit || (bestFit = {}))[loc] = msWaiting[loc];
} else {
//Mix in the properties of this locale together.
//Split the locale into pieces.
mixed = {};
parts = loc.split("-");
for (j = parts.length; j > 0; j--) {
locPart = parts.slice(0, j).join("-");
if (locPart !== "root" && bundle[locPart]) {
require.mixin(mixed, bundle[locPart]);
}
}
if (bundle.root) {
require.mixin(mixed, bundle.root);
}
context.defined[modulePrefix + "/" + loc + "/" + moduleSuffix] = mixed;
}
}
} }
req(toLoad);
onLoad();
} else {
//First, fetch the master bundle, it knows what locales are available.
req([masterName], function (master) {
//Figure out the best fit
var needed = [];
//Finally define the default locale. Wait to the end of the property //Always allow for root, then do the rest of the locale parts.
//loop above so that the default locale bundle has been properly mixed addPart("root", master, needed, toLoad, prefix, suffix);
//together. for (i = 0; (part = parts[i]); i++) {
context.defined[master] = context.defined[modulePrefix + "/" + defLoc + "/" + moduleSuffix]; current += (current ? "-" : "") + part;
addPart(current, master, needed, toLoad, prefix, suffix);
//Handle any best fit locale definitions.
if (bestFit) {
for (loc in bestFit) {
if (!(loc in empty)) {
context.defined[modulePrefix + "/" + loc + "/" + moduleSuffix] = context.defined[modulePrefix + "/" + bestFit[loc] + "/" + moduleSuffix];
}
} }
}
//Load all the parts missing.
req(toLoad, function () {
var i, partBundle;
for (i = needed.length - 1; i > -1 && (part = needed[i]); i--) {
partBundle = master[part];
if (partBundle === true || partBundle === 1) {
partBundle = req(prefix + part + '/' + suffix);
}
require.mixin(value, partBundle);
}
//All done, notify the loader.
onLoad(value);
});
});
} }
} }
}); });

Просмотреть файл

@ -1,123 +0,0 @@
/**
* @license RequireJS jsonp Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license.
* see: http://github.com/jrburke/requirejs for details
*/
/*jslint nomen: false, plusplus: false */
/*global require: false, setTimeout: false */
"use strict";
(function () {
var countId = 0;
//A place to hold callback functions
require._jsonp = {};
require.plugin({
prefix: "jsonp",
/**
* This callback is prefix-specific, only gets called for this prefix
*/
require: function (name, deps, callback, context) {
//No-op, require never gets these jsonp items, they are always
//a dependency, see load for the action.
},
/**
* Called when a new context is defined. Use this to store
* context-specific info on it.
*/
newContext: function (context) {
require.mixin(context, {
jsonpWaiting: []
});
},
/**
* Called when a dependency needs to be loaded.
*/
load: function (name, contextName) {
//Name has format: some/url?param1=value1&callback=?
//where the last question mark indicates where the jsonp callback
//function name needs to go.
var index = name.indexOf("?"),
url = name.substring(0, index),
params = name.substring(index + 1, name.length),
context = require.s.contexts[contextName],
data = {
name: name
},
funcName = "f" + (countId++),
head = require.s.head,
node = head.ownerDocument.createElement("script");
//Create JSONP callback function
require._jsonp[funcName] = function (value) {
data.value = value;
context.loaded[name] = true;
require.checkLoaded(contextName);
//Use a setTimeout for cleanup because some older IE versions vomit
//if removing a script node while it is being evaluated.
setTimeout(function () {
head.removeChild(node);
delete require._jsonp[funcName];
}, 15);
};
//Hold on to the data for later dependency resolution in orderDeps.
context.jsonpWaiting.push(data);
//Build up the full JSONP URL
url = require.nameToUrl(url, "?", contextName);
//nameToUrl call may or may not have placed an ending ? on the URL,
//be sure there is one and add the rest of the params.
url += (url.indexOf("?") === -1 ? "?" : "") + params.replace("?", "require._jsonp." + funcName);
context.loaded[name] = false;
node.type = "text/javascript";
node.charset = "utf-8";
node.src = url;
//Use async so Gecko does not block on executing the script if something
//like a long-polling comet tag is being run first. Gecko likes
//to evaluate scripts in DOM order, even for dynamic scripts.
//It will fetch them async, but only evaluate the contents in DOM
//order, so a long-polling script tag can delay execution of scripts
//after it. But telling Gecko we expect async gets us the behavior
//we want -- execute it whenever it is finished downloading. Only
//Helps Firefox 3.6+
node.async = true;
head.appendChild(node);
},
/**
* Called when the dependencies of a module are checked.
*/
checkDeps: function (name, deps, context) {
//No-op, checkDeps never gets these jsonp items, they are always
//a dependency, see load for the action.
},
/**
* Called to determine if a module is waiting to load.
*/
isWaiting: function (context) {
return !!context.jsonpWaiting.length;
},
/**
* Called when all modules have been loaded.
*/
orderDeps: function (context) {
//Clear up state since further processing could
//add more things to fetch.
var i, dep, waitAry = context.jsonpWaiting;
context.jsonpWaiting = [];
for (i = 0; (dep = waitAry[i]); i++) {
context.defined[dep.name] = dep.value;
}
}
});
}());

Просмотреть файл

@ -1,10 +1,11 @@
/** /**
* @license RequireJS order Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. * @license RequireJS order Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
/*jslint nomen: false, plusplus: false */ /*jslint nomen: false, plusplus: false */
/*global require: false, window: false, document: false, setTimeout: false */ /*global require: false, define: false, window: false, document: false,
setTimeout: false */
"use strict"; "use strict";
(function () { (function () {
@ -14,39 +15,65 @@
//Currently, Gecko and Opera do not load/fire onload for scripts with //Currently, Gecko and Opera do not load/fire onload for scripts with
//type="script/cache" but they execute injected scripts in order //type="script/cache" but they execute injected scripts in order
//unless the 'async' flag is present. //unless the 'async' flag is present.
var supportsInOrderExecution = ((window.opera && Object.prototype.toString.call(window.opera) === "[object Opera]") || //However, this is all changing in latest browsers implementing HTML5
//spec. Firefox nightly supports using the .async true by default, and
//if false, then it will execute in order. Favor that test first for forward
//compatibility. However, it is unclear if webkit/IE will follow suit.
//Latest webkit breaks the script/cache trick.
//Test for document and window so that this file can be loaded in
//a web worker/non-browser env. It will not make sense to use this
//plugin in a non-browser env, but the file should not error out if included
//in the allplugins-require.js file, then loaded in a non-browser env.
var supportsInOrderExecution = typeof document !== "undefined" &&
typeof window !== "undefined" &&
(document.createElement("script").async ||
(window.opera && Object.prototype.toString.call(window.opera) === "[object Opera]") ||
//If Firefox 2 does not have to be supported, then //If Firefox 2 does not have to be supported, then
//a better check may be: //a better check may be:
//('mozIsLocallyAvailable' in window.navigator) //('mozIsLocallyAvailable' in window.navigator)
("MozAppearance" in document.documentElement.style)), ("MozAppearance" in document.documentElement.style)),
readyRegExp = /^(complete|loaded)$/; readyRegExp = /^(complete|loaded)$/,
waiting = [],
cached = {};
function loadResource(name, req, onLoad) {
req([name], function (value) {
//The value may be a real defined module. Wrap
//it in a function call, because this function is used
//as the factory function for this ordered dependency.
onLoad(function () {
return value;
});
});
}
//Callback used by the type="script/cache" callback that indicates a script //Callback used by the type="script/cache" callback that indicates a script
//has finished downloading. //has finished downloading.
function scriptCacheCallback(evt) { function scriptCacheCallback(evt) {
var node = evt.currentTarget || evt.srcElement, i, var node = evt.currentTarget || evt.srcElement, i,
context, contextName, moduleName, waiting, cached; moduleName, resource;
if (evt.type === "load" || readyRegExp.test(node.readyState)) { if (evt.type === "load" || readyRegExp.test(node.readyState)) {
//Pull out the name of the module and the context. //Pull out the name of the module and the context.
contextName = node.getAttribute("data-requirecontext");
moduleName = node.getAttribute("data-requiremodule"); moduleName = node.getAttribute("data-requiremodule");
context = require.s.contexts[contextName];
waiting = context.orderWaiting;
cached = context.orderCached;
//Mark this cache request as loaded //Mark this cache request as loaded
cached[moduleName] = true; cached[moduleName] = true;
//Find out how many ordered modules have loaded //Find out how many ordered modules have loaded
for (i = 0; cached[waiting[i]]; i++) {} for (i = 0; (resource = waiting[i]); i++) {
if (i > 0) { if (cached[resource.name]) {
require(waiting.splice(0, i), contextName); loadResource(resource.name, resource.req, resource.onLoad);
} else {
//Something in the ordered list is not loaded,
//so wait.
break;
}
} }
//If no other order cache items are in the queue, do some cleanup. //If just loaded some items, remove them from waiting.
if (!waiting.length) { if (i > 0) {
context.orderCached = {}; waiting.splice(0, i);
} }
//Remove this script tag from the DOM //Remove this script tag from the DOM
@ -58,34 +85,15 @@
} }
} }
require.plugin({ define({
prefix: "order", load: function (name, req, onLoad, config) {
var url = req.nameToUrl(name, null);
/** //If a build, just load the module as usual.
* This callback is prefix-specific, only gets called for this prefix if (config.isBuild) {
*/ loadResource(name, req, onLoad);
require: function (name, deps, callback, context) { return;
//No-op, require never gets these order items, they are always }
//a dependency, see load for the action.
},
/**
* Called when a new context is defined. Use this to store
* context-specific info on it.
*/
newContext: function (context) {
require.mixin(context, {
orderWaiting: [],
orderCached: {}
});
},
/**
* Called when a dependency needs to be loaded.
*/
load: function (name, contextName) {
var context = require.s.contexts[contextName],
url = require.nameToUrl(name, null, contextName);
//Make sure the async attribute is not set for any pathway involving //Make sure the async attribute is not set for any pathway involving
//this script. //this script.
@ -93,7 +101,14 @@
if (supportsInOrderExecution) { if (supportsInOrderExecution) {
//Just a normal script tag append, but without async attribute //Just a normal script tag append, but without async attribute
//on the script. //on the script.
require([name], contextName); req([name], function (value) {
//The value may be a real defined module. Wrap
//it in a function call, because this function is used
//as the factory function for this ordered dependency.
onLoad(function () {
return value;
});
});
} else { } else {
//Credit to LABjs author Kyle Simpson for finding that scripts //Credit to LABjs author Kyle Simpson for finding that scripts
//with type="script/cache" allow scripts to be downloaded into //with type="script/cache" allow scripts to be downloaded into
@ -101,32 +116,24 @@
//so that subsequent addition of a real type="text/javascript" //so that subsequent addition of a real type="text/javascript"
//tag will cause the scripts to be executed immediately in the //tag will cause the scripts to be executed immediately in the
//correct order. //correct order.
context.orderWaiting.push(name); if (req.isDefined(name)) {
context.loaded[name] = false; req([name], function (value) {
require.attach(url, contextName, name, scriptCacheCallback, "script/cache"); //The value may be a real defined module. Wrap
//it in a function call, because this function is used
//as the factory function for this ordered dependency.
onLoad(function () {
return value;
});
});
} else {
waiting.push({
name: name,
req: req,
onLoad: onLoad
});
require.attach(url, "", name, scriptCacheCallback, "script/cache");
}
} }
},
/**
* Called when the dependencies of a module are checked.
*/
checkDeps: function (name, deps, context) {
//No-op, checkDeps never gets these order items, they are always
//a dependency, see load for the action.
},
/**
* Called to determine if a module is waiting to load.
*/
isWaiting: function (context) {
return !!context.orderWaiting.length;
},
/**
* Called when all modules have been loaded. Not needed for this plugin.
* State is reset as part of scriptCacheCallback.
*/
orderDeps: function (context) {
} }
}); });
}()); }());

Просмотреть файл

@ -1,6 +1,6 @@
/** /**
* @license RequireJS rhino Copyright (c) 2010, The Dojo Foundation All Rights Reserved. * @license RequireJS rhino Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
/*global require: false, readFile: false */ /*global require: false, readFile: false */
@ -10,21 +10,69 @@ TODO: Work out relative paths, that use ./ and such, and allow loading normal
CommonJS modules, by overriding require.get(). CommonJS modules, by overriding require.get().
*/ */
/*globals load: false */ /*globals load: false, java: false */
"use strict"; "use strict";
require.load = function (moduleName, contextName) { (function () {
var url = require.nameToUrl(moduleName, null, contextName),
context = require.s.contexts[contextName];
//isDone is used by require.ready() var fileUtil = {
require.s.isDone = false; backSlashRegExp: /\\/g,
//Indicate a the module is in process of loading. getLineSeparator: function () {
context.loaded[moduleName] = false; return java.lang.System.getProperty("line.separator"); //Java String
}
};
load(url); require.load = function (context, moduleName, url) {
//isDone is used by require.ready()
require.s.isDone = false;
//Support anonymous modules. //Indicate a the module is in process of loading.
require.completeLoad(moduleName, context); context.loaded[moduleName] = false;
}; context.scriptCount += 1;
load(url);
//Support anonymous modules.
context.completeLoad(moduleName);
};
//Adapter to get text plugin to work.
require.fetchText = function (url, callback) {
var encoding = "utf-8",
file = new java.io.File(url),
lineSeparator = fileUtil.getLineSeparator(),
input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
stringBuffer, line,
content = '';
try {
stringBuffer = new java.lang.StringBuffer();
line = input.readLine();
// Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
// http://www.unicode.org/faq/utf_bom.html
// Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
if (line && line.length() && line.charAt(0) === 0xfeff) {
// Eat the BOM, since we've already found the encoding on this file,
// and we plan to concatenating this buffer with others; the BOM should
// only appear at the top of a file.
line = line.substring(1);
}
stringBuffer.append(line);
while ((line = input.readLine()) !== null) {
stringBuffer.append(lineSeparator);
stringBuffer.append(line);
}
//Make sure we return a JavaScript string and not a Java string.
content = String(stringBuffer.toString()); //String
} finally {
input.close();
}
callback(content);
};
}());

Просмотреть файл

@ -1,16 +1,18 @@
/** /**
* @license RequireJS text Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. * @license RequireJS text Copyright (c) 2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
/*jslint regexp: false, nomen: false, plusplus: false */ /*jslint regexp: false, nomen: false, plusplus: false */
/*global require: false, XMLHttpRequest: false, ActiveXObject: false */ /*global require: false, XMLHttpRequest: false, ActiveXObject: false,
define: false */
"use strict"; "use strict";
(function () { (function () {
var progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], var progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],
xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,
bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im; bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im,
buildMap = [];
if (!require.textStrip) { if (!require.textStrip) {
require.textStrip = function (text) { require.textStrip = function (text) {
@ -30,6 +32,17 @@
}; };
} }
if (!require.jsEscape) {
require.jsEscape = function (text) {
return text.replace(/(['\\])/g, '\\$1')
.replace(/[\f]/g, "\\f")
.replace(/[\b]/g, "\\b")
.replace(/[\n]/g, "\\n")
.replace(/[\t]/g, "\\t")
.replace(/[\r]/g, "\\r");
};
}
//Upgrade require to add some methods for XHR handling. But it could be that //Upgrade require to add some methods for XHR handling. But it could be that
//this require is used in a non-browser env, so detect for existing method //this require is used in a non-browser env, so detect for existing method
//before attaching one. //before attaching one.
@ -50,7 +63,7 @@
progIds = [progId]; // so faster next time progIds = [progId]; // so faster next time
break; break;
} }
} }
} }
if (!xhr) { if (!xhr) {
@ -60,7 +73,7 @@
return xhr; return xhr;
}; };
} }
if (!require.fetchText) { if (!require.fetchText) {
require.fetchText = function (url, callback) { require.fetchText = function (url, callback) {
var xhr = require.getXhr(); var xhr = require.getXhr();
@ -76,120 +89,43 @@
}; };
} }
require.plugin({ define({
prefix: "text", load: function (name, req, onLoad, config) {
//Name has format: some.module.filext!strip
/** //The strip part is optional.
* This callback is prefix-specific, only gets called for this prefix
*/
require: function (name, deps, callback, context) {
//No-op, require never gets these text items, they are always
//a dependency, see load for the action.
},
/**
* Called when a new context is defined. Use this to store
* context-specific info on it.
*/
newContext: function (context) {
require.mixin(context, {
text: {},
textWaiting: []
});
},
/**
* Called when a dependency needs to be loaded.
*/
load: function (name, contextName) {
//Name has format: some.module!filext!strip!text
//The strip and text parts are optional.
//if strip is present, then that means only get the string contents //if strip is present, then that means only get the string contents
//inside a body tag in an HTML string. For XML/SVG content it means //inside a body tag in an HTML string. For XML/SVG content it means
//removing the <?xml ...?> declarations so the content can be inserted //removing the <?xml ...?> declarations so the content can be inserted
//into the current doc without problems. //into the current doc without problems.
//If text is present, it is the actual text of the file.
var strip = false, text = null, key, url, index = name.indexOf("."), var strip = false, url, index = name.indexOf("."),
modName = name.substring(0, index), fullKey, modName = name.substring(0, index),
ext = name.substring(index + 1, name.length), ext = name.substring(index + 1, name.length);
context = require.s.contexts[contextName],
tWaitAry = context.textWaiting;
index = ext.indexOf("!"); index = ext.indexOf("!");
if (index !== -1) { if (index !== -1) {
//Pull off the strip arg. //Pull off the strip arg.
strip = ext.substring(index + 1, ext.length); strip = ext.substring(index + 1, ext.length);
strip = strip === "strip";
ext = ext.substring(0, index); ext = ext.substring(0, index);
index = strip.indexOf("!"); }
if (index !== -1 && strip.substring(0, index) === "strip") {
//Pull off the text. //Load the text.
text = strip.substring(index + 1, strip.length); url = req.nameToUrl(modName, "." + ext);
strip = "strip"; require.fetchText(url, function (text) {
} else if (strip !== "strip") { text = strip ? require.textStrip(text) : text;
//strip is actually the inlined text. if (config.isBuild && config.inlineText) {
text = strip; buildMap[name] = text;
strip = null;
} }
} onLoad(text);
key = modName + "!" + ext; });
fullKey = strip ? key + "!" + strip : key;
//Store off text if it is available for the given key and be done.
if (text !== null && !context.text[key]) {
context.defined[name] = context.text[key] = text;
return;
}
//If text is not available, load it.
if (!context.text[key] && !context.textWaiting[key] && !context.textWaiting[fullKey]) {
//Keep track that the fullKey needs to be resolved, during the
//orderDeps stage.
if (!tWaitAry[fullKey]) {
tWaitAry[fullKey] = tWaitAry[(tWaitAry.push({
name: name,
key: key,
fullKey: fullKey,
strip: !!strip
}) - 1)];
}
//Load the text.
url = require.nameToUrl(modName, "." + ext, contextName);
context.loaded[name] = false;
require.fetchText(url, function (text) {
context.text[key] = text;
context.loaded[name] = true;
require.checkLoaded(contextName);
});
}
}, },
/** write: function (pluginName, moduleName, write) {
* Called when the dependencies of a module are checked. if (moduleName in buildMap) {
*/ var text = require.jsEscape(buildMap[moduleName]);
checkDeps: function (name, deps, context) { write("define('" + pluginName + "!" + moduleName +
//No-op, checkDeps never gets these text items, they are always "', function () { return '" + text + "';});\n");
//a dependency, see load for the action.
},
/**
* Called to determine if a module is waiting to load.
*/
isWaiting: function (context) {
return !!context.textWaiting.length;
},
/**
* Called when all modules have been loaded.
*/
orderDeps: function (context) {
//Clear up state since further processing could
//add more things to fetch.
var i, dep, text, tWaitAry = context.textWaiting;
context.textWaiting = [];
for (i = 0; (dep = tWaitAry[i]); i++) {
text = context.text[dep.key];
context.defined[dep.name] = dep.strip ? require.textStrip(text) : text;
} }
} }
}); });

Просмотреть файл

@ -1,30 +0,0 @@
/**
* @license RequireJS transportD Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
* Available via the MIT, GPL or new BSD license.
* see: http://github.com/jrburke/requirejs for details
*/
/*jslint */
/*global require: false */
"use strict";
/**
* An adapter for the CommonJS Transport/D proposal:
* http://wiki.commonjs.org/wiki/Modules/Transport/D
* NOTE: this integration does NOT support contexts, so only one version in the page.
* @param {Object} modules a dictionary of module names with module descriptors
* @param [Array] dependencies a list of module names that are dependencies for
* all the modules listed in the modules argument.
*/
require.define = function (modules, dependencies) {
var moduleName, descriptor;
for (moduleName in modules) {
if (modules.hasOwnProperty(moduleName)) {
descriptor = modules[moduleName];
require.def(
moduleName,
(descriptor.injects || ["require", "exports", "module"]).concat(dependencies || []),
typeof descriptor === "function" ? descriptor : descriptor.factory
);
}
}
};

Просмотреть файл

@ -1,10 +0,0 @@
{
baseUrl: "../../web-static/scripts/",
paths: {
"index": "../settings/index",
"jquery": "requireplugins-jquery-1.4.2"
},
name: "index",
exclude: ['jquery'],
out: '../../web-static/settings/index.js'
}

Просмотреть файл

@ -1,10 +0,0 @@
{
baseUrl: "../../web-static/scripts/",
paths: {
"index": "../share/index",
"jquery": "requireplugins-jquery-1.4.2"
},
name: "index",
exclude: ['jquery'],
out: '../../web-static/share/index.js'
}

304
web/0.1.7/auth.html Normal file
Просмотреть файл

@ -0,0 +1,304 @@
<!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.1.7/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.1.7/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.1.7/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"],
function (require, $, url) {
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
try {
window.opener.postMessage(target, '*');
window.close();
} catch(e) {
var url = location.protocol + "//" + location.host + "/settings/?target="+target;
window.location = url;
}
}
var search = window.location.href.split('?')[1];
if (search) {
search = search.split('#')[0];
var args = url.queryToObject(search);
if (args['domain']) {
$("#domain").attr("value", args['domain']);
if (args['domain'] == 'googleapps.com') {
$('#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="/auth.html#oauth_success">
<input class="boxFlex google" type="hidden" name="end_point_auth_failure" value="/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>

Просмотреть файл

10
web/0.1.7/build.js Normal file
Просмотреть файл

@ -0,0 +1,10 @@
({
baseUrl: "scripts/",
paths: {
"index": "../index",
"jquery": "requireplugins-jquery"
},
name: "index",
exclude: ['jquery'],
out: './index.js'
})

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 1.1 KiB

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 469 B

После

Ширина:  |  Высота:  |  Размер: 469 B

Двоичные данные
web/0.1.7/i/LinkedIn_Logo16px.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 716 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 670 B

После

Ширина:  |  Высота:  |  Размер: 670 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 494 B

После

Ширина:  |  Высота:  |  Размер: 494 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 142 B

После

Ширина:  |  Высота:  |  Размер: 142 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 139 B

После

Ширина:  |  Высота:  |  Размер: 139 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 136 B

После

Ширина:  |  Высота:  |  Размер: 136 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 139 B

После

Ширина:  |  Высота:  |  Размер: 139 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 389 B

После

Ширина:  |  Высота:  |  Размер: 389 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 4.7 KiB

После

Ширина:  |  Высота:  |  Размер: 4.7 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 4.4 KiB

После

Ширина:  |  Высота:  |  Размер: 4.4 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 448 B

После

Ширина:  |  Высота:  |  Размер: 448 B

Двоичные данные
web/0.1.7/i/fancybox/blank.gif Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 43 B

Двоичные данные
web/0.1.7/i/fancybox/fancy_close.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Двоичные данные
web/0.1.7/i/fancybox/fancy_loading.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 10 KiB

Двоичные данные
web/0.1.7/i/fancybox/fancy_nav_left.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичные данные
web/0.1.7/i/fancybox/fancy_nav_right.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичные данные
web/0.1.7/i/fancybox/fancy_shadow_e.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 107 B

Двоичные данные
web/0.1.7/i/fancybox/fancy_shadow_n.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 106 B

Двоичные данные
web/0.1.7/i/fancybox/fancy_shadow_ne.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 347 B

Двоичные данные
web/0.1.7/i/fancybox/fancy_shadow_nw.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 324 B

Двоичные данные
web/0.1.7/i/fancybox/fancy_shadow_s.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 111 B

Двоичные данные
web/0.1.7/i/fancybox/fancy_shadow_se.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 352 B

Двоичные данные
web/0.1.7/i/fancybox/fancy_shadow_sw.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 340 B

Двоичные данные
web/0.1.7/i/fancybox/fancy_shadow_w.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 103 B

Двоичные данные
web/0.1.7/i/fancybox/fancy_title_left.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 503 B

Двоичные данные
web/0.1.7/i/fancybox/fancy_title_main.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 96 B

Двоичные данные
web/0.1.7/i/fancybox/fancy_title_over.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 70 B

Двоичные данные
web/0.1.7/i/fancybox/fancy_title_right.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 506 B

Двоичные данные
web/0.1.7/i/fancybox/fancybox-x.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 203 B

Двоичные данные
web/0.1.7/i/fancybox/fancybox-y.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 176 B

Двоичные данные
web/0.1.7/i/fancybox/fancybox.png Executable file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 15 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 468 B

После

Ширина:  |  Высота:  |  Размер: 468 B

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 2.7 KiB

После

Ширина:  |  Высота:  |  Размер: 2.7 KiB

Двоичные данные
web/0.1.7/i/panel/f1accounts.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 67 KiB

Двоичные данные
web/0.1.7/i/panel/f1panel.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 66 KiB

Двоичные данные
web/0.1.7/i/panel/step-01.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 12 KiB

Двоичные данные
web/0.1.7/i/panel/step-02.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 27 KiB

Двоичные данные
web/0.1.7/i/panel/step-022.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 23 KiB

Двоичные данные
web/0.1.7/i/panel/step-03.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.2 KiB

Просмотреть файл

До

Ширина:  |  Высота:  |  Размер: 27 KiB

После

Ширина:  |  Высота:  |  Размер: 27 KiB

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше