Skip to content

Commit

Permalink
Babel & Webpack added, components out
Browse files Browse the repository at this point in the history
  • Loading branch information
YoruNoHikage committed Dec 23, 2016
1 parent 1fbb1cf commit 388082a
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 161 deletions.
13 changes: 13 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"presets": [
["env", {
"debug": true,
"targets": {
"firefox": 45
},
"modules": false,
"useBuiltIns": true
}],
"react"
]
}
1 change: 1 addition & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ cp -r --parents chrome/ components/ defaults/ modules/ platform/ chrome.manifest
LIB_DIR=chrome/Echofon/content/lib/
cp node_modules/react/dist/react.js "$LIB_DIR"
cp node_modules/react-dom/dist/react-dom.js "$LIB_DIR"
npm run build

cd build/src/chrome/Echofon
zip -r -9 ../Echofon.jar *
Expand Down
189 changes: 28 additions & 161 deletions chrome/Echofon/content/utility.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,171 +3,19 @@
//
// Copyright (c) 2009-2010 Kazuho Okui / naan studio, Inc. ALL RIGHTS RESERVED.
//
import { createElement as e } from 'react';
import ReactDOM from 'react-dom';

if (typeof EchofonCommon == 'undefined') {
import AnchorText from '../../../src/components/AnchorText/index.jsx';
import RichText from '../../../src/components/RichText/index.jsx';
import StatusTagLine from '../../../src/components/StatusTagLine/index.jsx';

Components.utils.import("resource://echofon/PhotoBackend.jsm");

const e = React.createElement;

function getString(key) {
return document.getElementById("echofon-strings").getString(key).replace(/\\S/g, " ");
}

function formatText({ children, type }) {
const text = getString(type);

// for single value
let arr = text.split(/(%S)/);
if (arr.length > 1) {
arr[1] = children;
return arr;
}

// for multiple values
return text.split(/%(\d)\$S/).map((chunk, i) => ((i % 2) && children[parseInt(chunk)-1]) || chunk);
}

const AnchorText = ({ children, link, text, type, className = 'echofon-hyperlink', additionalClasses, style, screen_name, created_at, label }) => {
const attrs = {
style,
className: additionalClasses ? className + ' ' + additionalClasses : className,
href: link,
type,
ref: (node) => {
if (node) {
node.setAttribute('text', text);
node.setAttribute('tooltip', 'echofon-tooltip');
if (screen_name) node.setAttribute('screen_name', screen_name);
if (created_at) node.setAttribute('created_at', created_at);
if (label) node.setAttribute('label', label);
}
},
};

return e('label', attrs, children);
};

class RichText extends React.Component {
componentDidMount() {
const { uid, msg, parent_elem } = this.props;

if (msg.entities) {
return EchofonCommon.convertLinksWithEntities(uid, msg, this.refs.node, parent_elem);
}
else {
return EchofonCommon.convertLinksWithRegExp(uid, msg, this.refs.node, parent_elem);
}
}

render() {
const { user } = this.props;
const children = [];

var style = EchofonCommon.pref().getIntPref("displayStyle");
if (style !== 0) {
const displayName = (style == 1) ? user.name : user.screen_name;
const anchor = e(AnchorText, {
link: EchofonCommon.userViewURL(user.screen_name),
text: displayName,
type: 'username',
screen_name: user.screen_name,
additionalClasses: 'echofon-status-user',
}, displayName);

children.push(anchor, ' ');
}

return e('description', { className: 'echofon-status-body', ref: 'node' }, ...children);
}
}

const StatusTagLine = ({ msg, fontSize, appMode, user }) => {
let infoChildren = [];

var permalink = (msg.retweeted_status_id) ? msg.retweeted_status_id : msg.id;

if (msg.metadata && msg.metadata.result_type === "popular") {
infoChildren.push(e('description', { className: 'echofon-top-tweet' }, 'Top Tweet'));
}

const label = EchofonCommon.getLocalTimeForDate(msg.created_at, appMode !== 'window' && msg.type !== 'user-timeline');
const time = e(AnchorText, {
link: EchofonCommon.twitterURL(user.screen_name + "/statuses/" + permalink),
text: label,
type: 'link',
className: 'echofon-status-timestamp',
created_at: new Date(msg.created_at).getTime(),
label,
}, label);
infoChildren.push(time);

if (msg.source) {
if (msg.source.match(/<a href\=\"([^\"]*)\"[^>]*>(.*)<\/a>/)) {
const source = e(AnchorText, {
link: RegExp.$1,
text: RegExp.$2,
type: 'app',
className: 'echofon-source-link',
}, RegExp.$2);
const sources = formatText({type: 'via', children: source});

infoChildren.push(e('box', {}, ' '), ...sources); // whitespace box hack, if better, plz tell us
}
}
if (msg.place) {
if (appMode === 'window') {
const text = EchofonCommon.getFormattedString('from', [msg.place.full_name]);
infoChildren.push(text);
} else {
infoChildren.push(e('box', {}, e('image', { className: 'echofon-place-icon' }), msg.place.full_name));
}
}
if (msg.in_reply_to_status_id && msg.in_reply_to_screen_name) {
const link = EchofonCommon.twitterURL(msg.in_reply_to_screen_name + '/statuses/' + msg.in_reply_to_status_id);
if (appMode === 'window' || msg.type === 'user-timeline') {
const text = EchofonCommon.getFormattedString('inReplyToInline', [msg.in_reply_to_screen_name]);
infoChildren.push(
e(AnchorText, {
link,
text,
type: 'tweet-popup',
className: 'echofon-source-link echofon-source-link-left-padding',
}, text)
);
} else {
const icon = e('image', {
className: 'echofon-in-reply-to-icon',
});
infoChildren.push(
e(AnchorText, {
link,
type: 'tweet-popup',
className: 'echofon-source-link',
}, icon, msg.in_reply_to_screen_name)
);
}
}
/*
if (msg.metadata && msg.metadata.result_type === 'popular') {
if (msg.metadata.recent_retweets) {
infoChildren.push(e(
'description',
{ className: 'echofon-top-tweet-retweets' },
`, retweeted ${msg.metadata.recent_retweets} times`
));
}
}
*/

return e('echofon-status-tagline', {
style: {
fontSize: (fontSize - 1) + 'px',
display: 'block',
},
}, ...infoChildren);
};

var EchofonCommon = {

FFVersion: 0,
Expand Down Expand Up @@ -369,7 +217,7 @@ var EchofonCommon = {
type: 'username',
}, nameLabel);

const rtby = formatText({type: 'retweetedBy', children: linkToUser});
const rtby = EchofonCommon.formatText({type: 'retweetedBy', children: linkToUser});

rt = e('echofon-status-retweet-status', {
anonid: 'retweet',
Expand Down Expand Up @@ -1046,6 +894,20 @@ var EchofonCommon = {
return node;
},

formatText: function({ children, type }) {
const text = getString(type);

// for single value
let arr = text.split(/(%S)/);
if (arr.length > 1) {
arr[1] = children;
return arr;
}

// for multiple values
return text.split(/%(\d)\$S/).map((chunk, i) => ((i % 2) && children[parseInt(chunk)-1]) || chunk);
},

// OAuth
//
startOAuth: function(screen_name, callback) {
Expand Down Expand Up @@ -1114,11 +976,10 @@ var EchofonCommon = {
return EchofonCommon.pref().getIntPref("fontSize");
},

Cc: this.Components.classes,
Ci: this.Components.interfaces
Cc: Components.classes,
Ci: Components.interfaces

};
}

function echofonObserver()
{
Expand Down Expand Up @@ -1183,3 +1044,9 @@ echofonObserver.prototype.remove = function()
{
Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService).removeObserver(this, "echofon-status");
};

// This is the only way I found to expose globally the variables
// the expose-loader sounds interesting but does not attach to the window object
// or maybe I'm mistaken
window.EchofonCommon = EchofonCommon;
window.echofonObserver = echofonObserver;
9 changes: 9 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "full featured, super clean Twitter app for Firefox",
"main": "install.rdf",
"scripts": {
"build": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
Expand All @@ -23,7 +24,15 @@
},
"homepage": "https://github.com/echofox-team/echofon-firefox-unofficial#readme",
"dependencies": {
"babel-polyfill": "^6.20.0",
"react": "^15.4.1",
"react-dom": "^15.4.1"
},
"devDependencies": {
"babel-core": "^6.21.0",
"babel-loader": "^6.2.10",
"babel-preset-env": "^1.1.4",
"babel-preset-react": "^6.16.0",
"webpack": "^2.2.0-rc.1"
}
}
22 changes: 22 additions & 0 deletions src/components/AnchorText/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';

const AnchorText = ({ children, link, text, type, className : defaultClasses = 'echofon-hyperlink', additionalClasses, style, screen_name, created_at, label }) => {
const className = additionalClasses ? defaultClasses + ' ' + additionalClasses : defaultClasses;
const setXULAttributes = (node) => {
if (node) {
node.setAttribute('text', text);
node.setAttribute('tooltip', 'echofon-tooltip');
if (screen_name) node.setAttribute('screen_name', screen_name);
if (created_at) node.setAttribute('created_at', created_at);
if (label) node.setAttribute('label', label);
}
};

return (
<label style={style} className={className} href={link} type={type} ref={setXULAttributes}>
{children}
</label>
);
};

export default AnchorText;
56 changes: 56 additions & 0 deletions src/components/RichText/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from 'react';

// this should be elsewhere
const DISPLAY_STYLE_BOTH = 0;
const DISPLAY_STYLE_NAME = 1;
const DISPLAY_STYLE_SCREEN_NAME = 2;

class RichText extends React.Component {
componentDidMount() {
const { uid, msg, parent_elem } = this.props;

if (msg.entities) {
return EchofonCommon.convertLinksWithEntities(uid, msg, this.refs.node, parent_elem);
}
else {
return EchofonCommon.convertLinksWithRegExp(uid, msg, this.refs.node, parent_elem);
}
}

renderNameHeader() {
const { user } = this.props;
const style = EchofonCommon.pref().getIntPref("displayStyle");

const displayName = (style === DISPLAY_STYLE_NAME) ? user.name : user.screen_name;

return (
<AnchorText
additionalClasses="echofon-status-user"
type="username"
link={EchofonCommon.userViewURL(user.screen_name)}
text={displayName}
screen_name={user.screen_name}
>
{displayName}
</AnchorText>
);
}

render() {
const style = EchofonCommon.pref().getIntPref("displayStyle");

// When display style is set to both screen_name and name, a new container is created
// meanwhile when set to only one, it's rendered inline with the message body.
// This will change as we refactor every component later.

return (
<description className="echofon-status-body" ref="node">
{style !== DISPLAY_STYLE_BOTH && this.renderNameHeader()}
{style !== DISPLAY_STYLE_BOTH && ' '}
{/* appended when component mount, this will change */}
</description>
);
}
}

export default RichText;
Loading

0 comments on commit 388082a

Please sign in to comment.