Skip to content

Commit

Permalink
Port LMEM to the latest Crossbuilder version
Browse files Browse the repository at this point in the history
  • Loading branch information
nsteenv committed Feb 22, 2016
1 parent 6b27627 commit 0dc5d9c
Show file tree
Hide file tree
Showing 63 changed files with 3,595 additions and 15 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
"dependencies": {
"chrome-storage-local": "^0.1.5",
"crossmessaging": "^0.2.0",
"lodash": "^4.0.0",
"react": "^0.14.7",
"react-dom": "^0.14.7",
"react-redux": "^4.4.0",
Expand Down
5 changes: 5 additions & 0 deletions src/app/actions/browsing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { findMatchingOffers } from './offers';

export function webRequestLaunched(details) {
return dispatch => dispatch(findMatchingOffers(details));
}
50 changes: 50 additions & 0 deletions src/app/actions/offers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { MATCHING_OFFERS_FOUND, ADD_OFFERS, REMOVE_ALL_OFFERS, REMOVE_ALL_MATCHING_OFFERS } from './../constants/ActionTypes';
import * as _ from 'lodash'

export function findMatchingOffers(details) {
return (dispatch, getState) => {
//if ajax request, we reject it
if(details.type !== "main_frame") return;

//we find matches
const matching_offers = _.filter(getState().offers, (item) => {
return (new RegExp(item.matchingContext.url).test(details.url));
});

//if no matching offers, we stop the dispatching
if(matching_offers.length == 0) return;

dispatch(matchingOffersFound({
context: {
request: details
},
matchingOffers: matching_offers
}));
};
}

export function matchingOffersFound(details) {
return {
type: MATCHING_OFFERS_FOUND,
payload: details
};
}

export function flushMatchingOffers(){
return {
type: REMOVE_ALL_MATCHING_OFFERS
};
}

export function addOffers(details) {
return {
type: ADD_OFFERS,
payload: details
};
}

export function flushOffers() {
return {
type: REMOVE_ALL_OFFERS
};
}
88 changes: 88 additions & 0 deletions src/app/components/Alternatives.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React, { Component, PropTypes } from 'react';

const styles = {
position: "fixed",
bottom: 0,
left: 0,
right: 0,
minHeight: '225px',
zIndex: 99999,
};

const Alternatives = ({matching, stylesUrl, imagesUrl}) => (
<section id="lmem--alternatives--root" style={styles}>
<link href='https://fonts.googleapis.com/css?family=Ubuntu:400,300,300italic,400italic,500,500italic,700,700italic' rel='stylesheet' type='text/css' />
<link rel="stylesheet" href={stylesUrl} />
<div className="main">
<div className="wrapperframe">
<div className="mainframe"><div className="mainframe-inner">
<div className="highlight">
<p className="reco">{matching.description}</p>
<div className="button-directive">
<a href={matching.alternatives[0].url} target="_blank" className="button with-image reco-button">
<img src={ imagesUrl + 'arrow.svg' } className="reco-picto" />
<span className="button-label">{matching.alternatives[0].title}</span>
</a>
</div>
</div>
</div></div>
</div>

<aside className="lmem-topbar fixed">
<div className="lmem-topbar-notification">

<div className="mainframe">
<div className="mainframe-inner">
<h1 className="lmem-topbar-title">
{ 'Le M' + String.fromCharCode(234) + 'me en Mieux selon ' }
<strong>{matching.alternatives[0].contributor }</strong>
</h1>
</div>
</div>
</div>

<div className="button-wrapper">
<div className="button-directive">
<a title="" target="" className="button button-compact with-image">
<img src={ imagesUrl + 'arrow.svg' } className="lmem-controls-picto lmem-controls-close" />
<span className="button-label">{ 'R' + String.fromCharCode(233) + 'duire' }</span>
</a>
</div>
</div>

<a className="lmem-topbar-logo with-tooltip" href="">
<img src={ imagesUrl + 'logo-lmem.svg' } alt="" />
<span className="tooltip tooltip-right"><span>
{ 'R' + String.fromCharCode(233) + 'duire le panneau comparatif' }
</span></span>
</a>
</aside>

<footer className="lmem-footer sideframe fixed">
<div className="lmem-footer-wrapper">
<a className="lmem-footer-logo with-tooltip" href="">
<img src={ imagesUrl + 'logo-lmem.svg' } alt="" />
<span className="tooltip tooltip-right"><span>
{ 'R' + String.fromCharCode(233) + 'duire le panneau comparatif' }
</span></span>
</a>

<div className="lmem-disclaimer">
<a className="no-visited with-tooltip" href="http://www.lmem.net/" target="_blank">{ 'Le M' + String.fromCharCode(234) + 'me en Mieux' }</a>
{ ', service ind' + String.fromCharCode(233) + 'pendant du site Web consult' + String.fromCharCode(233) + ' ' }
(<a target="_blank" href="http://cgu.lmem.net/">
{ 'conditions g' + String.fromCharCode(233) + 'n' + String.fromCharCode(233) + 'rales d' + String.fromCharCode(8217) + 'utilisation' }</a>).
</div>
</div>
</footer>
</div>
</section>
);

Alternatives.propTypes = {
alternative: PropTypes.object.isRequired,
stylesUrl: PropTypes.string.isRequired,
imagesUrl: PropTypes.string.isRequired,
};

export default Alternatives;
23 changes: 23 additions & 0 deletions src/app/components/Editor/AddOffers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { Component, PropTypes } from 'react';

class AddOffers extends React.Component {

render () {
const { addOffers } = this.props;
return (
<div>
<textarea style={{width: "100%", height: "100px"}} ref="add_offer"></textarea><br />
<a href="#" onClick={(e)=> {
addOffers(this.refs.add_offer.value) && e.preventDefault();
}}>Ajouter</a>
</div>
);
}
}

AddOffers.propTypes = {
addOffers: PropTypes.func.isRequired
};


export default AddOffers;
48 changes: 48 additions & 0 deletions src/app/components/Editor/SeeCurrentOffers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { Component, PropTypes } from 'react';

class SeeCurrentOffers extends React.Component {

state = { displayIt: false };

toggleDisplay(){ this.setState({ displayIt: !this.state.displayIt }); }
prettyPrintOffers(offers){ return JSON.stringify(offers,null,2); }

render () {
const { store: reduxStore, actions: { flushMatchingOffers, flushOffers } } = this.props;
const displayStyle = {
textAlign: "left",
border: "solid 2px black",
padding: "25px",
whiteSpace: "pre-wrap"
};

return (
<div>
<a href="#" onClick={(e)=>(this.toggleDisplay() && e.preventDefault())}>
{(this.state.displayIt)
? 'hide offers'
: 'display current offers'
}
</a>
{(this.state.displayIt)
? <div>
<h3>Offres</h3>
<pre style={displayStyle}>{this.prettyPrintOffers(reduxStore.offers)}</pre>
<a href="#" onClick={(e) => (flushOffers() && e.preventDefault)}>Vider les offres</a>
&nbsp;|&nbsp;
<a href="#" onClick={(e) => (flushMatchingOffers() && e.preventDefault)}>Vider les alternatives</a>
</div>
: ''
}
</div>
);
}
}

SeeCurrentOffers.propTypes = {
store: PropTypes.object.isRequired,
actions: PropTypes.object.isRequired,
};


export default SeeCurrentOffers;
6 changes: 6 additions & 0 deletions src/app/constants/ActionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@ export const NOTIFY_RECEIVE = 'notify/RECEIVE';

export const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
export const DECREMENT_COUNTER = 'DECREMENT_COUNTER';

export const MATCHING_OFFERS_FOUND = 'matching_offers/FOUND';
export const REMOVE_ALL_MATCHING_OFFERS = 'matching_offers/FLUSH';

export const ADD_OFFERS = 'offers/APPEND';
export const REMOVE_ALL_OFFERS = 'offers/FLUSH';
5 changes: 5 additions & 0 deletions src/app/constants/assetsUrls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { getURL } from '../../vapi/chromeBackground'

export const IMAGES_URL = getURL('img/');
export const FONTS_URL = getURL('fonts/');
export const STYLES_URL = getURL('styles/');
8 changes: 4 additions & 4 deletions src/app/containers/App.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { connect } from 'react-redux';

import Counter from '../components/Counter';
import * as counterActions from '../actions/counter';
import Alternative from '../components/Alternatives';
import * as alternativesActions from '../actions/offers';

function mapStateToProps(state) {
return { state };
}

const mapDispatchToProps = counterActions; // { ...counterActions, ...};
const mapDispatchToProps = alternativesActions; // { ...counterActions, ...};

export default connect(mapStateToProps, mapDispatchToProps)(Counter);
export default connect(mapStateToProps, mapDispatchToProps)(Alternative);
3 changes: 3 additions & 0 deletions src/app/containers/ContentScript/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/**
* Created by alemaire on 21/01/2016.
*/
3 changes: 3 additions & 0 deletions src/app/containers/ContentScript/Root.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/**
* Created by alemaire on 21/01/2016.
*/
27 changes: 27 additions & 0 deletions src/app/containers/PopUp/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';

import SeeCurrentOffers from '../../components/Editor/SeeCurrentOffers';
import AddOffers from '../../components/Editor/AddOffers';

import * as alternativesActions from '../../actions/offers';

function mapStateToProps(store) {
return { store };
}

const mapDispatchToProps = (dispatch) => {
return {
actions: bindActionCreators(alternativesActions, dispatch)
};
};

const PopupApp = ({ store, actions }) => (
<div style={{width: "600px"}}>
<AddOffers addOffers={actions.addOffers} />
<SeeCurrentOffers store={store} actions={actions} />
</div>
);

export default connect(mapStateToProps, mapDispatchToProps)(PopupApp);
15 changes: 15 additions & 0 deletions src/app/containers/PopUp/Root.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React, { Component, PropTypes } from 'react';
import { Provider } from 'react-redux';
import PopupApp from './App';

const PopUpRoot = ({store}) => (
<Provider store={store}>
<PopupApp />
</Provider>
);

PopUpRoot.propTypes = {
store: PropTypes.object.isRequired
};

export default PopUpRoot;
7 changes: 4 additions & 3 deletions src/app/containers/Root.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import App from './App';

export default class Root extends Component {
static propTypes = {
store: PropTypes.object.isRequired
store: PropTypes.object.isRequired,
tabId: PropTypes.number.isRequired,
};

render() {
const { store } = this.props;
const { store, tabId } = this.props;
return (
<Provider store={store}>
<Provider store={store} tabId={tabId}>
<App />
</Provider>
);
Expand Down
51 changes: 51 additions & 0 deletions src/app/injector/alternatives.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as _ from 'lodash';
import React from 'react';
import { renderToStaticMarkup } from 'react-dom/server';

import Alternative from 'app/components/Alternatives';
import { STYLES_URL, IMAGES_URL } from 'app/constants/assetsUrls';

class AlternativesInjector {

constructor(vAPI) {
this.vAPI = vAPI;
}

listen(store) {
store.subscribe(() => {
this.renderForEachTab(store.getState());
});
}

buildDom(component) {
return "console.log('Prepare to inject');\
function ready(f){ /in/.test(document.readyState) ? setTimeout(ready,90,f):f() }; \
ready(function() {\
console.log('LMEM injection'); \
var div = document.createElement('div'); \
div.innerHTML = '"+ component +"'; \
document.body.appendChild(div); \
});";
}

renderForEachTab(state) {
setTimeout(()=>{
_.forIn(state.matchingTabs, (value, key) => {
this.vAPI.tabs.injectScript(key, {
code: this.buildDom(this.renderForTab(key, value)),
runAt: 'document_start'
});
});
}, 1500); //we wait for the Dom to be built
}

renderForTab(tabId, alternative) {
var alternativeTo = alternative.matchingOffers[0];
var stylesUrl = STYLES_URL + 'main.css';
return renderToStaticMarkup(
<Alternative matching={alternativeTo} stylesUrl={stylesUrl} imagesUrl={IMAGES_URL} />
)
}
}

export default AlternativesInjector;
7 changes: 7 additions & 0 deletions src/app/injector/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import AlternativesInjector from './alternatives'

export default {
init: function(vAPI, store) {
new AlternativesInjector(vAPI).listen(store);
}
}
Loading

0 comments on commit 0dc5d9c

Please sign in to comment.