mirror of
https://github.com/responsively-org/responsively-app
synced 2024-09-21 06:41:55 +00:00
Merge conflicts resolved
This commit is contained in:
commit
02cd39304a
2674 changed files with 817 additions and 468776 deletions
|
@ -352,6 +352,24 @@
|
|||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sidthesloth92",
|
||||
"name": "Dinesh Balaji",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/4656109?v=4",
|
||||
"profile": "http://dbwriteups.wordpress.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "med1001",
|
||||
"name": "MedBMoussa",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/26111211?v=4",
|
||||
"profile": "https://github.com/med1001",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 5,
|
||||
|
|
37
.github/ISSUE_TEMPLATE/01-bug-report.md
vendored
Normal file
37
.github/ISSUE_TEMPLATE/01-bug-report.md
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
name: "\U0001F41E Bug report"
|
||||
about: Report a bug in Responsively
|
||||
---
|
||||
|
||||
<!-- 🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅
|
||||
Hi there! 😄
|
||||
|
||||
To expedite issue processing please search open and closed issues before submitting a new one. Existing issues often contain information about workarounds, resolution, or progress updates.
|
||||
🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅 -->
|
||||
|
||||
# 🐞 bug report
|
||||
|
||||
### ✍️ Description
|
||||
|
||||
<!-- A clear and concise description of the problem. -->
|
||||
|
||||
### 🕵🏼♂️ Is this a regression?
|
||||
|
||||
<!-- Did this behavior use to work in the previous version? -->
|
||||
|
||||
### 🔬 Minimal Reproduction
|
||||
|
||||
<!-- Clear steps to re-produce the issue. -->
|
||||
|
||||
### 🌍 Your Environment
|
||||
|
||||
<!-- Press `Ctrl/Cmd + F1` and paste it here. -->
|
||||
<pre><code>
|
||||
|
||||
</code></pre>
|
||||
|
||||
### 🔥 Exception or Error or Screenshot
|
||||
|
||||
<pre><code>
|
||||
|
||||
</code></pre>
|
18
.github/ISSUE_TEMPLATE/02-feature-request.md
vendored
Normal file
18
.github/ISSUE_TEMPLATE/02-feature-request.md
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
name: "\U0001F680 Feature request"
|
||||
about: Suggest a feature for Responsively.
|
||||
---
|
||||
|
||||
# 🚀 Feature Request
|
||||
|
||||
### 📝 Description
|
||||
|
||||
<!-- A clear and concise description of the problem or missing capability. -->
|
||||
|
||||
### ✨ Describe the solution you'd like
|
||||
|
||||
<!-- If you have a solution in mind, please describe it. -->
|
||||
|
||||
### ✍️ Describe alternatives you've considered
|
||||
|
||||
<!-- Have you considered any alternative solutions or workarounds? -->
|
13
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
13
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
# ✨ Pull Request
|
||||
|
||||
### 📓 Referenced Issue
|
||||
|
||||
<!-- Please link the related issue. Use # before the issue number and use the verbs 'fixes', 'resolves' to auto-link it, for eg, Fixes: #<issue-number> -->
|
||||
|
||||
### ℹ️ About the PR
|
||||
|
||||
<!-- Please provide a description of your solution if it is not clear in the related issue or if the PR has a breaking change. If there is an interesting topic to discuss or you have questions or there is an issue with electron or another library that you have used. -->
|
||||
|
||||
### 🖼️ Testing Scenarios / Screenshots
|
||||
|
||||
<!-- Please include screenshots or gif to showcase the final output. Also, try to explain the testing you did to validate your change. -->
|
1
.github/opencollective.yml
vendored
Normal file
1
.github/opencollective.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
collective: responsively
|
|
@ -63,11 +63,16 @@ Please visit the website to know more about the application - https://responsive
|
|||
## Download
|
||||
The application is available for Mac, Windows and Linux platforms. Please download it from here - https://github.com/responsively-org/responsively-app/releases
|
||||
|
||||
Alternatively, MacOS users can use brew to install it:
|
||||
Alternatively, MacOS users can use [`brew`](https://formulae.brew.sh/cask/responsively) to install it:
|
||||
```bash
|
||||
brew cask install responsively
|
||||
```
|
||||
|
||||
Also, Windows users can use [`chocolatey`](https://chocolatey.org/packages/responsively/) to install it:
|
||||
```bash
|
||||
choco install responsively
|
||||
```
|
||||
|
||||
Follow on Twitter for future updates - [![Twitter Follow](https://img.shields.io/twitter/follow/ResponsivelyApp?style=social)](https://twitter.com/ResponsivelyApp)
|
||||
|
||||
## Issues
|
||||
|
@ -147,6 +152,8 @@ Thanks go to these wonderful people ([emoji key](https://allcontributors.org/doc
|
|||
<td align="center"><a href="http://ruisaraiva.dev"><img src="https://avatars2.githubusercontent.com/u/7356098?v=4" width="100px;" alt=""/><br /><sub><b>Rui Saraiva</b></sub></a><br /><a href="https://github.com/responsively-org/responsively-app/commits?author=ruisaraiva19" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.bakirci.nl"><img src="https://avatars2.githubusercontent.com/u/9880089?v=4" width="100px;" alt=""/><br /><sub><b>Mehmet Bakirci</b></sub></a><br /><a href="https://github.com/responsively-org/responsively-app/commits?author=MBakirci" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/JLambertazzo"><img src="https://avatars0.githubusercontent.com/u/42924425?v=4" width="100px;" alt=""/><br /><sub><b>Julien Bertazzo Lambert</b></sub></a><br /><a href="https://github.com/responsively-org/responsively-app/commits?author=JLambertazzo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://dbwriteups.wordpress.com"><img src="https://avatars3.githubusercontent.com/u/4656109?v=4" width="100px;" alt=""/><br /><sub><b>Dinesh Balaji</b></sub></a><br /><a href="https://github.com/responsively-org/responsively-app/commits?author=sidthesloth92" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/med1001"><img src="https://avatars3.githubusercontent.com/u/26111211?v=4" width="100px;" alt=""/><br /><sub><b>MedBMoussa</b></sub></a><br /><a href="https://github.com/responsively-org/responsively-app/commits?author=med1001" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React, {Fragment} from 'react';
|
||||
import {Switch, Route} from 'react-router';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import {makeStyles} from '@material-ui/core/styles';
|
||||
|
@ -9,15 +8,13 @@ import LeftIconsPaneContainer from './containers/LeftIconsPaneContainer';
|
|||
import StatusBarContainer from './containers/StatusBarContainer';
|
||||
import DevToolResizerContainer from './containers/DevToolResizerContainer';
|
||||
|
||||
const Routes = () => {
|
||||
const AppContent = () => {
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<Fragment>
|
||||
<Paper elevation={0} className={classes.root}>
|
||||
<div className={classes.contentColumn}>
|
||||
<Switch>
|
||||
<Route path={routes.HOME} component={Browser} />
|
||||
</Switch>
|
||||
<Browser />
|
||||
</div>
|
||||
</Paper>
|
||||
<StatusBarContainer />
|
||||
|
@ -69,4 +66,4 @@ const useStyles = makeStyles(theme => ({
|
|||
},
|
||||
}));
|
||||
|
||||
export default Routes;
|
||||
export default AppContent;
|
|
@ -15,9 +15,11 @@ import {
|
|||
DELETE_STORAGE,
|
||||
ADDRESS_CHANGE,
|
||||
STOP_LOADING,
|
||||
TOGGLE_DEVICE_DESIGN_MODE_STATE,
|
||||
} from '../constants/pubsubEvents';
|
||||
import {getBounds, getDefaultDevToolsWindowSize} from '../reducers/browser';
|
||||
import {DEVTOOLS_MODES} from '../constants/previewerLayouts';
|
||||
import {normalizeZoomLevel} from '../utils/browserUtils';
|
||||
|
||||
export const NEW_ADDRESS = 'NEW_ADDRESS';
|
||||
export const NEW_PAGE_META_FIELD = 'NEW_PAGE_META_FIELD';
|
||||
|
@ -44,6 +46,10 @@ export const NEW_FOCUSED_DEVICE = 'NEW_FOCUSED_DEVICE';
|
|||
export const TOGGLE_ALL_DEVICES_MUTED = 'TOGGLE_ALL_DEVICES_MUTED';
|
||||
export const TOGGLE_DEVICE_MUTED = 'TOGGLE_DEVICE_MUTED';
|
||||
export const NEW_THEME = 'NEW_THEME';
|
||||
export const TOGGLE_ALL_DEVICES_DESIGN_MODE = 'TOGGLE_ALL_DEVICES_DESIGN_MODE';
|
||||
export const TOGGLE_DEVICE_DESIGN_MODE = 'TOGGLE_DEVICE_DESIGN_MODE';
|
||||
export const SET_HEADER_VISIBILITY = 'SET_HEADER_VISIBILITY';
|
||||
export const SET_LEFT_PANE_VISIBILITY = 'SET_LEFT_PANE_VISIBILITY';
|
||||
|
||||
export function newAddress(address) {
|
||||
return {
|
||||
|
@ -208,6 +214,19 @@ export function toggleDeviceMuted(deviceId, isMuted) {
|
|||
};
|
||||
}
|
||||
|
||||
export function toggleAllDevicesDesignMode() {
|
||||
return {
|
||||
type: TOGGLE_ALL_DEVICES_DESIGN_MODE,
|
||||
};
|
||||
}
|
||||
|
||||
export function toggleDeviceDesignMode(deviceId) {
|
||||
return {
|
||||
type: TOGGLE_DEVICE_DESIGN_MODE,
|
||||
deviceId,
|
||||
};
|
||||
}
|
||||
|
||||
export function onAddressChange(newURL, force) {
|
||||
return (dispatch: Dispatch, getState: RootStateType) => {
|
||||
const {
|
||||
|
@ -249,12 +268,13 @@ export function onZoomChange(newLevel) {
|
|||
const {
|
||||
browser: {zoomLevel},
|
||||
} = getState();
|
||||
const normalizedZoomLevel = normalizeZoomLevel(newLevel);
|
||||
|
||||
if (newLevel === zoomLevel) {
|
||||
if (normalizedZoomLevel === zoomLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(newZoomLevel(newLevel));
|
||||
dispatch(newZoomLevel(normalizedZoomLevel));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -720,6 +740,23 @@ export function onDeviceMutedChange(deviceId, isMuted) {
|
|||
};
|
||||
}
|
||||
|
||||
export function onToggleAllDeviceDesignMode() {
|
||||
return (dispatch: Dispatch, getState: RootStateType) => {
|
||||
const {
|
||||
browser: {allDevicesInDesignMode},
|
||||
} = getState();
|
||||
const next = !allDevicesInDesignMode;
|
||||
pubsub.publish(TOGGLE_DEVICE_DESIGN_MODE_STATE, [{designMode: next}]);
|
||||
dispatch(toggleAllDevicesDesignMode());
|
||||
};
|
||||
}
|
||||
|
||||
export function onToggleDeviceDesignMode(deviceId) {
|
||||
return (dispatch: Dispatch, getState: RootStateType) => {
|
||||
dispatch(toggleDeviceDesignMode(deviceId));
|
||||
};
|
||||
}
|
||||
|
||||
export function toggleInspector() {
|
||||
return (dispatch: Dispatch, getState: RootStateType) => {
|
||||
const {
|
||||
|
@ -848,3 +885,25 @@ export function setTheme(theme) {
|
|||
theme,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows/Hides the top control pane.
|
||||
* @param {boolean} isVisible Shows the top pane when true and hides when false.
|
||||
*/
|
||||
export function setHeaderVisibility(isVisible: boolean) {
|
||||
return {
|
||||
type: SET_HEADER_VISIBILITY,
|
||||
isVisible,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows/Hides the left control pane.
|
||||
* @param {boolean} isVisible Shows the left control pane when true and hides when false.
|
||||
*/
|
||||
export function setLeftPaneVisibility(isVisible: boolean) {
|
||||
return {
|
||||
type: SET_LEFT_PANE_VISIBILITY,
|
||||
isVisible,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import type {Dispatch, GetState} from '../reducers/types';
|
|||
import {
|
||||
SET_NETWORK_TROTTLING_PROFILE,
|
||||
CLEAR_NETWORK_CACHE,
|
||||
SET_NETWORK_PROXY_PROFILE,
|
||||
} from '../constants/pubsubEvents';
|
||||
import {convertToProxyConfig, proxyRuleToString} from '../utils/proxyUtils';
|
||||
import {ipcRenderer} from 'electron';
|
||||
|
|
|
@ -11,7 +11,6 @@ import logo from '../../../resources/logo.svg';
|
|||
|
||||
function updateNotificationStatus(id, action) {
|
||||
const notifications = settings.get(APP_NOTIFICATION) || [];
|
||||
const commonClasses = useCommonStyles();
|
||||
|
||||
const notificationStatusObject = {
|
||||
id,
|
||||
|
@ -39,6 +38,8 @@ function checkIfInteracted(id) {
|
|||
const AppNotification = () => {
|
||||
const [notificationInteracted, setNotificationInteracted] = useState(false);
|
||||
const [data, setData] = useState(null);
|
||||
const commonClasses = useCommonStyles();
|
||||
|
||||
useEffect(() => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
return;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
padding: 10px 20px 20px 20px;
|
||||
min-width: 250px;
|
||||
max-width: 320px;
|
||||
color: #f8f8f8;
|
||||
}
|
||||
|
||||
.titleContainer {
|
||||
|
|
|
@ -9,6 +9,7 @@ import CloseIcon from '@material-ui/icons/Close';
|
|||
import AddIcon from '@material-ui/icons/Add';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import Toolbar from '@material-ui/core/Toolbar';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import {DragDropContext, Droppable, Draggable} from 'react-beautiful-dnd';
|
||||
|
@ -16,6 +17,7 @@ import LightBulbIcon from '../icons/LightBulb';
|
|||
import DeviceList from './DeviceList';
|
||||
import AddDeviceContainer from '../../containers/AddDeviceContainer';
|
||||
import ErrorBoundary from '../ErrorBoundary';
|
||||
import {recommendedMaxNumberOfDevices} from '../../utils/deviceManagerUtils';
|
||||
|
||||
import styles from './styles.css';
|
||||
|
||||
|
@ -29,6 +31,8 @@ function DeviceManager(props) {
|
|||
inactiveFiltered: [],
|
||||
});
|
||||
|
||||
const [maxDevicesWarning, setMaxDevicesWarning] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const activeDevices = props.browser.devices;
|
||||
const activeDevicesById = activeDevices.reduce((acc, val) => {
|
||||
|
@ -36,6 +40,8 @@ function DeviceManager(props) {
|
|||
return acc;
|
||||
}, {});
|
||||
|
||||
setMaxDevicesWarning(activeDevices.length >= recommendedMaxNumberOfDevices);
|
||||
|
||||
const currentInactiveDevicesById = devices.inactive.reduce((acc, val) => {
|
||||
acc[val.id] = val;
|
||||
return acc;
|
||||
|
@ -104,6 +110,7 @@ function DeviceManager(props) {
|
|||
const updateDevices = devices => {
|
||||
const active = [...devices.active];
|
||||
const inactive = [...devices.inactive];
|
||||
setMaxDevicesWarning(active.length >= recommendedMaxNumberOfDevices);
|
||||
setDevices({active, inactive});
|
||||
props.setActiveDevices(active);
|
||||
};
|
||||
|
@ -115,7 +122,10 @@ function DeviceManager(props) {
|
|||
color="primary"
|
||||
aria-label="upload picture"
|
||||
component="span"
|
||||
onClick={() => setOpen(true)}
|
||||
onClick={() => {
|
||||
props.onDevToolsClose(null, true);
|
||||
setOpen(true);
|
||||
}}
|
||||
className={styles.editButton}
|
||||
>
|
||||
Customize
|
||||
|
@ -133,6 +143,12 @@ function DeviceManager(props) {
|
|||
</Toolbar>
|
||||
</AppBar>
|
||||
<div className={styles.container}>
|
||||
{maxDevicesWarning && (
|
||||
<Alert severity="warning" className={classes.maxDevicesWarning}>
|
||||
Adding more than {recommendedMaxNumberOfDevices} devices may
|
||||
slow down the system.
|
||||
</Alert>
|
||||
)}
|
||||
<Typography variant="body1" className={classes.toolTip}>
|
||||
<span>✨</span>Drag and drop the devices across to re-order them.
|
||||
</Typography>
|
||||
|
@ -190,6 +206,10 @@ const useStyles = makeStyles(theme => ({
|
|||
color: theme.palette.text.primary,
|
||||
width: 'fit-content',
|
||||
},
|
||||
maxDevicesWarning: {
|
||||
position: 'absolute',
|
||||
top: '80px',
|
||||
},
|
||||
}));
|
||||
|
||||
export default DeviceManager;
|
||||
|
|
|
@ -69,6 +69,7 @@ class ErrorBoundary extends React.Component {
|
|||
|
||||
const styles = theme => ({
|
||||
errorBoundaryContainer: {
|
||||
background: theme.palette.background.default,
|
||||
overflowY: 'auto',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
|
|
|
@ -12,23 +12,35 @@ import InputAdornment from '@material-ui/core/InputAdornment';
|
|||
import {remote, ipcRenderer} from 'electron';
|
||||
import cx from 'classnames';
|
||||
import {
|
||||
makeStyles,
|
||||
Popper,
|
||||
Fade,
|
||||
Paper,
|
||||
Typography,
|
||||
ClickAwayListener,
|
||||
} from '@material-ui/core';
|
||||
import {useTheme} from '@material-ui/core/styles';
|
||||
import {useTheme, makeStyles} from '@material-ui/core/styles';
|
||||
import styles from './styles.css';
|
||||
import useCommonStyles from '../useCommonStyles';
|
||||
import helpScreenshot from './help-screenshot.png';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
const useStyles = makeStyles(theme => ({
|
||||
adornedEnd: {
|
||||
paddingRight: 0,
|
||||
},
|
||||
});
|
||||
extensionsHelp: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: 500,
|
||||
padding: 12,
|
||||
color: 'white',
|
||||
borderRadius: 4,
|
||||
background: theme.palette.mode({
|
||||
light: theme.palette.secondary.main,
|
||||
dark: '#313131',
|
||||
}),
|
||||
boxShadow: '3px 3px 6px 1px black',
|
||||
},
|
||||
}));
|
||||
|
||||
export default function ExtensionsManager({triggerNavigationReload}) {
|
||||
const {BrowserWindow} = remote;
|
||||
|
@ -114,22 +126,25 @@ export default function ExtensionsManager({triggerNavigationReload}) {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Popper open={helpOpen} anchorEl={anchorEl} placement="bottom" transition>
|
||||
<Popper
|
||||
open={helpOpen}
|
||||
anchorEl={anchorEl}
|
||||
placement="bottom-start"
|
||||
transition
|
||||
>
|
||||
{({TransitionProps}) => (
|
||||
<ClickAwayListener onClickAway={toggleHelp}>
|
||||
<Fade {...TransitionProps} timeout={350}>
|
||||
<Paper>
|
||||
<div className={styles.extensionsHelp}>
|
||||
<div className={classes.extensionsHelp}>
|
||||
<p className={cx(styles.extensionsHelpText)}>
|
||||
Find the extension on Chrome Web Store and copy the
|
||||
extension ID from the address bar(as shown below).
|
||||
Find the extension on Chrome Web Store and copy the extension
|
||||
ID from the address bar(as shown below).
|
||||
</p>
|
||||
<img
|
||||
className={styles.extensionsHelpImg}
|
||||
src={helpScreenshot}
|
||||
/>
|
||||
</div>
|
||||
</Paper>
|
||||
</Fade>
|
||||
</ClickAwayListener>
|
||||
)}
|
||||
|
|
|
@ -49,19 +49,9 @@
|
|||
margin-top: 12px !important;
|
||||
}
|
||||
|
||||
.extensionsHelp {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 500px;
|
||||
padding: 12px;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
background: #252526;
|
||||
box-shadow: 3px 3px 6px 1px black;
|
||||
}
|
||||
|
||||
.extensionsHelpText {
|
||||
font-size: 12px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.extensionsHelpImg {
|
||||
|
|
|
@ -10,14 +10,15 @@ import PermissionPopup from '../PermissionPopup';
|
|||
|
||||
import NavigationControlsContainer from '../../containers/NavigationControlsContainer';
|
||||
import BookmarksBar from '../../containers/BookmarksBarContainer';
|
||||
import AppNotification from '../AppNotification/AppNotification';
|
||||
import Logo from '../icons/Logo';
|
||||
import ZenButton from '../ZenButton';
|
||||
import cx from 'classnames';
|
||||
|
||||
const Header = () => {
|
||||
const Header = props => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<div className={cx([classes.container, {zenMode: !props.isHeaderVisible}])}>
|
||||
<div className={classes.firstRow}>
|
||||
<Logo className={classes.logo} width={40} height={40} />
|
||||
<Grid
|
||||
|
@ -52,23 +53,46 @@ const Header = () => {
|
|||
pauseOnHover
|
||||
toastClassName={classes.darkToast}
|
||||
/>
|
||||
<AppNotification />
|
||||
<ZenButton
|
||||
active={!props.isHeaderVisible}
|
||||
onClick={() => props.setHeaderVisibility(!props.isHeaderVisible)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
container: {
|
||||
position: 'relative',
|
||||
background: theme.palette.background.l1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
padding: os.platform() === 'darwin' ? '20px 0 5px' : '0 0 0',
|
||||
padding: os.platform() === 'darwin' ? '0 0 5px' : '0 0 0',
|
||||
boxShadow: `0 ${theme.palette.mode({
|
||||
light: '0px',
|
||||
dark: '3px',
|
||||
})} 5px rgba(0, 0, 0, 0.35)`,
|
||||
zIndex: 500,
|
||||
transform: 'translateY(0)',
|
||||
transition: 'transform .1s ease-out',
|
||||
'& .zenButton': {
|
||||
background: theme.palette.background.l1,
|
||||
display: 'none',
|
||||
position: 'absolute',
|
||||
bottom: '0px',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, 100%)',
|
||||
},
|
||||
'&:hover .zenButton': {
|
||||
display: 'flex',
|
||||
},
|
||||
'&.zenMode': {
|
||||
transform: 'translateY(-100%)',
|
||||
},
|
||||
'&.zenMode .zenButton': {
|
||||
display: 'flex',
|
||||
},
|
||||
},
|
||||
firstRow: {
|
||||
display: 'flex',
|
||||
|
|
20
desktop-app/app/components/HorizontalSpacer/index.js
Normal file
20
desktop-app/app/components/HorizontalSpacer/index.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import React from 'react';
|
||||
import {makeStyles} from '@material-ui/core/styles';
|
||||
|
||||
/**
|
||||
* Application toolbar that appears at the top of a window.
|
||||
*/
|
||||
const HorizontalSpacer = () => {
|
||||
const classes = useStyles();
|
||||
return <div className={classes.container} />;
|
||||
};
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
container: {
|
||||
background: theme.palette.background.l1,
|
||||
padding: '11px 0',
|
||||
zIndex: '10',
|
||||
},
|
||||
}));
|
||||
|
||||
export default HorizontalSpacer;
|
|
@ -9,6 +9,7 @@ import NetworkIcon from '../icons/Network';
|
|||
import Logo from '../icons/Logo';
|
||||
import Gift from '../icons/Gift';
|
||||
import Headway from '../Headway';
|
||||
import ZenButton from '../ZenButton';
|
||||
|
||||
import styles from './styles.css';
|
||||
import useCommonStyles from '../useCommonStyles';
|
||||
|
@ -23,14 +24,38 @@ import {makeStyles} from '@material-ui/core/styles';
|
|||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
container: {
|
||||
position: 'relative',
|
||||
backgroundColor: theme.palette.background.l2,
|
||||
display: 'flex',
|
||||
flexFlow: 'column',
|
||||
marginTop: '-50px',
|
||||
paddingTop: '50px',
|
||||
width: 50,
|
||||
boxShadow: `0 ${theme.palette.mode({
|
||||
light: '3px',
|
||||
dark: '3px',
|
||||
})} 5px rgba(0, 0, 0, 0.35)`,
|
||||
zIndex: 1,
|
||||
transform: 'translateX(0)',
|
||||
transition: 'transform .1s ease-out',
|
||||
'& .zenButton': {
|
||||
position: 'absolute',
|
||||
background: theme.palette.background.l2,
|
||||
top: '50%',
|
||||
right: '0',
|
||||
transformOrigin: 'center',
|
||||
transform: 'translate(100%, -50%) rotate(-90deg) translateY(-30px)',
|
||||
display: 'none',
|
||||
},
|
||||
'&:hover .zenButton': {
|
||||
display: 'flex',
|
||||
},
|
||||
'&.zenMode': {
|
||||
transform: 'translateX(-100%)',
|
||||
},
|
||||
'&.zenMode .zenButton': {
|
||||
display: 'flex',
|
||||
},
|
||||
},
|
||||
leftPaneIcon: {
|
||||
'& svg': {
|
||||
|
@ -55,7 +80,11 @@ const LeftIconsPane = props => {
|
|||
props.openDrawerAndSetContent(content);
|
||||
};
|
||||
return (
|
||||
<div className={mStyles.container}>
|
||||
<div
|
||||
className={`${mStyles.container} ${
|
||||
props.isLeftPaneVisible ? '' : 'zenMode'
|
||||
}`}
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
spacing={1}
|
||||
|
@ -118,6 +147,12 @@ const LeftIconsPane = props => {
|
|||
</Grid>
|
||||
</Grid>
|
||||
<Headway />
|
||||
{!props.drawer.open && (
|
||||
<ZenButton
|
||||
active={!props.isLeftPaneVisible}
|
||||
onClick={() => props.setLeftPaneVisibility(!props.isLeftPaneVisible)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -96,7 +96,7 @@ const useStyles = makeStyles(theme => ({
|
|||
marginBottom: 0,
|
||||
},
|
||||
wilcardsAndMoreLink: {
|
||||
color: 'white',
|
||||
color: theme.palette.text.normal,
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
bypassListField: {
|
||||
|
|
|
@ -7,6 +7,11 @@ import {CAPABILITIES} from '../../constants/devices';
|
|||
import useCommonStyles from '../useCommonStyles';
|
||||
import {getDeviceIcon} from '../../utils/iconUtils';
|
||||
import KebabMenu from '../KebabMenu';
|
||||
import {
|
||||
FLIP_ORIENTATION_ALL_DEVICES,
|
||||
SCREENSHOT_ALL_DEVICES,
|
||||
} from '../../constants/pubsubEvents';
|
||||
import pubsub from 'pubsub.js';
|
||||
|
||||
function Renderer(props) {
|
||||
const {device, hidden, transmitNavigatorStatus} = props;
|
||||
|
@ -62,6 +67,22 @@ function Renderer(props) {
|
|||
</div>
|
||||
</div>
|
||||
<KebabMenu>
|
||||
<KebabMenu.Item
|
||||
onClick={() =>
|
||||
pubsub.publish(SCREENSHOT_ALL_DEVICES, [{deviceId: device.id}])
|
||||
}
|
||||
>
|
||||
Full Page Screenshot
|
||||
</KebabMenu.Item>
|
||||
<KebabMenu.Item
|
||||
onClick={() =>
|
||||
pubsub.publish(FLIP_ORIENTATION_ALL_DEVICES, [
|
||||
{deviceId: device.id},
|
||||
])
|
||||
}
|
||||
>
|
||||
Tilt Device
|
||||
</KebabMenu.Item>
|
||||
<KebabMenu.Item
|
||||
onClick={props.device.isMuted ? _unmuteDevice : _muteDevice}
|
||||
>
|
||||
|
|
|
@ -9,6 +9,7 @@ import ScrollUpIcon from '../icons/ScrollUp';
|
|||
import ScreenshotIcon from '../icons/FullScreenshot';
|
||||
import DeviceRotateIcon from '../icons/DeviceRotate';
|
||||
import InspectElementIcon from '../icons/InspectElement';
|
||||
import DesignModeIcon from '../icons/DesignMode';
|
||||
import MutedIcon from '../icons/Muted';
|
||||
import UnmutedIcon from '../icons/Unmuted';
|
||||
import useCommonStyles from '../useCommonStyles';
|
||||
|
@ -33,6 +34,7 @@ const ScrollControls = ({
|
|||
toggleInspector,
|
||||
toggleCSSEditor,
|
||||
onAllDevicesMutedChange,
|
||||
onToggleAllDeviceDesignMode,
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
const theme = useTheme();
|
||||
|
@ -44,7 +46,6 @@ const ScrollControls = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.container}>
|
||||
<Grid container spacing={1} alignItems="center">
|
||||
<Grid item className={commonClasses.icon}>
|
||||
|
@ -108,11 +109,28 @@ const ScrollControls = ({
|
|||
</div>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
className={cx(commonClasses.icon, {
|
||||
[commonClasses.iconSelected]: browser.allDevicesInDesignMode,
|
||||
})}
|
||||
>
|
||||
<Tooltip
|
||||
title={
|
||||
browser.allDevicesInDesignMode
|
||||
? 'Disable Design Mode on all devices'
|
||||
: 'Enable Design Mode on all devices'
|
||||
}
|
||||
>
|
||||
<div onClick={onToggleAllDeviceDesignMode}>
|
||||
<DesignModeIcon {...{...iconProps, ...{height: 22, width: 22}}} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
<ToggleTouch iconProps={iconProps} />
|
||||
<ZoomContainer iconProps={iconProps} />
|
||||
</Grid>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@ import {withStyles, withTheme} from '@material-ui/core/styles';
|
|||
import debounce from 'lodash/debounce';
|
||||
import pubsub from 'pubsub.js';
|
||||
import BugIcon from '../icons/Bug';
|
||||
import MutedIcon from '../icons/Muted';
|
||||
import UnmutedIcon from '../icons/Unmuted';
|
||||
import FullScreenshotIcon from '../icons/FullScreenshot';
|
||||
import ScreenshotIcon from '../icons/Screenshot';
|
||||
import DeviceRotateIcon from '../icons/DeviceRotate';
|
||||
|
@ -30,8 +28,10 @@ import {
|
|||
OPEN_CONSOLE_FOR_DEVICE,
|
||||
PROXY_AUTH_ERROR,
|
||||
APPLY_CSS,
|
||||
TOGGLE_DEVICE_DESIGN_MODE_STATE,
|
||||
} from '../../constants/pubsubEvents';
|
||||
import {CAPABILITIES} from '../../constants/devices';
|
||||
import {DESIGN_MODE_JS_VALUES} from '../../constants/values';
|
||||
|
||||
import styles from './style.module.css';
|
||||
import {styles as commonStyles} from '../useCommonStyles';
|
||||
|
@ -45,9 +45,11 @@ import Maximize from '../icons/Maximize';
|
|||
import Minimize from '../icons/Minimize';
|
||||
import Focus from '../icons/Focus';
|
||||
import Unfocus from '../icons/Unfocus';
|
||||
import DesignModeIcon from '../icons/DesignMode';
|
||||
import {captureOnSentry} from '../../utils/logUtils';
|
||||
import {getBrowserSyncEmbedScriptURL} from '../../services/browserSync';
|
||||
import Spinner from '../Spinner';
|
||||
import {isSslValidationFailed} from '../../utils/generalUtils';
|
||||
|
||||
const {BrowserWindow} = remote;
|
||||
|
||||
|
@ -141,6 +143,12 @@ class WebView extends Component {
|
|||
this.subscriptions.push(
|
||||
pubsub.subscribe(TOGGLE_DEVICE_MUTED_STATE, this.processToggleMuteEvent)
|
||||
);
|
||||
this.subscriptions.push(
|
||||
pubsub.subscribe(
|
||||
TOGGLE_DEVICE_DESIGN_MODE_STATE,
|
||||
this.changeDesignModeState
|
||||
)
|
||||
);
|
||||
|
||||
this.subscriptions.push(
|
||||
pubsub.subscribe(
|
||||
|
@ -201,6 +209,9 @@ class WebView extends Component {
|
|||
id: this.props.device.id,
|
||||
loading: false,
|
||||
});
|
||||
this.changeDesignModeState({
|
||||
designMode: !!this.props.device.designMode,
|
||||
});
|
||||
});
|
||||
this.webviewRef.current.addEventListener(
|
||||
'did-fail-load',
|
||||
|
@ -271,6 +282,12 @@ class WebView extends Component {
|
|||
this._unmuteWebView();
|
||||
}
|
||||
}
|
||||
|
||||
if (prevProps.device.designMode !== this.props.device.designMode) {
|
||||
this.changeDesignModeState({
|
||||
designMode: !!this.props.device.designMode,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getWebContentsId() {
|
||||
|
@ -394,10 +411,14 @@ class WebView extends Component {
|
|||
processScreenshotEvent = async ({
|
||||
now,
|
||||
fullScreen = true,
|
||||
deviceId,
|
||||
}: {
|
||||
now?: Date,
|
||||
fullScreen?: boolean,
|
||||
}) => {
|
||||
if (deviceId && this.props.device.id !== deviceId) {
|
||||
return;
|
||||
}
|
||||
this.setState({screenshotInProgress: true});
|
||||
try {
|
||||
await this.closeBrowserSyncSocket(this.webviewRef.current);
|
||||
|
@ -421,8 +442,9 @@ class WebView extends Component {
|
|||
this.setState({screenshotInProgress: false});
|
||||
};
|
||||
|
||||
processFlipOrientationEvent = () => {
|
||||
if (!this.isMobile) {
|
||||
processFlipOrientationEvent = (message = {}) => {
|
||||
const {deviceId} = message;
|
||||
if (deviceId && this.props.device.id !== deviceId) {
|
||||
return;
|
||||
}
|
||||
this._flipOrientation();
|
||||
|
@ -432,6 +454,16 @@ class WebView extends Component {
|
|||
this.getWebContents().setAudioMuted(muted);
|
||||
};
|
||||
|
||||
changeDesignModeState = ({designMode}) => {
|
||||
this.webviewRef.current
|
||||
.executeJavaScript(
|
||||
`document.designMode = "${
|
||||
designMode ? DESIGN_MODE_JS_VALUES.ON : DESIGN_MODE_JS_VALUES.OFF
|
||||
}";`
|
||||
)
|
||||
.catch(captureOnSentry);
|
||||
};
|
||||
|
||||
processOpenDevToolsInspectorEvent = message => {
|
||||
const {
|
||||
x: webViewX,
|
||||
|
@ -667,6 +699,11 @@ class WebView extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
_toggleDesignMode = () => {
|
||||
const {id: deviceId} = this.props.device;
|
||||
this.props.onToggleDeviceDesignMode(deviceId);
|
||||
};
|
||||
|
||||
_focusDevice = () => {
|
||||
this.props.setPreviewLayout(INDIVIDUAL_LAYOUT);
|
||||
this.props.setFocusedDevice(this.props.device.id);
|
||||
|
@ -935,27 +972,6 @@ class WebView extends Component {
|
|||
<ScreenshotIcon height={18} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip title="Full Page Screenshot">
|
||||
<div
|
||||
className={cx(styles.webViewToolbarIcons, classes.icon)}
|
||||
onClick={this.processScreenshotEvent}
|
||||
>
|
||||
<FullScreenshotIcon height={18} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
{this.isMobile ? (
|
||||
<Tooltip title="Tilt Device">
|
||||
<div
|
||||
className={cx(styles.webViewToolbarIcons, classes.icon, {
|
||||
[classes.iconSelected]: this.state.isTilted,
|
||||
})}
|
||||
onClick={this._flipOrientation}
|
||||
>
|
||||
<DeviceRotateIcon height={17} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
|
||||
<Tooltip title="Disable event mirroring">
|
||||
<div
|
||||
className={cx(styles.webViewToolbarIcons, classes.icon, {
|
||||
|
@ -966,6 +982,20 @@ class WebView extends Component {
|
|||
<UnplugIcon height={30} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={`${
|
||||
this.props.device.designMode ? 'Disable' : 'Enable'
|
||||
} Design Mode`}
|
||||
>
|
||||
<div
|
||||
className={cx(styles.webViewToolbarIcons, classes.icon, {
|
||||
[classes.iconSelected]: this.props.device.designMode,
|
||||
})}
|
||||
onClick={this._toggleDesignMode}
|
||||
>
|
||||
<DesignModeIcon height={20} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className={cx(styles.webViewToolbarRight)}>
|
||||
<Tooltip
|
||||
|
@ -1008,9 +1038,17 @@ class WebView extends Component {
|
|||
>
|
||||
<p>ERROR: {errorCode}</p>
|
||||
<p className={cx(styles.errorDesc)}>{errorDesc}</p>
|
||||
|
||||
{proxyAuthError && (
|
||||
<p className={cx(styles.errorDesc)}>Proxy Authentication Error</p>
|
||||
)}
|
||||
|
||||
{isSslValidationFailed(errorCode) && (
|
||||
<p className={cx(classes.errorHelpSuggestion)}>
|
||||
If you wish to proceed, you can disable the SSL validation in
|
||||
the user preferences.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{this._getWebViewTag(deviceStyles, containerWidth, containerHeight)}
|
||||
</div>
|
||||
|
@ -1061,5 +1099,12 @@ const webViewStyles = theme => ({
|
|||
bottom: 0,
|
||||
},
|
||||
},
|
||||
errorHelpSuggestion: {
|
||||
position: 'absolute',
|
||||
top: '25%',
|
||||
width: '100%',
|
||||
padding: 35,
|
||||
background: theme.palette.primary.main,
|
||||
},
|
||||
});
|
||||
export default withStyles(webViewStyles)(withTheme(WebView));
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
display: none;
|
||||
z-index: 1;
|
||||
text-align: center;
|
||||
color: #f8f8f8;
|
||||
}
|
||||
|
||||
.deviceOverlay.overlayEnabled {
|
||||
|
@ -62,6 +63,7 @@
|
|||
|
||||
.errorDesc {
|
||||
font-size: 20px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.iconWrapperS {
|
||||
|
|
47
desktop-app/app/components/ZenButton/index.js
Normal file
47
desktop-app/app/components/ZenButton/index.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import {useTheme, makeStyles} from '@material-ui/core/styles';
|
||||
import Chevron from '../icons/Chevron';
|
||||
import cx from 'classnames';
|
||||
|
||||
/**
|
||||
* Button with a Chevron in the middle used for toggling zen mode on/off.
|
||||
* @param active Indicates whether zen mode is on or not.
|
||||
* @param onClick Callback function for when the button is clicked.
|
||||
*/
|
||||
const ZenButton = ({active = false, onClick}) => {
|
||||
const classes = useStyles();
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<div className={cx(['zenButton', classes.container])} onClick={onClick}>
|
||||
<Tooltip title="Hide/Show">
|
||||
<div className={cx([classes.icon, {invert: active}])}>
|
||||
<Chevron width={19} height={8} color={theme.palette.lightIcon.main} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
borderRadius: '0 0 8px 8px',
|
||||
display: 'flex',
|
||||
height: '20px',
|
||||
justifyContent: 'center',
|
||||
textAlign: 'center',
|
||||
width: '80px',
|
||||
cursor: 'pointer',
|
||||
boxShadow: '0 5px 5px rgba(0, 0, 0, 0.35)',
|
||||
},
|
||||
icon: {
|
||||
marginTop: '-5px',
|
||||
'&.invert': {
|
||||
transform: 'rotateX(180deg) translateY(-5px)',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export default ZenButton;
|
|
@ -16,6 +16,7 @@ import styles from './styles.module.css';
|
|||
import useCommonStyles from '../useCommonStyles';
|
||||
import './otherStyles.css';
|
||||
import {Tooltip} from '@material-ui/core';
|
||||
import {MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL} from '../../constants';
|
||||
|
||||
function BrowserZoom(props) {
|
||||
const [showExpanded, setShowExpanded] = useState(false);
|
||||
|
@ -51,7 +52,7 @@ function BrowserZoom(props) {
|
|||
}
|
||||
};
|
||||
|
||||
const value = Math.round(props.browser.zoomLevel * 100);
|
||||
const zoomLevel = props.browser.zoomLevel;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -69,7 +70,11 @@ function BrowserZoom(props) {
|
|||
})}
|
||||
>
|
||||
<ToggleButtonGroup value={[]} onChange={_zoomChange}>
|
||||
<ToggleButton value="zoomOut" disabled={value === 20} disableRipple>
|
||||
<ToggleButton
|
||||
value="zoomOut"
|
||||
disabled={zoomLevel === MIN_ZOOM_LEVEL}
|
||||
disableRipple
|
||||
>
|
||||
–
|
||||
</ToggleButton>
|
||||
<Typography
|
||||
|
@ -79,9 +84,13 @@ function BrowserZoom(props) {
|
|||
'MuiToggleButton-root'
|
||||
)}
|
||||
>
|
||||
{value}%
|
||||
{Math.round(props.browser.zoomLevel * 100)}%
|
||||
</Typography>
|
||||
<ToggleButton value="zoomIn" disabled={value === 200} disableRipple>
|
||||
<ToggleButton
|
||||
value="zoomIn"
|
||||
disabled={zoomLevel === MAX_ZOOM_LEVEL}
|
||||
disableRipple
|
||||
>
|
||||
+
|
||||
</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
|
|
22
desktop-app/app/components/icons/Chevron.js
Normal file
22
desktop-app/app/components/icons/Chevron.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
import React from 'react';
|
||||
|
||||
/**
|
||||
* Flattened Chevron icon.
|
||||
*/
|
||||
export default ({width, height, color, padding, margin}) => (
|
||||
<svg
|
||||
height={height}
|
||||
width={width}
|
||||
style={{padding, margin}}
|
||||
viewBox={`0 0 ${width} ${height}`}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M1 6.5L9.5 2L18 6.5"
|
||||
stroke={color}
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
30
desktop-app/app/components/icons/DesignMode.js
Normal file
30
desktop-app/app/components/icons/DesignMode.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import React, {Fragment} from 'react';
|
||||
|
||||
export default ({width, height, color, padding, margin}) => (
|
||||
<Fragment>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
height={height}
|
||||
width={width}
|
||||
fill={color}
|
||||
style={{padding, margin}}
|
||||
className="designModeIcon"
|
||||
viewBox="0 0 36 36"
|
||||
>
|
||||
<path
|
||||
d="M28 30H6V8h13.22l2-2H6a2 2 0 0 0-2 2v22a2 2 0 0 0 2 2h22a2 2 0 0 0 2-2V15l-2 2z"
|
||||
className="clr-i-outline clr-i-outline-path-1"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M33.53 5.84l-3.37-3.37a1.61 1.61 0 0 0-2.28 0L14.17 16.26l-1.11 4.81A1.61 1.61 0 0 0 14.63 23a1.69 1.69 0 0 0 .37 0l4.85-1.07L33.53 8.12a1.61 1.61 0 0 0 0-2.28zM18.81 20.08l-3.66.81l.85-3.63L26.32 6.87l2.82 2.82zM30.27 8.56l-2.82-2.82L29 4.16L31.84 7z"
|
||||
className="clr-i-outline clr-i-outline-path-2"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</Fragment>
|
||||
);
|
|
@ -31,6 +31,9 @@ const lightTheme = {
|
|||
l10: '#d2d2d2',
|
||||
l20: '#8a8a8a',
|
||||
},
|
||||
border: {
|
||||
color: '#000000',
|
||||
},
|
||||
header: {
|
||||
main: '#F5F5F5',
|
||||
},
|
||||
|
@ -72,6 +75,9 @@ const darkTheme = {
|
|||
l10: '#9e9e9e',
|
||||
l20: '#aeaeae',
|
||||
},
|
||||
border: {
|
||||
color: '#ffffff',
|
||||
},
|
||||
header: {
|
||||
main: '#252526',
|
||||
},
|
||||
|
|
|
@ -49,6 +49,7 @@ export type Device = {
|
|||
type: DeviceType,
|
||||
source: Source,
|
||||
isMuted: boolean,
|
||||
designMode: boolean,
|
||||
};
|
||||
|
||||
function getOS(device) {
|
||||
|
|
16
desktop-app/app/constants/index.js
Normal file
16
desktop-app/app/constants/index.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
// @flow
|
||||
|
||||
/**
|
||||
* Default zoom level for the application.
|
||||
*/
|
||||
export const DEFAULT_ZOOM_LEVEL = 0.6;
|
||||
|
||||
/**
|
||||
* Minimum zoom threshold for the application.
|
||||
*/
|
||||
export const MIN_ZOOM_LEVEL = 0.2;
|
||||
|
||||
/**
|
||||
* Maximum zoom threshold for the application.
|
||||
*/
|
||||
export const MAX_ZOOM_LEVEL = 2.0;
|
|
@ -24,3 +24,6 @@ export const HIDE_PERMISSION_POPUP_DUE_TO_RELOAD =
|
|||
'HIDE_PERMISSION_POPUP_DUE_TO_RELOAD';
|
||||
export const PERMISSION_MANAGEMENT_PREFERENCE_CHANGED =
|
||||
'PERMISSION_MANAGEMENT_PREFERENCE_CHANGED';
|
||||
|
||||
export const TOGGLE_DEVICE_DESIGN_MODE_STATE =
|
||||
'TOGGLE_DEVICE_DESIGN_MODE_STATE';
|
||||
|
|
|
@ -2,3 +2,13 @@ export const SCREENSHOT_MECHANISM = {
|
|||
V1: 'V1',
|
||||
V2: 'V2',
|
||||
};
|
||||
|
||||
export const SSL_ERROR_CODES = {
|
||||
FIRST: -200,
|
||||
LAST: -299,
|
||||
};
|
||||
|
||||
export const DESIGN_MODE_JS_VALUES = {
|
||||
ON: 'on',
|
||||
OFF: 'off',
|
||||
};
|
||||
|
|
|
@ -3,18 +3,20 @@ import React, {Fragment} from 'react';
|
|||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Header from '../../components/Header';
|
||||
import DevicePreviewerContainer from '../DevicePreviewerContainer';
|
||||
import DrawerContainer from '../DrawerContainer';
|
||||
import * as BrowserActions from '../../actions/browser';
|
||||
import {DEVTOOLS_MODES} from '../../constants/previewerLayouts';
|
||||
import LeftIconsPaneContainer from '../LeftIconsPaneContainer';
|
||||
|
||||
type Props = {};
|
||||
import HeaderContainer from '../HeaderContainer';
|
||||
import os from 'os';
|
||||
import HorizontalSpacer from '../../components/HorizontalSpacer';
|
||||
import AppNotification from '../../components/AppNotification/AppNotification';
|
||||
|
||||
const Browser = ({browser}) => (
|
||||
<Fragment>
|
||||
<Header />
|
||||
{os.platform() === 'darwin' && <HorizontalSpacer />}
|
||||
<HeaderContainer />
|
||||
<div style={{display: 'flex', height: '100%'}}>
|
||||
<LeftIconsPaneContainer />
|
||||
<div
|
||||
|
@ -60,6 +62,7 @@ const Browser = ({browser}) => (
|
|||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<AppNotification />
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
|
|
19
desktop-app/app/containers/HeaderContainer/index.js
Normal file
19
desktop-app/app/containers/HeaderContainer/index.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
// @flow
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
|
||||
import Header from '../../components/Header';
|
||||
import * as BrowserActions from '../../actions/browser';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
isHeaderVisible: state.browser.isHeaderVisible,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return bindActionCreators(BrowserActions, dispatch);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Header);
|
|
@ -1,5 +1,4 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
|
||||
|
@ -9,6 +8,7 @@ import * as BrowserActions from '../../actions/browser';
|
|||
function mapStateToProps(state) {
|
||||
return {
|
||||
drawer: state.browser.drawer,
|
||||
isLeftPaneVisible: state.browser.isLeftPaneVisible,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import React, {Component} from 'react';
|
||||
import {Provider} from 'react-redux';
|
||||
import {ConnectedRouter} from 'connected-react-router';
|
||||
import log from 'electron-log';
|
||||
import {makeStyles} from '@material-ui/core/styles';
|
||||
import {ThemeProvider} from '@material-ui/styles';
|
||||
import {remote} from 'electron';
|
||||
import Routes from '../Routes';
|
||||
import AppContent from '../AppContent';
|
||||
import ErrorBoundary from '../components/ErrorBoundary';
|
||||
import {
|
||||
registerShortcut,
|
||||
|
@ -29,22 +28,19 @@ import {toggleBookmarkUrl} from '../actions/bookmarks';
|
|||
import pubsub from 'pubsub.js';
|
||||
import {PROXY_AUTH_ERROR} from '../constants/pubsubEvents';
|
||||
import useCreateTheme from '../components/useCreateTheme';
|
||||
import {DEFAULT_ZOOM_LEVEL} from '../constants';
|
||||
|
||||
function App({history}) {
|
||||
function App() {
|
||||
const theme = useCreateTheme();
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
{process.env.NODE_ENV !== 'development' ? (
|
||||
<ErrorBoundary>
|
||||
<ConnectedRouter history={history}>
|
||||
<Routes />
|
||||
</ConnectedRouter>
|
||||
<AppContent />
|
||||
</ErrorBoundary>
|
||||
) : (
|
||||
<ConnectedRouter history={history}>
|
||||
<Routes />
|
||||
</ConnectedRouter>
|
||||
<AppContent />
|
||||
)}
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
@ -95,7 +91,7 @@ export default class Root extends Component {
|
|||
registerShortcut(
|
||||
{id: 'ZoomReset', title: 'Zoom Reset', accelerators: ['mod+0']},
|
||||
() => {
|
||||
store.dispatch(onZoomChange(0.6));
|
||||
store.dispatch(onZoomChange(DEFAULT_ZOOM_LEVEL));
|
||||
},
|
||||
true
|
||||
);
|
||||
|
@ -226,10 +222,10 @@ export default class Root extends Component {
|
|||
};
|
||||
|
||||
render() {
|
||||
const {store, history} = this.props;
|
||||
const {store} = this.props;
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<App history={history} />
|
||||
<App />
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,9 +4,10 @@ const {promisify} = require('util');
|
|||
const Jimp = require('jimp');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const UUID = require('uuid/v4');
|
||||
const uuid = require('uuid');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
const UUID = uuid.v4;
|
||||
const tempDir = path.join(os.tmpdir(), UUID());
|
||||
|
||||
registerPromiseWorker(({images, direction, resultFilename}) => {
|
||||
|
|
|
@ -6,7 +6,7 @@ import {remote} from 'electron';
|
|||
import {render} from 'react-dom';
|
||||
import {AppContainer} from 'react-hot-loader';
|
||||
import Root from './containers/Root';
|
||||
import {configureStore, history} from './store/configureStore';
|
||||
import {configureStore} from './store/configureStore';
|
||||
import './app.global.css';
|
||||
import * as Sentry from '@sentry/electron';
|
||||
import appMetadata from './services/db/appMetadata';
|
||||
|
@ -40,7 +40,7 @@ const store = configureStore();
|
|||
|
||||
render(
|
||||
<AppContainer>
|
||||
<Root store={store} history={history} />
|
||||
<Root store={store} />
|
||||
</AppContainer>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
@ -51,7 +51,7 @@ if (module.hot) {
|
|||
const NextRoot = require('./containers/Root').default;
|
||||
render(
|
||||
<AppContainer>
|
||||
<NextRoot store={store} history={history} />
|
||||
<NextRoot store={store} />
|
||||
</AppContainer>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
|
|
@ -63,6 +63,19 @@ migrateDeviceSchema();
|
|||
if (process.env.NODE_ENV !== 'development') {
|
||||
Sentry.init({
|
||||
dsn: 'https://f2cdbc6a88aa4a068a738d4e4cfd3e12@sentry.io/1553155',
|
||||
environment: process.env.NODE_ENV,
|
||||
beforeSend: (event, hint) => {
|
||||
// Suppress address already in use error
|
||||
if (
|
||||
(event?.exception?.values?.[0]?.value || '').indexOf(
|
||||
'listen EADDRINUSE: address already in use'
|
||||
) > -1
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
event.tags = {appVersion: app.getVersion()};
|
||||
return event;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -355,6 +368,7 @@ const createWindow = async () => {
|
|||
} else {
|
||||
mainWindow.show();
|
||||
}
|
||||
mainWindow.maximize();
|
||||
onResize();
|
||||
});
|
||||
|
||||
|
|
|
@ -26,6 +26,10 @@ import {
|
|||
NEW_CSS_EDITOR_STATUS,
|
||||
NEW_CSS_EDITOR_POSITION,
|
||||
NEW_CSS_EDITOR_CONTENT,
|
||||
TOGGLE_ALL_DEVICES_DESIGN_MODE,
|
||||
TOGGLE_DEVICE_DESIGN_MODE,
|
||||
SET_HEADER_VISIBILITY,
|
||||
SET_LEFT_PANE_VISIBILITY,
|
||||
} from '../actions/browser';
|
||||
import {
|
||||
CHANGE_ACTIVE_THROTTLING_PROFILE,
|
||||
|
@ -56,6 +60,8 @@ import {
|
|||
saveLastOpenedAddress,
|
||||
} from '../utils/navigatorUtils';
|
||||
import {updateExistingUrl} from '../services/searchUrlSuggestions';
|
||||
import {normalizeZoomLevel} from '../utils/browserUtils';
|
||||
import {DEFAULT_ZOOM_LEVEL} from '../constants';
|
||||
|
||||
export const FILTER_FIELDS = {
|
||||
OS: 'OS',
|
||||
|
@ -188,6 +194,9 @@ export type BrowserStateType = {
|
|||
windowSize: WindowSizeType,
|
||||
allDevicesMuted: boolean,
|
||||
networkConfiguration: NetworkConfigurationType,
|
||||
allDevicesInDesignMode: boolean,
|
||||
isHeaderVisible: boolean,
|
||||
isLeftPaneVisible: boolean,
|
||||
};
|
||||
|
||||
let _activeDevices = null;
|
||||
|
@ -220,13 +229,14 @@ function _getActiveDevices() {
|
|||
activeDevices.forEach(device => {
|
||||
device.loading = false;
|
||||
device.isMuted = false;
|
||||
device.designMode = false;
|
||||
});
|
||||
}
|
||||
return activeDevices;
|
||||
}
|
||||
|
||||
function _getUserPreferences(): UserPreferenceType {
|
||||
return settings.get(USER_PREFERENCES);
|
||||
return settings.get(USER_PREFERENCES) || {};
|
||||
}
|
||||
|
||||
function _setUserPreferences(userPreferences) {
|
||||
|
@ -306,7 +316,8 @@ export default function browser(
|
|||
? getLastOpenedAddress()
|
||||
: getHomepage(),
|
||||
currentPageMeta: {},
|
||||
zoomLevel: _getUserPreferences().zoomLevel || 0.6,
|
||||
zoomLevel:
|
||||
normalizeZoomLevel(_getUserPreferences().zoomLevel) || DEFAULT_ZOOM_LEVEL,
|
||||
theme: _getUserPreferences().theme,
|
||||
previousZoomLevel: null,
|
||||
scrollPosition: {x: 0, y: 0},
|
||||
|
@ -341,6 +352,9 @@ export default function browser(
|
|||
windowSize: getWindowSize(),
|
||||
allDevicesMuted: false,
|
||||
networkConfiguration: _getNetworkConfiguration(),
|
||||
allDevicesInDesignMode: false,
|
||||
isHeaderVisible: true,
|
||||
isLeftPaneVisible: true,
|
||||
},
|
||||
action: Action
|
||||
) {
|
||||
|
@ -538,6 +552,42 @@ export default function browser(
|
|||
proxy: action.profile,
|
||||
},
|
||||
};
|
||||
case TOGGLE_ALL_DEVICES_DESIGN_MODE:
|
||||
const nextDevices = state.devices;
|
||||
const nextDesginModeForAll = !state.allDevicesInDesignMode;
|
||||
nextDevices.forEach(d => (d.designMode = nextDesginModeForAll));
|
||||
return {
|
||||
...state,
|
||||
allDevicesInDesignMode: nextDesginModeForAll,
|
||||
devices: nextDevices,
|
||||
};
|
||||
case TOGGLE_DEVICE_DESIGN_MODE:
|
||||
const deviceIndex = state.devices.findIndex(
|
||||
x => x.id === action.deviceId
|
||||
);
|
||||
if (deviceIndex === -1) return {...state};
|
||||
const nextDesignModeForDevice = !state.devices[deviceIndex].designMode;
|
||||
state.devices[deviceIndex] = {
|
||||
...state.devices[deviceIndex],
|
||||
designMode: nextDesignModeForDevice,
|
||||
};
|
||||
return {
|
||||
...state,
|
||||
allDevicesInDesignMode: state.devices.every(x => x.designMode),
|
||||
devices: [...state.devices],
|
||||
};
|
||||
case SET_HEADER_VISIBILITY:
|
||||
return {
|
||||
...state,
|
||||
isHeaderVisible: action.isVisible,
|
||||
};
|
||||
|
||||
case SET_LEFT_PANE_VISIBILITY:
|
||||
return {
|
||||
...state,
|
||||
isLeftPaneVisible: action.isVisible,
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
// @flow
|
||||
import {combineReducers} from 'redux';
|
||||
import {connectRouter} from 'connected-react-router';
|
||||
import browser from './browser';
|
||||
import bookmarks from './bookmarks';
|
||||
import statusBar from './statusBar';
|
||||
|
||||
export default function createRootReducer(history: History) {
|
||||
export default function createRootReducer() {
|
||||
return combineReducers({
|
||||
router: connectRouter(history),
|
||||
browser,
|
||||
bookmarks,
|
||||
statusBar,
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
import {createStore, applyMiddleware, compose} from 'redux';
|
||||
import thunk from 'redux-thunk';
|
||||
import {createHashHistory} from 'history';
|
||||
import {routerMiddleware, routerActions} from 'connected-react-router';
|
||||
import {createLogger} from 'redux-logger';
|
||||
import createRootReducer from '../reducers';
|
||||
|
||||
const history = createHashHistory();
|
||||
|
||||
const rootReducer = createRootReducer(history);
|
||||
const rootReducer = createRootReducer();
|
||||
|
||||
const configureStore = initialState => {
|
||||
// Redux Configuration
|
||||
|
@ -28,14 +24,9 @@ const configureStore = initialState => {
|
|||
middleware.push(logger);
|
||||
}
|
||||
|
||||
// Router Middleware
|
||||
const router = routerMiddleware(history);
|
||||
middleware.push(router);
|
||||
|
||||
// Redux DevTools Configuration
|
||||
const actionCreators = {
|
||||
...routerActions,
|
||||
};
|
||||
const actionCreators = {};
|
||||
|
||||
// If Redux DevTools Extension is installed use it, otherwise use Redux compose
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
|
||||
|
@ -64,4 +55,4 @@ const configureStore = initialState => {
|
|||
return store;
|
||||
};
|
||||
|
||||
export default {configureStore, history};
|
||||
export default {configureStore};
|
||||
|
|
|
@ -8,5 +8,3 @@ const selectedConfigureStore =
|
|||
: configureStoreDev;
|
||||
|
||||
export const {configureStore} = selectedConfigureStore;
|
||||
|
||||
export const {history} = selectedConfigureStore;
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
// @flow
|
||||
import {createStore, applyMiddleware} from 'redux';
|
||||
import thunk from 'redux-thunk';
|
||||
import {createHashHistory} from 'history';
|
||||
import {routerMiddleware} from 'connected-react-router';
|
||||
import createRootReducer from '../reducers';
|
||||
|
||||
const history = createHashHistory();
|
||||
const rootReducer = createRootReducer(history);
|
||||
const router = routerMiddleware(history);
|
||||
const rootReducer = createRootReducer();
|
||||
const heap = () => next => action => {
|
||||
window.requestIdleCallback(() => {
|
||||
if (window.heap) {
|
||||
|
@ -19,10 +15,10 @@ const heap = () => next => action => {
|
|||
});
|
||||
return next(action);
|
||||
};
|
||||
const enhancer = applyMiddleware(thunk, router, heap);
|
||||
const enhancer = applyMiddleware(thunk, heap);
|
||||
|
||||
function configureStore(initialState) {
|
||||
return createStore(rootReducer, initialState, enhancer);
|
||||
}
|
||||
|
||||
export default {configureStore, history};
|
||||
export default {configureStore};
|
||||
|
|
|
@ -11,7 +11,7 @@ const useStyles = makeStyles(theme => ({
|
|||
height: '40vh',
|
||||
marginBottom: '10px',
|
||||
marginTop: '10px',
|
||||
border: '1px white solid',
|
||||
border: `1px solid ${theme.palette.border.color}`,
|
||||
padding: '0 10px',
|
||||
borderRadius: '4px',
|
||||
},
|
||||
|
|
19
desktop-app/app/utils/browserUtils.js
Normal file
19
desktop-app/app/utils/browserUtils.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
// @flow
|
||||
|
||||
import {MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL} from '../constants';
|
||||
|
||||
/**
|
||||
* Ensures that the given zoom level stays between MIN_ZOOM_LEVEL and MAX_ZOOM_LEVEL and returns it.
|
||||
* @param zoomLevel The zoom level to be normalized.
|
||||
*/
|
||||
export function normalizeZoomLevel(zoomLevel: number): number {
|
||||
if (zoomLevel < MIN_ZOOM_LEVEL) {
|
||||
return MIN_ZOOM_LEVEL;
|
||||
}
|
||||
|
||||
if (zoomLevel > MAX_ZOOM_LEVEL) {
|
||||
return MAX_ZOOM_LEVEL;
|
||||
}
|
||||
|
||||
return zoomLevel;
|
||||
}
|
18
desktop-app/app/utils/deviceManagerUtils.js
Normal file
18
desktop-app/app/utils/deviceManagerUtils.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import os from 'os';
|
||||
|
||||
export const MIN_NUMBER_OF_DEVICES = 2;
|
||||
|
||||
export function getRecommendedMaxNumberOfDevices() {
|
||||
const logicalCpuInfos = os.cpus();
|
||||
const cpuSpeed = logicalCpuInfos[0].speed;
|
||||
const cpuCount = logicalCpuInfos.length;
|
||||
|
||||
const value = Math.max(
|
||||
MIN_NUMBER_OF_DEVICES,
|
||||
Math.trunc(cpuCount * (cpuSpeed / 2000))
|
||||
);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export const recommendedMaxNumberOfDevices = getRecommendedMaxNumberOfDevices();
|
|
@ -2,6 +2,7 @@ import {app} from 'electron';
|
|||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import {SSL_ERROR_CODES} from '../constants/values';
|
||||
|
||||
export const getPackageJson = () => {
|
||||
let appPath;
|
||||
|
@ -36,3 +37,9 @@ export const getEnvironmentInfo = () => {
|
|||
osInfo,
|
||||
};
|
||||
};
|
||||
|
||||
export function isSslValidationFailed(errorCode) {
|
||||
return (
|
||||
errorCode <= SSL_ERROR_CODES.FIRST && errorCode >= SSL_ERROR_CODES.LAST
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "Responsively-App",
|
||||
"productName": "ResponsivelyApp",
|
||||
"version": "0.13.0",
|
||||
"version": "0.14.1",
|
||||
"description": "A developer-friendly browser for developing responsive web apps",
|
||||
"scripts": {
|
||||
"build": "concurrently \"yarn build-main\" \"yarn build-renderer\"",
|
||||
|
@ -225,12 +225,11 @@
|
|||
"babel-plugin-transform-react-remove-prop-types": "^0.4.20",
|
||||
"chalk": "^2.4.1",
|
||||
"concurrently": "^5.2.0",
|
||||
"connected-react-router": "^6.5.2",
|
||||
"cross-env": "^5.2.0",
|
||||
"cross-spawn": "^6.0.5",
|
||||
"css-loader": "^1.0.1",
|
||||
"detect-port": "^1.3.0",
|
||||
"electron": "^9.1.1",
|
||||
"electron": "^9.3.1",
|
||||
"electron-builder": "^22.8.0",
|
||||
"electron-devtools-installer": "^3.1.1",
|
||||
"enzyme": "^3.7.0",
|
||||
|
@ -306,7 +305,6 @@
|
|||
"electron-updater": "^4.3.1",
|
||||
"electron-util": "^0.14.2",
|
||||
"framer-motion": "^2.2.0",
|
||||
"history": "^4.7.2",
|
||||
"jimp": "^0.12.1",
|
||||
"lodash": "^4.17.19",
|
||||
"merge-img": "^2.1.3",
|
||||
|
@ -324,8 +322,6 @@
|
|||
"react-redux": "^7.1.0",
|
||||
"react-resizable": "^1.10.1",
|
||||
"react-rnd": "^10.2.2",
|
||||
"react-router": "^5.0.1",
|
||||
"react-router-dom": "^5.0.1",
|
||||
"react-select": "^3.1.0",
|
||||
"react-switch": "^5.0.1",
|
||||
"react-tabs": "^3.0.0",
|
||||
|
|
|
@ -66,7 +66,7 @@ Check it out our GitHub repo - [![GitHub stars](https://img.shields.io/github/st
|
|||
|
||||
Follow on Twitter for future updates - [![Twitter Follow](https://img.shields.io/twitter/follow/ResponsivelyApp?style=social)](https://twitter.com/ResponsivelyApp)
|
||||
|
||||
Sponsor this project on [Open Collective](opencollective.com/responsively)
|
||||
Sponsor this project on [Open Collective](https://opencollective.com/responsively)
|
||||
|
||||
Come say hi to us on [Slack](https://join.slack.com/t/responsively/shared_invite/zt-haoieftz-IsMw64H6jXC23pJ16ROLzw)!
|
||||
</description>
|
||||
|
|
|
@ -3,26 +3,10 @@ const {version, build, productName} = require('../package.json');
|
|||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const RELATIVE_FOLDER_PATH = '../release';
|
||||
|
||||
const getZipFile = () => {
|
||||
const product = (build || {}).productName || productName;
|
||||
const zipName = `${product}-${version}.zip`;
|
||||
const zipPath = path.resolve(__dirname, RELATIVE_FOLDER_PATH, zipName);
|
||||
|
||||
if (fs.existsSync(zipPath)) {
|
||||
console.log(`\nIncluded '${zipName}' in publish files`);
|
||||
return zipPath;
|
||||
}
|
||||
throw new Error(`Expected zip file '${zipPath}' not found`);
|
||||
};
|
||||
|
||||
const getExtraPublishFiles = () =>
|
||||
generateChecksums().then(files => {
|
||||
const zipFile = getZipFile();
|
||||
const all = [zipFile, ...files];
|
||||
console.log(`\nExtra Files Included:\n${all.join('\n')}`);
|
||||
return all;
|
||||
console.log(`\nExtra Files Included:\n${files.join('\n')}`);
|
||||
return files;
|
||||
});
|
||||
|
||||
exports.default = getExtraPublishFiles;
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const crypto = require('crypto');
|
||||
const pkg = require('../package.json');
|
||||
|
||||
const version = pkg.version;
|
||||
const requiredFiles = [
|
||||
`Responsively-App-${version}.x86_64.rpm`,
|
||||
`ResponsivelyApp-${version}-mac.zip`,
|
||||
`ResponsivelyApp-${version}.AppImage`,
|
||||
`ResponsivelyApp-${version}.dmg`,
|
||||
`ResponsivelyApp ${version}.exe`,
|
||||
`ResponsivelyApp Setup ${version}.exe`,
|
||||
];
|
||||
|
||||
function hashFile(file, algorithm = 'sha512', encoding = 'hex', options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -31,17 +42,16 @@ const SKIP_SUFFIX_LIST = [CHECKSUM_SUFFIX, '.yml', '.yaml', '.txt'];
|
|||
const generateChecksums = async () => {
|
||||
const result = [];
|
||||
const installerPath = path.resolve(__dirname, RELATIVE_FOLDER_PATH);
|
||||
const files = await fs.promises.readdir(installerPath);
|
||||
console.log("\nGenerating checksum files for files in: '%s'", installerPath);
|
||||
|
||||
for (const file of files) {
|
||||
for (const file of requiredFiles) {
|
||||
if (SKIP_SUFFIX_LIST.some(s => file.endsWith(s))) continue;
|
||||
|
||||
const filePath = path.join(installerPath, file);
|
||||
const stat = await fs.promises.stat(filePath);
|
||||
|
||||
if (stat.isFile()) {
|
||||
const checksumFile = `${file}${CHECKSUM_SUFFIX}`;
|
||||
const checksumFile = `${file.replace(/ /g, '-')}${CHECKSUM_SUFFIX}`;
|
||||
const checksumFilePath = path.join(installerPath, checksumFile);
|
||||
const checksum = await hashFile(filePath);
|
||||
await fs.promises.writeFile(checksumFilePath, checksum);
|
||||
|
|
|
@ -5193,13 +5193,6 @@ connect@3.6.6:
|
|||
parseurl "~1.3.2"
|
||||
utils-merge "1.0.1"
|
||||
|
||||
connected-react-router@^6.5.2:
|
||||
version "6.8.0"
|
||||
resolved "https://registry.yarnpkg.com/connected-react-router/-/connected-react-router-6.8.0.tgz#ddc687b31d498322445d235d660798489fa56cae"
|
||||
integrity sha512-E64/6krdJM3Ag3MMmh2nKPtMbH15s3JQDuaYJvOVXzu6MbHbDyIvuwLOyhQIuP4Om9zqEfZYiVyflROibSsONg==
|
||||
dependencies:
|
||||
prop-types "^15.7.2"
|
||||
|
||||
console-browserify@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
|
||||
|
@ -6358,10 +6351,10 @@ electron-util@^0.14.2:
|
|||
electron-is-dev "^1.1.0"
|
||||
new-github-issue-url "^0.2.1"
|
||||
|
||||
electron@^9.1.1:
|
||||
version "9.1.1"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-9.1.1.tgz#d52c9873be4113287c3eb2b02f85bad6644b100e"
|
||||
integrity sha512-BYvroBLV9x7G4iN33P/IxeZqwjl62/9VuBAF1CoM0m6OeheaiLog1ZMKLlCqVXycJvvrAvLHc454DDEmwnqqhA==
|
||||
electron@^9.3.1:
|
||||
version "9.3.1"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-9.3.1.tgz#e301932c5c0537d8c9a8850d216d3ba454dbf55c"
|
||||
integrity sha512-DScrhqBT4a54KfdF0EoipALpHmdQTn3m7SSCtbpTcEcG+UDUiXad2cOfW6DHeVH7N+CVDKDG12q2PhVJjXkFAA==
|
||||
dependencies:
|
||||
"@electron/get" "^1.0.1"
|
||||
"@types/node" "^12.0.12"
|
||||
|
@ -8372,18 +8365,6 @@ highlight-es@^1.0.0:
|
|||
is-es2016-keyword "^1.0.0"
|
||||
js-tokens "^3.0.0"
|
||||
|
||||
history@^4.7.2, history@^4.9.0:
|
||||
version "4.10.1"
|
||||
resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3"
|
||||
integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.1.2"
|
||||
loose-envify "^1.2.0"
|
||||
resolve-pathname "^3.0.0"
|
||||
tiny-invariant "^1.0.2"
|
||||
tiny-warning "^1.0.0"
|
||||
value-equal "^1.0.1"
|
||||
|
||||
hmac-drbg@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
|
||||
|
@ -8393,7 +8374,7 @@ hmac-drbg@^1.0.0:
|
|||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.1"
|
||||
|
||||
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
|
||||
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
|
@ -10600,7 +10581,7 @@ longest-streak@^2.0.1:
|
|||
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4"
|
||||
integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==
|
||||
|
||||
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
|
||||
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
|
@ -11000,14 +10981,6 @@ min-indent@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
|
||||
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
|
||||
|
||||
mini-create-react-context@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz#df60501c83151db69e28eac0ef08b4002efab040"
|
||||
integrity sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
tiny-warning "^1.0.3"
|
||||
|
||||
mini-css-extract-plugin@^0.4.4:
|
||||
version "0.4.5"
|
||||
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.5.tgz#c99e9e78d54f3fa775633aee5933aeaa4e80719a"
|
||||
|
@ -13157,7 +13130,7 @@ react-input-autosize@^2.2.2:
|
|||
dependencies:
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.6, react-is@^16.9.0:
|
||||
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.6, react-is@^16.9.0:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
@ -13202,35 +13175,6 @@ react-rnd@^10.2.2:
|
|||
react-draggable "4.4.3"
|
||||
tslib "2.0.0"
|
||||
|
||||
react-router-dom@^5.0.1:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662"
|
||||
integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.1.2"
|
||||
history "^4.9.0"
|
||||
loose-envify "^1.3.1"
|
||||
prop-types "^15.6.2"
|
||||
react-router "5.2.0"
|
||||
tiny-invariant "^1.0.2"
|
||||
tiny-warning "^1.0.0"
|
||||
|
||||
react-router@5.2.0, react-router@^5.0.1:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293"
|
||||
integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.1.2"
|
||||
history "^4.9.0"
|
||||
hoist-non-react-statics "^3.1.0"
|
||||
loose-envify "^1.3.1"
|
||||
mini-create-react-context "^0.4.0"
|
||||
path-to-regexp "^1.7.0"
|
||||
prop-types "^15.6.2"
|
||||
react-is "^16.6.0"
|
||||
tiny-invariant "^1.0.2"
|
||||
tiny-warning "^1.0.0"
|
||||
|
||||
react-select@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.1.0.tgz#ab098720b2e9fe275047c993f0d0caf5ded17c27"
|
||||
|
@ -13827,11 +13771,6 @@ resolve-from@^5.0.0:
|
|||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
|
||||
integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
|
||||
|
||||
resolve-pathname@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd"
|
||||
integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==
|
||||
|
||||
resolve-url@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
|
||||
|
@ -15618,12 +15557,12 @@ timsort@^0.3.0:
|
|||
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
|
||||
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
|
||||
|
||||
tiny-invariant@^1.0.2, tiny-invariant@^1.0.4, tiny-invariant@^1.0.6:
|
||||
tiny-invariant@^1.0.4, tiny-invariant@^1.0.6:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"
|
||||
integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==
|
||||
|
||||
tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3:
|
||||
tiny-warning@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
|
||||
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
|
||||
|
@ -16316,11 +16255,6 @@ validator@^13.1.1:
|
|||
resolved "https://registry.yarnpkg.com/validator/-/validator-13.1.1.tgz#f8811368473d2173a9d8611572b58c5783f223bf"
|
||||
integrity sha512-8GfPiwzzRoWTg7OV1zva1KvrSemuMkv07MA9TTl91hfhe+wKrsrgVN4H2QSFd/U/FhiU3iWPYVgvbsOGwhyFWw==
|
||||
|
||||
value-equal@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c"
|
||||
integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==
|
||||
|
||||
vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
|
|
3
website/.gitignore
vendored
3
website/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
dist
|
||||
node_modules
|
||||
.DS_Store
|
|
@ -1,7 +0,0 @@
|
|||
# LICENSE #
|
||||
|
||||
Leap Bootstrap Theme by Medium Rare
|
||||
|
||||
Use of this theme is subject to the license terms set out on the Bootstrap Themes site:
|
||||
|
||||
https://themes.getbootstrap.com/licenses/
|
|
@ -1,30 +0,0 @@
|
|||
# README #
|
||||
|
||||
Leap Bootstrap Theme by Medium Rare
|
||||
|
||||
### Where are the docs? ###
|
||||
|
||||
* Formal documentation is located at http://leap.mediumra.re/documentation/index.html - accessible from the **Documentation** link on most demo pages.
|
||||
* You can find lists of the styled components at pages/components-leap.html and pages/components-bootstrap.html
|
||||
|
||||
### Getting Set Up (optional) ###
|
||||
|
||||
Setup instructions are located in the docs mentioned above.
|
||||
|
||||
The short version:
|
||||
|
||||
* npm install -g gulp-cli
|
||||
* npm install
|
||||
* gulp
|
||||
|
||||
### Getting Support ###
|
||||
|
||||
Medium Rare provides support for bugfixes and guidance on using the theme.
|
||||
|
||||
To access support, find the support link in your Bootstrap Marketplace dashboard.
|
||||
|
||||
### Giving Feedback ###
|
||||
|
||||
We strive to improve our products and we rely on feedback from our customers.
|
||||
|
||||
Please feel free to share any feedback about Leap via twitter @mrareweb or feedback(at)mrare.co.
|
|
@ -1,136 +0,0 @@
|
|||
-
|
||||
files: "clipboard.min.js"
|
||||
from: "node_modules/clipboard/dist"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "jquery.min.js"
|
||||
from: "node_modules/jquery/dist"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "jquery.countdown.min.js"
|
||||
from: "node_modules/jquery-countdown/dist"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "flatpickr.min.js"
|
||||
from: "node_modules/flatpickr/dist"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "flatpickr.min.css"
|
||||
from: "node_modules/flatpickr/dist"
|
||||
to: "scss/custom/components/plugins"
|
||||
-
|
||||
files: "flickity.pkgd.min.js"
|
||||
from: "node_modules/flickity/dist"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "flickity.css"
|
||||
from: "node_modules/flickity/dist"
|
||||
to: "scss/custom/components/plugins"
|
||||
-
|
||||
files: "ion.rangeSlider.min.js"
|
||||
from: "node_modules/ion-rangeslider/js"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "ion.rangeSlider.css"
|
||||
from: "node_modules/ion-rangeslider/css"
|
||||
to: "scss/custom/components/plugins"
|
||||
-
|
||||
files: "isotope.pkgd.min.js"
|
||||
from: "node_modules/isotope-layout/dist"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "jquery.fancybox.min.css"
|
||||
from: "node_modules/@fancyapps/fancybox/dist"
|
||||
to: "scss/custom/components/plugins"
|
||||
-
|
||||
files: "jquery.fancybox.min.js"
|
||||
from: "node_modules/@fancyapps/fancybox/dist"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "popper.min.js"
|
||||
from: "node_modules/popper.js/dist/umd"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "popper.min.js.map"
|
||||
from: "node_modules/popper.js/dist/umd"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "prism.js"
|
||||
from: "node_modules/prismjs"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "prism.css"
|
||||
from: "node_modules/prismjs/themes"
|
||||
to: "scss/custom/components/plugins"
|
||||
-
|
||||
files: "prism-okaidia.css"
|
||||
from: "node_modules/prismjs/themes"
|
||||
to: "scss/custom/components/plugins"
|
||||
-
|
||||
files:
|
||||
- "scrollMonitor.js"
|
||||
- "scrollMonitor.js.map"
|
||||
from: "node_modules/scrollmonitor"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "smooth-scroll.polyfills.min.js"
|
||||
from: "node_modules/smooth-scroll/dist"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files:
|
||||
- "svg-injector.umd.production.js"
|
||||
- "svg-injector.umd.production.js.map"
|
||||
from: "node_modules/@tanem/svg-injector/dist"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files:
|
||||
- "typed.min.js"
|
||||
- "typed.min.js.map"
|
||||
from: "node_modules/typed.js/lib"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "aos.css"
|
||||
from: "node_modules/aos/dist"
|
||||
to: "scss/custom/components/plugins"
|
||||
-
|
||||
files: "aos.js"
|
||||
from: "node_modules/aos/dist"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "twitterFetcher_min.js"
|
||||
from: "node_modules/twitter-fetcher/js"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files:
|
||||
- "jarallax.min.js"
|
||||
- "jarallax-video.min.js"
|
||||
- "jarallax-element.min.js"
|
||||
- "jarallax.min.js.map"
|
||||
- "jarallax-video.min.js.map"
|
||||
- "jarallax-element.min.js.map"
|
||||
from: "node_modules/jarallax/dist"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files: "jarallax.css"
|
||||
from: "node_modules/jarallax/dist"
|
||||
to: "scss/custom/components/plugins"
|
||||
-
|
||||
files: "plyr.css"
|
||||
from: "node_modules/plyr/dist"
|
||||
to: "scss/custom/components/plugins"
|
||||
-
|
||||
files:
|
||||
- "plyr.polyfilled.min.js"
|
||||
- "plyr.polyfilled.min.js.map"
|
||||
from: "node_modules/plyr/dist"
|
||||
to: "pages/assets/js"
|
||||
-
|
||||
files:
|
||||
- "*.woff"
|
||||
- "*.woff2"
|
||||
from: "node_modules/inter-ui/Inter UI (web)"
|
||||
to: "assets/fonts"
|
||||
-
|
||||
files: "jquery.smartWizard.min.js"
|
||||
from: "node_modules/smartwizard/dist/js"
|
||||
to: "pages/assets/js"
|
|
@ -1,45 +0,0 @@
|
|||
<?php
|
||||
// SETTINGS FOR MAILCHIMP SUBSCRIPTION
|
||||
|
||||
// Log in to MailChimp and create an API key under:
|
||||
// [ Account ] -> [ Extras ] -> [ API Keys ]
|
||||
$apiKey = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-us8';
|
||||
|
||||
// Find your list ID by opening the list in MailChimp, then:
|
||||
// [ Settings ] -> [ List name and defaults ]
|
||||
$listId = 'abcdefghij';
|
||||
|
||||
// Form data to use as email field
|
||||
// (The name="..." value from the email field in your HTML form)
|
||||
$emailField = 'email';
|
||||
|
||||
// Fields to be submitted to your MailChimp list along with the email address
|
||||
// In this example, "NAME" is the field in your MailChimp list,
|
||||
// and $_POST["name"] is the form data from the user to fill that field
|
||||
$mergeFields = array(
|
||||
"NAME" => $_POST["name"],
|
||||
);
|
||||
|
||||
// What the user's status will be after submitting.
|
||||
// Options are 'pending', 'subscribed', 'unsubscribed', 'cleaned'
|
||||
// We recommend 'pending' as this will result in the user receiving
|
||||
// an opt-in confirmation email from MailChimp.
|
||||
// For single opt-in use 'subscribed'.
|
||||
$status = 'pending';
|
||||
|
||||
// Text to show user upon successful subscribe operation
|
||||
$successMessage = "Thanks for subscribing, please check your inbox for confirmation.";
|
||||
|
||||
// Text to show when the user is already subscribed to the list
|
||||
$alreadySubscribed = "You are already subscribed to this list.";
|
||||
|
||||
// Text to show when the user is already subscribed to the list
|
||||
$checkConfirmation = "Your subscription is pending, check your inbox for a confirmation link.";
|
||||
|
||||
// Google reCAPTCHA
|
||||
// If your form is configured with a reCAPTCHA widget, this secret key will be used to validate with Google's server.
|
||||
$recaptchaSecretKey = 'insert-your-recaptcha-secret-key-here';
|
||||
$recaptchaErrorMessage = 'There was a problem verifying the Google reCaptcha. Please try again.';
|
||||
|
||||
require('vendor/mediumrare/mailchimp_subscribe.php');
|
||||
?>
|
|
@ -1,75 +0,0 @@
|
|||
<?php
|
||||
|
||||
// error_reporting(-1);
|
||||
// ini_set('display_errors', 'On');
|
||||
|
||||
/*----------------------------------------------------------------------------*\
|
||||
|* Email settings for sending all emails from your website forms. *|
|
||||
\*============================================================================*/
|
||||
|
||||
|
||||
// Set the details of your SMTP server here:
|
||||
// These details will be used to log in to the SMTP server and send an email
|
||||
// to the site admin when a user submits a form.
|
||||
// Optionally, you can send an email to the user to confirm receipt of their form submission.
|
||||
|
||||
// Outgoing Server Settings - replace values on the right of the = sign with your own.
|
||||
// These 3 settings are are required.
|
||||
// We do not recommend using Gmail as a server to send email.
|
||||
// We recommend that you set up an email address on your hosting provider to perform the sending.
|
||||
// (see cPanel -> email accounts). Using an account at your host improves deliverability.
|
||||
|
||||
// These are the Outgoing Server (SMTP) details provided by your email host
|
||||
$outgoingServerAddress = 'server.company.com'; // consult your hosting provider.
|
||||
$outgoingServerPort = '25'; // '587' , '25' - consult your hosting provider
|
||||
$outgoingServerSecurity = 'tls'; // 'ssl' , 'tls' , null - consult your hosting provider.
|
||||
|
||||
// Sending Account Settings - replace these details with an email account held on the SMTP server entered above.
|
||||
// This will also be used as the account to send the confirmation to the user.
|
||||
$sendingAccountUsername = 'insert_your_account_here';
|
||||
$sendingAccountPassword = 'insert_your_password_here';
|
||||
|
||||
// Recipient (To:) Details - Change this to the email details of who will receive all the emails from the website.
|
||||
$recipientEmail = 'recipient@email.com'; // Where to send the admin email.
|
||||
$recipientName = 'Recipient Name'; // Name of admin to receive email from website.
|
||||
|
||||
// Email details - Change these to suit your website needs
|
||||
$emailSubject = 'A message from a form on your website'; // Subject of the email that the admin will see.
|
||||
$websiteName = 'Edit your company website name'; // This is used as the "From name".
|
||||
$adminEmailTemplate = 'email_to_admin.html'; // Name of template (in templates folder) to use for email to admin.
|
||||
|
||||
// Success Message to display in browser
|
||||
$successMessage = 'Thank you, a member of our team will be in touch shortly.';
|
||||
|
||||
// Google reCAPTCHA
|
||||
// If your form is configured with a reCAPTCHA widget, this secret key will be used to validate with Google's server.
|
||||
$recaptchaSecretKey = 'optionally_insert_your_recaptcha_secret_key_here';
|
||||
$recaptchaErrorMessage = 'There was a problem verifying the Google reCaptcha. Please try again.';
|
||||
|
||||
// Send User a Confirmation Email?
|
||||
$sendConfirmationToUser = true; // leave false to disable confirmation, set to true to enable.
|
||||
$userEmailField = "contact-email"; // What part of form data to use as an address to send confirmation email.
|
||||
$userNameField = "contact-name"; // What part of form data to use as the user's name on confirmation email.
|
||||
$confirmationEmailTemplate = "confirmation_to_user.html"; // Name of template (in templates folder) to use for email to user.
|
||||
$confirmationSubject = "Thanks for testing our contact form!"; // The subject of the confirmation email.
|
||||
$confirmationFromName = "A Template by Medium Rare"; // Used in the "from" field of the email.
|
||||
$confirmationReplyTo = "admin@yourcompany.com"; // If the user wants to reply to the confirmation email, where should it go?
|
||||
// The text replacements to use when constructing the confirmation email body
|
||||
// Eg. By default, this will replace [[name]] in the email template with
|
||||
// the 'name' field sent through the form. ucfirst sets the first letter to uppercase.
|
||||
$confirmationReplacements = array(
|
||||
"[[contact-name]]" => ucfirst($_POST["contact-name"]),
|
||||
"[[mRareAddress]]" => 'http://mrare.co',
|
||||
);
|
||||
|
||||
// Save to CSV file to keep a text record of the form entries
|
||||
// This file should be password protected!
|
||||
$saveToCSV = true;
|
||||
$saveToCSVFileName = "csv/csv_forms_email_1.csv";
|
||||
|
||||
/*----------------------------------------------------------------------------*\
|
||||
|* You do not need to edit anything below this line, the rest is automatic. *|
|
||||
\*============================================================================*/
|
||||
include('vendor/mediumrare/smtp_email.php');
|
||||
|
||||
?>
|
|
@ -1,23 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<h1>Thanks for submitting a form on our website.</h1>
|
||||
<P>
|
||||
Dear [[contact-name]],
|
||||
</P>
|
||||
<p>
|
||||
We're glad you took the time to send us a message.
|
||||
</p>
|
||||
<p>
|
||||
Just so you know, this is an automated email sent from our website.
|
||||
</p>
|
||||
<p>
|
||||
We'll be in touch with you soon to respond to your enquiry.
|
||||
</p>
|
||||
<p>
|
||||
Regards, <br />
|
||||
Company Name Here <br />
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<body>
|
||||
<h1>EMAIL NOTICE</h1>
|
||||
|
||||
<p>
|
||||
<ul>
|
||||
<li>
|
||||
Name: [[contact-name]]
|
||||
</li>
|
||||
<li>
|
||||
Email: [[contact-email]]
|
||||
</li>
|
||||
<li>
|
||||
Company: [[contact-company]]
|
||||
</li>
|
||||
<li>
|
||||
Phone: [[contact-phone]]
|
||||
</li>
|
||||
<li>
|
||||
Message: [[contact-message]]
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
<h6>End of email</h6>
|
||||
</body>
|
||||
|
||||
</html>
|
489
website/forms/vendor/drewm/MailChimp.php
vendored
489
website/forms/vendor/drewm/MailChimp.php
vendored
|
@ -1,489 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace DrewM\MailChimp;
|
||||
|
||||
/**
|
||||
* Super-simple, minimum abstraction MailChimp API v3 wrapper
|
||||
* MailChimp API v3: http://developer.mailchimp.com
|
||||
* This wrapper: https://github.com/drewm/mailchimp-api
|
||||
*
|
||||
* @author Drew McLellan <drew.mclellan@gmail.com>
|
||||
* @version 2.5
|
||||
*/
|
||||
class MailChimp
|
||||
{
|
||||
private $api_key;
|
||||
private $api_endpoint = 'https://<dc>.api.mailchimp.com/3.0';
|
||||
|
||||
const TIMEOUT = 10;
|
||||
|
||||
/* SSL Verification
|
||||
Read before disabling:
|
||||
http://snippets.webaware.com.au/howto/stop-turning-off-curlopt_ssl_verifypeer-and-fix-your-php-config/
|
||||
*/
|
||||
public $verify_ssl = true;
|
||||
|
||||
private $request_successful = false;
|
||||
private $last_error = '';
|
||||
private $last_response = array();
|
||||
private $last_request = array();
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
*
|
||||
* @param string $api_key Your MailChimp API key
|
||||
* @param string $api_endpoint Optional custom API endpoint
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($api_key, $api_endpoint = null)
|
||||
{
|
||||
if (!function_exists('curl_init') || !function_exists('curl_setopt')) {
|
||||
throw new \Exception("cURL support is required, but can't be found.");
|
||||
}
|
||||
|
||||
$this->api_key = $api_key;
|
||||
|
||||
if ($api_endpoint === null) {
|
||||
if (strpos($this->api_key, '-') === false) {
|
||||
throw new \Exception("Invalid MailChimp API key supplied.");
|
||||
}
|
||||
list(, $data_center) = explode('-', $this->api_key);
|
||||
$this->api_endpoint = str_replace('<dc>', $data_center, $this->api_endpoint);
|
||||
} else {
|
||||
$this->api_endpoint = $api_endpoint;
|
||||
}
|
||||
|
||||
$this->last_response = array('headers' => null, 'body' => null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of a Batch request. Optionally with the ID of an existing batch.
|
||||
*
|
||||
* @param string $batch_id Optional ID of an existing batch, if you need to check its status for example.
|
||||
*
|
||||
* @return Batch New Batch object.
|
||||
*/
|
||||
public function new_batch($batch_id = null)
|
||||
{
|
||||
return new Batch($this, $batch_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The url to the API endpoint
|
||||
*/
|
||||
public function getApiEndpoint()
|
||||
{
|
||||
return $this->api_endpoint;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert an email address into a 'subscriber hash' for identifying the subscriber in a method URL
|
||||
*
|
||||
* @param string $email The subscriber's email address
|
||||
*
|
||||
* @return string Hashed version of the input
|
||||
*/
|
||||
public function subscriberHash($email)
|
||||
{
|
||||
return md5(strtolower($email));
|
||||
}
|
||||
|
||||
/**
|
||||
* Was the last request successful?
|
||||
*
|
||||
* @return bool True for success, false for failure
|
||||
*/
|
||||
public function success()
|
||||
{
|
||||
return $this->request_successful;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error returned by either the network transport, or by the API.
|
||||
* If something didn't work, this should contain the string describing the problem.
|
||||
*
|
||||
* @return string|false describing the error
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
return $this->last_error ?: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array containing the HTTP headers and the body of the API response.
|
||||
*
|
||||
* @return array Assoc array with keys 'headers' and 'body'
|
||||
*/
|
||||
public function getLastResponse()
|
||||
{
|
||||
return $this->last_response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array containing the HTTP headers and the body of the API request.
|
||||
*
|
||||
* @return array Assoc array
|
||||
*/
|
||||
public function getLastRequest()
|
||||
{
|
||||
return $this->last_request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP DELETE request - for deleting data
|
||||
*
|
||||
* @param string $method URL of the API request method
|
||||
* @param array $args Assoc array of arguments (if any)
|
||||
* @param int $timeout Timeout limit for request in seconds
|
||||
*
|
||||
* @return array|false Assoc array of API response, decoded from JSON
|
||||
*/
|
||||
public function delete($method, $args = array(), $timeout = self::TIMEOUT)
|
||||
{
|
||||
return $this->makeRequest('delete', $method, $args, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP GET request - for retrieving data
|
||||
*
|
||||
* @param string $method URL of the API request method
|
||||
* @param array $args Assoc array of arguments (usually your data)
|
||||
* @param int $timeout Timeout limit for request in seconds
|
||||
*
|
||||
* @return array|false Assoc array of API response, decoded from JSON
|
||||
*/
|
||||
public function get($method, $args = array(), $timeout = self::TIMEOUT)
|
||||
{
|
||||
return $this->makeRequest('get', $method, $args, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP PATCH request - for performing partial updates
|
||||
*
|
||||
* @param string $method URL of the API request method
|
||||
* @param array $args Assoc array of arguments (usually your data)
|
||||
* @param int $timeout Timeout limit for request in seconds
|
||||
*
|
||||
* @return array|false Assoc array of API response, decoded from JSON
|
||||
*/
|
||||
public function patch($method, $args = array(), $timeout = self::TIMEOUT)
|
||||
{
|
||||
return $this->makeRequest('patch', $method, $args, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP POST request - for creating and updating items
|
||||
*
|
||||
* @param string $method URL of the API request method
|
||||
* @param array $args Assoc array of arguments (usually your data)
|
||||
* @param int $timeout Timeout limit for request in seconds
|
||||
*
|
||||
* @return array|false Assoc array of API response, decoded from JSON
|
||||
*/
|
||||
public function post($method, $args = array(), $timeout = self::TIMEOUT)
|
||||
{
|
||||
return $this->makeRequest('post', $method, $args, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP PUT request - for creating new items
|
||||
*
|
||||
* @param string $method URL of the API request method
|
||||
* @param array $args Assoc array of arguments (usually your data)
|
||||
* @param int $timeout Timeout limit for request in seconds
|
||||
*
|
||||
* @return array|false Assoc array of API response, decoded from JSON
|
||||
*/
|
||||
public function put($method, $args = array(), $timeout = self::TIMEOUT)
|
||||
{
|
||||
return $this->makeRequest('put', $method, $args, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the underlying HTTP request. Not very exciting.
|
||||
*
|
||||
* @param string $http_verb The HTTP verb to use: get, post, put, patch, delete
|
||||
* @param string $method The API method to be called
|
||||
* @param array $args Assoc array of parameters to be passed
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return array|false Assoc array of decoded result
|
||||
*/
|
||||
private function makeRequest($http_verb, $method, $args = array(), $timeout = self::TIMEOUT)
|
||||
{
|
||||
$url = $this->api_endpoint . '/' . $method;
|
||||
|
||||
$response = $this->prepareStateForRequest($http_verb, $method, $url, $timeout);
|
||||
|
||||
$httpHeader = array(
|
||||
'Accept: application/vnd.api+json',
|
||||
'Content-Type: application/vnd.api+json',
|
||||
'Authorization: apikey ' . $this->api_key
|
||||
);
|
||||
|
||||
if (isset($args["language"])) {
|
||||
$httpHeader[] = "Accept-Language: " . $args["language"];
|
||||
}
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeader);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'DrewM/MailChimp-API/3.0 (github.com/drewm/mailchimp-api)');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->verify_ssl);
|
||||
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, '');
|
||||
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
|
||||
|
||||
switch ($http_verb) {
|
||||
case 'post':
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
$this->attachRequestPayload($ch, $args);
|
||||
break;
|
||||
|
||||
case 'get':
|
||||
$query = http_build_query($args, '', '&');
|
||||
curl_setopt($ch, CURLOPT_URL, $url . '?' . $query);
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
|
||||
break;
|
||||
|
||||
case 'patch':
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
|
||||
$this->attachRequestPayload($ch, $args);
|
||||
break;
|
||||
|
||||
case 'put':
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
|
||||
$this->attachRequestPayload($ch, $args);
|
||||
break;
|
||||
}
|
||||
|
||||
$responseContent = curl_exec($ch);
|
||||
$response['headers'] = curl_getinfo($ch);
|
||||
$response = $this->setResponseState($response, $responseContent, $ch);
|
||||
$formattedResponse = $this->formatResponse($response);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
$isSuccess = $this->determineSuccess($response, $formattedResponse, $timeout);
|
||||
|
||||
return is_array($formattedResponse) ? $formattedResponse : $isSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $http_verb
|
||||
* @param string $method
|
||||
* @param string $url
|
||||
* @param integer $timeout
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function prepareStateForRequest($http_verb, $method, $url, $timeout)
|
||||
{
|
||||
$this->last_error = '';
|
||||
|
||||
$this->request_successful = false;
|
||||
|
||||
$this->last_response = array(
|
||||
'headers' => null, // array of details from curl_getinfo()
|
||||
'httpHeaders' => null, // array of HTTP headers
|
||||
'body' => null // content of the response
|
||||
);
|
||||
|
||||
$this->last_request = array(
|
||||
'method' => $http_verb,
|
||||
'path' => $method,
|
||||
'url' => $url,
|
||||
'body' => '',
|
||||
'timeout' => $timeout,
|
||||
);
|
||||
|
||||
return $this->last_response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTTP headers as an array of header-name => header-value pairs.
|
||||
*
|
||||
* The "Link" header is parsed into an associative array based on the
|
||||
* rel names it contains. The original value is available under
|
||||
* the "_raw" key.
|
||||
*
|
||||
* @param string $headersAsString
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getHeadersAsArray($headersAsString)
|
||||
{
|
||||
$headers = array();
|
||||
|
||||
foreach (explode("\r\n", $headersAsString) as $i => $line) {
|
||||
if ($i === 0) { // HTTP code
|
||||
continue;
|
||||
}
|
||||
|
||||
$line = trim($line);
|
||||
if (empty($line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list($key, $value) = explode(': ', $line);
|
||||
|
||||
if ($key == 'Link') {
|
||||
$value = array_merge(
|
||||
array('_raw' => $value),
|
||||
$this->getLinkHeaderAsArray($value)
|
||||
);
|
||||
}
|
||||
|
||||
$headers[$key] = $value;
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract all rel => URL pairs from the provided Link header value
|
||||
*
|
||||
* Mailchimp only implements the URI reference and relation type from
|
||||
* RFC 5988, so the value of the header is something like this:
|
||||
*
|
||||
* 'https://us13.api.mailchimp.com/schema/3.0/Lists/Instance.json; rel="describedBy",
|
||||
* <https://us13.admin.mailchimp.com/lists/members/?id=XXXX>; rel="dashboard"'
|
||||
*
|
||||
* @param string $linkHeaderAsString
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getLinkHeaderAsArray($linkHeaderAsString)
|
||||
{
|
||||
$urls = array();
|
||||
|
||||
if (preg_match_all('/<(.*?)>\s*;\s*rel="(.*?)"\s*/', $linkHeaderAsString, $matches)) {
|
||||
foreach ($matches[2] as $i => $relName) {
|
||||
$urls[$relName] = $matches[1][$i];
|
||||
}
|
||||
}
|
||||
|
||||
return $urls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the data and attach it to the request
|
||||
*
|
||||
* @param resource $ch cURL session handle, used by reference
|
||||
* @param array $data Assoc array of data to attach
|
||||
*/
|
||||
private function attachRequestPayload(&$ch, $data)
|
||||
{
|
||||
$encoded = json_encode($data);
|
||||
$this->last_request['body'] = $encoded;
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the response and format any error messages for debugging
|
||||
*
|
||||
* @param array $response The response from the curl request
|
||||
*
|
||||
* @return array|false The JSON decoded into an array
|
||||
*/
|
||||
private function formatResponse($response)
|
||||
{
|
||||
$this->last_response = $response;
|
||||
|
||||
if (!empty($response['body'])) {
|
||||
return json_decode($response['body'], true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do post-request formatting and setting state from the response
|
||||
*
|
||||
* @param array $response The response from the curl request
|
||||
* @param string $responseContent The body of the response from the curl request
|
||||
* @param resource $ch The curl resource
|
||||
*
|
||||
* @return array The modified response
|
||||
*/
|
||||
private function setResponseState($response, $responseContent, $ch)
|
||||
{
|
||||
if ($responseContent === false) {
|
||||
$this->last_error = curl_error($ch);
|
||||
} else {
|
||||
|
||||
$headerSize = $response['headers']['header_size'];
|
||||
|
||||
$response['httpHeaders'] = $this->getHeadersAsArray(substr($responseContent, 0, $headerSize));
|
||||
$response['body'] = substr($responseContent, $headerSize);
|
||||
|
||||
if (isset($response['headers']['request_header'])) {
|
||||
$this->last_request['headers'] = $response['headers']['request_header'];
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the response was successful or a failure. If it failed, store the error.
|
||||
*
|
||||
* @param array $response The response from the curl request
|
||||
* @param array|false $formattedResponse The response body payload from the curl request
|
||||
* @param int $timeout The timeout supplied to the curl request.
|
||||
*
|
||||
* @return bool If the request was successful
|
||||
*/
|
||||
private function determineSuccess($response, $formattedResponse, $timeout)
|
||||
{
|
||||
$status = $this->findHTTPStatus($response, $formattedResponse);
|
||||
|
||||
if ($status >= 200 && $status <= 299) {
|
||||
$this->request_successful = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset($formattedResponse['detail'])) {
|
||||
$this->last_error = sprintf('%d: %s', $formattedResponse['status'], $formattedResponse['detail']);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($timeout > 0 && $response['headers'] && $response['headers']['total_time'] >= $timeout) {
|
||||
$this->last_error = sprintf('Request timed out after %f seconds.', $response['headers']['total_time']);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->last_error = 'Unknown error, call getLastResponse() to find out what happened.';
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the HTTP status code from the headers or API response body
|
||||
*
|
||||
* @param array $response The response from the curl request
|
||||
* @param array|false $formattedResponse The response body payload from the curl request
|
||||
*
|
||||
* @return int HTTP status code
|
||||
*/
|
||||
private function findHTTPStatus($response, $formattedResponse)
|
||||
{
|
||||
if (!empty($response['headers']) && isset($response['headers']['http_code'])) {
|
||||
return (int)$response['headers']['http_code'];
|
||||
}
|
||||
|
||||
if (!empty($response['body']) && isset($formattedResponse['status'])) {
|
||||
return (int)$formattedResponse['status'];
|
||||
}
|
||||
|
||||
return 418;
|
||||
}
|
||||
}
|
0
website/forms/vendor/index.php
vendored
0
website/forms/vendor/index.php
vendored
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
// Get Basic HTML template for sending email with user's input.
|
||||
$pathToTemplate = 'templates/'.$adminEmailTemplate;
|
||||
|
||||
set_error_handler(
|
||||
function ($severity, $message, $file, $line) {
|
||||
$response->status = 'error';
|
||||
$response->message = 'Failed to open admin email template file. Email to admin was not sent. Error message:'.$message;
|
||||
echo(json_encode($response));
|
||||
exit;
|
||||
}
|
||||
);
|
||||
|
||||
try{
|
||||
$adminEmailTemplate = file_get_contents($pathToTemplate);
|
||||
} catch (Exception $err) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$postValues = array_values($_POST);
|
||||
// Take all Post array keys and
|
||||
$postKeys = array_map(function($value) {return '[['.$value.']]';}, array_keys($_POST));
|
||||
|
||||
$htmlContent = str_replace($postKeys, $postValues, $adminEmailTemplate);
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
// Get HTML template to send to User as confirmation.
|
||||
$pathToTemplate = 'templates/'.$confirmationEmailTemplate;
|
||||
|
||||
set_error_handler(
|
||||
function ($severity, $message, $file, $line) {
|
||||
$response->status = 'error';
|
||||
$response->message = 'Failed to open user confirmation email template file. Confirmation was not sent. ';
|
||||
echo(json_encode($response));
|
||||
exit;
|
||||
}
|
||||
);
|
||||
|
||||
try{
|
||||
$confirmationEmailTemplate = file_get_contents($pathToTemplate);
|
||||
} catch (Exception $err) {
|
||||
exit;
|
||||
}
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
|
||||
$confirmationHtmlContent = strtr($confirmationEmailTemplate, $confirmationReplacements);
|
||||
$confirmationTextContent = filter_var($confirmationHtmlContent, FILTER_SANITIZE_STRING);
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
// If the form has been submitted with a captcha, check it - if it fails from Google, exit the script after returning an error message.
|
||||
|
||||
$data = array(
|
||||
'secret' => $recaptchaSecretKey,
|
||||
'response' => $_POST['g-recaptcha-response']
|
||||
);
|
||||
|
||||
$verify = curl_init();
|
||||
curl_setopt($verify, CURLOPT_URL, "https://www.google.com/recaptcha/api/siteverify");
|
||||
curl_setopt($verify, CURLOPT_POST, true);
|
||||
curl_setopt($verify, CURLOPT_POSTFIELDS, http_build_query($data));
|
||||
curl_setopt($verify, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($verify, CURLOPT_RETURNTRANSFER, true);
|
||||
$gResponse = curl_exec($verify);
|
||||
|
||||
$gResponse = json_decode( $gResponse , true );
|
||||
|
||||
if($gResponse['success'] == false)
|
||||
{
|
||||
$response->status = "error";
|
||||
$response->message = $recaptchaErrorMessage;
|
||||
$response->errorDetail = json_encode($gResponse);
|
||||
$response->errorName = 'Google reCAPTCHA verification error';
|
||||
echo(json_encode($response));
|
||||
exit;
|
||||
}else{
|
||||
$response->recaptchaDetail = $gResponse;
|
||||
unset($_POST['g-recaptcha-response']);
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,16 +0,0 @@
|
|||
<?php
|
||||
|
||||
// Basic sanitization to remove tags to safeguard email
|
||||
function util_array_trim(array &$array, $filter = false)
|
||||
{
|
||||
array_walk_recursive($array, function (&$value) use ($filter) {
|
||||
$value = trim($value);
|
||||
if ($filter) {
|
||||
$value = filter_var($value, FILTER_SANITIZE_STRING);
|
||||
}
|
||||
});
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
$_POST = util_array_trim($_POST, true);
|
|
@ -1,16 +0,0 @@
|
|||
<?php
|
||||
|
||||
// Save to CSV file
|
||||
$file = fopen($saveToCSVFileName, 'a');
|
||||
$data = array_values($_POST);
|
||||
$data = array_merge(array( date("Y-m-d H:i:s")), $data);
|
||||
|
||||
fputcsv_eol($file, $data,"\n");
|
||||
fclose($file);
|
||||
|
||||
function fputcsv_eol($fp, $array, $eol) {
|
||||
fputcsv($fp, $array,',', '"');
|
||||
if("\n" != $eol && 0 === fseek($fp, -1, SEEK_CUR)) {
|
||||
fwrite($fp, $eol);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
// Require the Swift Mailer library
|
||||
require_once 'vendor/swiftmailer/swift_required.php';
|
||||
|
||||
$transport = Swift_SmtpTransport::newInstance( $outgoingServerAddress, $outgoingServerPort, $outgoingServerSecurity )
|
||||
->setUsername( $sendingAccountUsername )
|
||||
->setPassword( $sendingAccountPassword );
|
||||
|
||||
$mailer = Swift_Mailer::newInstance($transport);
|
||||
|
||||
$fromArray = array($sendingAccountUsername => $websiteName);
|
||||
$sentMessages = 0;
|
||||
|
||||
$message = Swift_Message::newInstance($emailSubject)
|
||||
->setSender(array($sendingAccountUsername => $websiteName))
|
||||
->setFrom($fromArray)
|
||||
->setReplyTo($_POST[$userEmailField])
|
||||
->setTo(array($recipientEmail => $recipientName))
|
||||
->setBody($textContent, 'text/plain')
|
||||
->addPart($htmlContent, 'text/html');
|
||||
|
||||
// Send the message or catch an error if it occurs.
|
||||
try{
|
||||
$sentMessages = $mailer->send($message);
|
||||
$response->status = "success";
|
||||
} catch(Exception $e){
|
||||
$response->status = "error";
|
||||
$response->message = $e->getMessage();
|
||||
echo(json_encode($response));
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
|
||||
// Require the Swift Mailer library
|
||||
require_once 'vendor/swiftmailer/swift_required.php';
|
||||
|
||||
$mailer = Swift_Mailer::newInstance($transport);
|
||||
|
||||
$fromArray = array($sendingAccountUsername => $confirmationFromName);
|
||||
|
||||
$message = Swift_Message::newInstance($confirmationSubject)
|
||||
->setSender(array($sendingAccountUsername => $confirmationFromName))
|
||||
->setFrom($fromArray)
|
||||
->setReplyTo($confirmationReplyTo)
|
||||
->setTo(array($_POST[$userEmailField] => $_POST[$userNameField]))
|
||||
->setBody($confirmationTextContent, 'text/plain')
|
||||
->addPart($confirmationHtmlContent, 'text/html');
|
||||
|
||||
// Send the message or catch an error if it occurs.
|
||||
try{
|
||||
$sentMessages = $mailer->send($message);
|
||||
$response->status = "success";
|
||||
} catch(Exception $e){
|
||||
$response->status = "error";
|
||||
$response->message = $e->getMessage();
|
||||
echo(json_encode($response));
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -1,15 +0,0 @@
|
|||
<?php
|
||||
|
||||
$textContent = "";
|
||||
// Creating the message text using fields sent through POST
|
||||
foreach ($_POST as $key => $value)
|
||||
{
|
||||
if($key !== 'g-recaptcha-response' && $key !== 'captcha'){// Sets of checkboxes will be shown as comma-separated values as they are passed in as an array.
|
||||
if(is_array($value)){
|
||||
$value = implode(', ' , $value);
|
||||
}
|
||||
$textContent .= ucfirst($key).": ".$value.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
0
website/forms/vendor/mediumrare/index.php
vendored
0
website/forms/vendor/mediumrare/index.php
vendored
|
@ -1,82 +0,0 @@
|
|||
<?php
|
||||
|
||||
//error_reporting(-1);
|
||||
//ini_set('display_errors', 'On');
|
||||
|
||||
// Include the MailChimp API wrapper
|
||||
// https://github.com/drewm/mailchimp-api
|
||||
include('vendor/drewm/MailChimp.php');
|
||||
use \DrewM\MailChimp\MailChimp;
|
||||
$MailChimp = new MailChimp($apiKey);
|
||||
|
||||
// Set up response object to be returned to browser as JSON
|
||||
$response = (object) array('status' => '', 'message' => $successMessage);
|
||||
|
||||
// If the form has been submitted with a captcha, verify it - if it fails from Google,
|
||||
// exit the script after returning an error message.
|
||||
if(isset($_POST['g-recaptcha-response'])){
|
||||
require('include/recaptcha_v2.php');
|
||||
}
|
||||
|
||||
// Make sure there are no blank fields which will cause an error in MailChimp
|
||||
foreach ($mergeFields as $key => $value)
|
||||
{
|
||||
if(empty($value)){
|
||||
$mergeFields[$key] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
// Check if email is subscribed to the list already
|
||||
$subscriber_hash = $MailChimp->subscriberHash($_POST[$emailField]);
|
||||
$result = $MailChimp->get("lists/$listId/members/$subscriber_hash");
|
||||
// Check result of MailChimp operation
|
||||
if ($MailChimp->success()) {
|
||||
// Success message
|
||||
$response->status = "success";
|
||||
if(json_decode($MailChimp->getLastResponse()['body'])->status === 'subscribed'){
|
||||
$response->message = $alreadySubscribed;
|
||||
}
|
||||
if(json_decode($MailChimp->getLastResponse()['body'])->status === 'pending'){
|
||||
$response->message = $checkConfirmation;
|
||||
}
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
} else {
|
||||
// If not found in list, it is 404 and the script should continue else, show the error.
|
||||
if(json_decode($MailChimp->getLastResponse()['body'])->status !== 404){
|
||||
handle_error($MailChimp);
|
||||
}
|
||||
}
|
||||
|
||||
// Submit subscriber data to MailChimp
|
||||
// For parameters doc, refer to: http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/
|
||||
// For wrapper's doc, visit: https://github.com/drewm/mailchimp-api
|
||||
$result = $MailChimp->post("lists/$listId/members", [
|
||||
'email_address' => $_POST[$emailField],
|
||||
'mergeFields' => $mergeFields,
|
||||
'status' => $status,
|
||||
]);
|
||||
|
||||
// Check result of MailChimp operation
|
||||
if ($MailChimp->success()) {
|
||||
// Success message
|
||||
$response->status = "success";
|
||||
$response->message = $successMessage;
|
||||
} else {
|
||||
// Display error
|
||||
handle_error($MailChimp);
|
||||
}
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
|
||||
function handle_error($MailChimp) {
|
||||
$response->status = "error";
|
||||
$response->message = $MailChimp->getLastError();
|
||||
$response->errorDetail = $MailChimp->getLastResponse()['body'];
|
||||
$response->errorName = 'MailChimp subscribe error';
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
?>
|
50
website/forms/vendor/mediumrare/smtp_email.php
vendored
50
website/forms/vendor/mediumrare/smtp_email.php
vendored
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
//error_reporting(-1);
|
||||
//ini_set('display_errors', 'On');
|
||||
|
||||
// Basic sanitization to remove tags from user input
|
||||
require('include/sanitize_post.php');
|
||||
|
||||
// Set default timezone as some servers do not have this set.
|
||||
if(isset($timeZone) && $timeZone != ""){
|
||||
date_default_timezone_set($timeZone);
|
||||
}
|
||||
else{
|
||||
date_default_timezone_set("UTC");
|
||||
}
|
||||
|
||||
// Set up response object to be returned to browser as JSON
|
||||
$response = (object) array('status' => '', 'message' => $successMessage);
|
||||
|
||||
// If the form has been submitted with a captcha, verify it - if it fails from Google,
|
||||
// exit the script after returning an error message.
|
||||
if(isset($_POST['g-recaptcha-response'])){
|
||||
require('include/recaptcha_v2.php');
|
||||
}
|
||||
|
||||
// Load template and make replacements
|
||||
require('include/load_template_admin.php');
|
||||
|
||||
// Assemble the text for the plain-text version of the message.
|
||||
require('include/text_content.php');
|
||||
|
||||
// Send the email via SMTP using Swiftmailer
|
||||
require('include/send_smtp_admin.php');
|
||||
|
||||
if($saveToCSV === true){
|
||||
require('include/save_csv.php');
|
||||
}
|
||||
|
||||
// Send confirmation email to user
|
||||
if($sendConfirmationToUser === true){
|
||||
// Load user confirmation template and makre replacements
|
||||
require('include/load_template_user.php');
|
||||
// Send the email to the user
|
||||
require('include/send_smtp_user.php');
|
||||
}
|
||||
|
||||
echo(json_encode($response));
|
||||
exit;
|
||||
|
||||
?>
|
|
@ -1,80 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* General utility class in Swift Mailer, not to be instantiated.
|
||||
*
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
abstract class Swift
|
||||
{
|
||||
public static $initialized = false;
|
||||
public static $inits = array();
|
||||
|
||||
/** Swift Mailer Version number generated during dist release process */
|
||||
const VERSION = '@SWIFT_VERSION_NUMBER@';
|
||||
|
||||
/**
|
||||
* Registers an initializer callable that will be called the first time
|
||||
* a SwiftMailer class is autoloaded.
|
||||
*
|
||||
* This enables you to tweak the default configuration in a lazy way.
|
||||
*
|
||||
* @param mixed $callable A valid PHP callable that will be called when autoloading the first Swift class
|
||||
*/
|
||||
public static function init($callable)
|
||||
{
|
||||
self::$inits[] = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal autoloader for spl_autoload_register().
|
||||
*
|
||||
* @param string $class
|
||||
*/
|
||||
public static function autoload($class)
|
||||
{
|
||||
// Don't interfere with other autoloaders
|
||||
if (0 !== strpos($class, 'Swift_')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$path = dirname(__FILE__).'/'.str_replace('_', '/', $class).'.php';
|
||||
|
||||
if (!file_exists($path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
require $path;
|
||||
|
||||
if (self::$inits && !self::$initialized) {
|
||||
self::$initialized = true;
|
||||
foreach (self::$inits as $init) {
|
||||
call_user_func($init);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure autoloading using Swift Mailer.
|
||||
*
|
||||
* This is designed to play nicely with other autoloaders.
|
||||
*
|
||||
* @param mixed $callable A valid PHP callable that will be called when autoloading the first Swift class
|
||||
*/
|
||||
public static function registerAutoload($callable = null)
|
||||
{
|
||||
if (null !== $callable) {
|
||||
self::$inits[] = $callable;
|
||||
}
|
||||
spl_autoload_register(array('Swift', 'autoload'));
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Attachment class for attaching files to a {@link Swift_Mime_Message}.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_Attachment extends Swift_Mime_Attachment
|
||||
{
|
||||
/**
|
||||
* Create a new Attachment.
|
||||
*
|
||||
* Details may be optionally provided to the constructor.
|
||||
*
|
||||
* @param string|Swift_OutputByteStream $data
|
||||
* @param string $filename
|
||||
* @param string $contentType
|
||||
*/
|
||||
public function __construct($data = null, $filename = null, $contentType = null)
|
||||
{
|
||||
call_user_func_array(
|
||||
array($this, 'Swift_Mime_Attachment::__construct'),
|
||||
Swift_DependencyContainer::getInstance()
|
||||
->createDependenciesFor('mime.attachment')
|
||||
);
|
||||
|
||||
$this->setBody($data);
|
||||
$this->setFilename($filename);
|
||||
if ($contentType) {
|
||||
$this->setContentType($contentType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Attachment.
|
||||
*
|
||||
* @param string|Swift_OutputByteStream $data
|
||||
* @param string $filename
|
||||
* @param string $contentType
|
||||
*
|
||||
* @return Swift_Mime_Attachment
|
||||
*/
|
||||
public static function newInstance($data = null, $filename = null, $contentType = null)
|
||||
{
|
||||
return new self($data, $filename, $contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Attachment from a filesystem path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $contentType optional
|
||||
*
|
||||
* @return Swift_Mime_Attachment
|
||||
*/
|
||||
public static function fromPath($path, $contentType = null)
|
||||
{
|
||||
return self::newInstance()->setFile(
|
||||
new Swift_ByteStream_FileByteStream($path),
|
||||
$contentType
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides the base functionality for an InputStream supporting filters.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
abstract class Swift_ByteStream_AbstractFilterableInputStream implements Swift_InputByteStream, Swift_Filterable
|
||||
{
|
||||
/**
|
||||
* Write sequence.
|
||||
*/
|
||||
protected $_sequence = 0;
|
||||
|
||||
/**
|
||||
* StreamFilters.
|
||||
*/
|
||||
private $_filters = array();
|
||||
|
||||
/**
|
||||
* A buffer for writing.
|
||||
*/
|
||||
private $_writeBuffer = '';
|
||||
|
||||
/**
|
||||
* Bound streams.
|
||||
*
|
||||
* @var Swift_InputByteStream[]
|
||||
*/
|
||||
private $_mirrors = array();
|
||||
|
||||
/**
|
||||
* Commit the given bytes to the storage medium immediately.
|
||||
*
|
||||
* @param string $bytes
|
||||
*/
|
||||
abstract protected function _commit($bytes);
|
||||
|
||||
/**
|
||||
* Flush any buffers/content with immediate effect.
|
||||
*/
|
||||
abstract protected function _flush();
|
||||
|
||||
/**
|
||||
* Add a StreamFilter to this InputByteStream.
|
||||
*
|
||||
* @param Swift_StreamFilter $filter
|
||||
* @param string $key
|
||||
*/
|
||||
public function addFilter(Swift_StreamFilter $filter, $key)
|
||||
{
|
||||
$this->_filters[$key] = $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an already present StreamFilter based on its $key.
|
||||
*
|
||||
* @param string $key
|
||||
*/
|
||||
public function removeFilter($key)
|
||||
{
|
||||
unset($this->_filters[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes $bytes to the end of the stream.
|
||||
*
|
||||
* @param string $bytes
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @throws Swift_IoException
|
||||
*/
|
||||
public function write($bytes)
|
||||
{
|
||||
$this->_writeBuffer .= $bytes;
|
||||
foreach ($this->_filters as $filter) {
|
||||
if ($filter->shouldBuffer($this->_writeBuffer)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->_doWrite($this->_writeBuffer);
|
||||
|
||||
return ++$this->_sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* For any bytes that are currently buffered inside the stream, force them
|
||||
* off the buffer.
|
||||
*
|
||||
* @throws Swift_IoException
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
$this->_doWrite($this->_writeBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach $is to this stream.
|
||||
*
|
||||
* The stream acts as an observer, receiving all data that is written.
|
||||
* All {@link write()} and {@link flushBuffers()} operations will be mirrored.
|
||||
*
|
||||
* @param Swift_InputByteStream $is
|
||||
*/
|
||||
public function bind(Swift_InputByteStream $is)
|
||||
{
|
||||
$this->_mirrors[] = $is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an already bound stream.
|
||||
*
|
||||
* If $is is not bound, no errors will be raised.
|
||||
* If the stream currently has any buffered data it will be written to $is
|
||||
* before unbinding occurs.
|
||||
*
|
||||
* @param Swift_InputByteStream $is
|
||||
*/
|
||||
public function unbind(Swift_InputByteStream $is)
|
||||
{
|
||||
foreach ($this->_mirrors as $k => $stream) {
|
||||
if ($is === $stream) {
|
||||
if ($this->_writeBuffer !== '') {
|
||||
$stream->write($this->_writeBuffer);
|
||||
}
|
||||
unset($this->_mirrors[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the contents of the stream (empty it) and set the internal pointer
|
||||
* to the beginning.
|
||||
*
|
||||
* @throws Swift_IoException
|
||||
*/
|
||||
public function flushBuffers()
|
||||
{
|
||||
if ($this->_writeBuffer !== '') {
|
||||
$this->_doWrite($this->_writeBuffer);
|
||||
}
|
||||
$this->_flush();
|
||||
|
||||
foreach ($this->_mirrors as $stream) {
|
||||
$stream->flushBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
/** Run $bytes through all filters */
|
||||
private function _filter($bytes)
|
||||
{
|
||||
foreach ($this->_filters as $filter) {
|
||||
$bytes = $filter->filter($bytes);
|
||||
}
|
||||
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
/** Just write the bytes to the stream */
|
||||
private function _doWrite($bytes)
|
||||
{
|
||||
$this->_commit($this->_filter($bytes));
|
||||
|
||||
foreach ($this->_mirrors as $stream) {
|
||||
$stream->write($bytes);
|
||||
}
|
||||
|
||||
$this->_writeBuffer = '';
|
||||
}
|
||||
}
|
|
@ -1,184 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allows reading and writing of bytes to and from an array.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_ByteStream_ArrayByteStream implements Swift_InputByteStream, Swift_OutputByteStream
|
||||
{
|
||||
/**
|
||||
* The internal stack of bytes.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $_array = array();
|
||||
|
||||
/**
|
||||
* The size of the stack
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_arraySize = 0;
|
||||
|
||||
/**
|
||||
* The internal pointer offset.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_offset = 0;
|
||||
|
||||
/**
|
||||
* Bound streams.
|
||||
*
|
||||
* @var Swift_InputByteStream[]
|
||||
*/
|
||||
private $_mirrors = array();
|
||||
|
||||
/**
|
||||
* Create a new ArrayByteStream.
|
||||
*
|
||||
* If $stack is given the stream will be populated with the bytes it contains.
|
||||
*
|
||||
* @param mixed $stack of bytes in string or array form, optional
|
||||
*/
|
||||
public function __construct($stack = null)
|
||||
{
|
||||
if (is_array($stack)) {
|
||||
$this->_array = $stack;
|
||||
$this->_arraySize = count($stack);
|
||||
} elseif (is_string($stack)) {
|
||||
$this->write($stack);
|
||||
} else {
|
||||
$this->_array = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads $length bytes from the stream into a string and moves the pointer
|
||||
* through the stream by $length.
|
||||
*
|
||||
* If less bytes exist than are requested the
|
||||
* remaining bytes are given instead. If no bytes are remaining at all, boolean
|
||||
* false is returned.
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function read($length)
|
||||
{
|
||||
if ($this->_offset == $this->_arraySize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't use array slice
|
||||
$end = $length + $this->_offset;
|
||||
$end = $this->_arraySize<$end
|
||||
?$this->_arraySize
|
||||
:$end;
|
||||
$ret = '';
|
||||
for (; $this->_offset < $end; ++$this->_offset) {
|
||||
$ret .= $this->_array[$this->_offset];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes $bytes to the end of the stream.
|
||||
*
|
||||
* @param string $bytes
|
||||
*/
|
||||
public function write($bytes)
|
||||
{
|
||||
$to_add = str_split($bytes);
|
||||
foreach ($to_add as $value) {
|
||||
$this->_array[] = $value;
|
||||
}
|
||||
$this->_arraySize = count($this->_array);
|
||||
|
||||
foreach ($this->_mirrors as $stream) {
|
||||
$stream->write($bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Not used.
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach $is to this stream.
|
||||
*
|
||||
* The stream acts as an observer, receiving all data that is written.
|
||||
* All {@link write()} and {@link flushBuffers()} operations will be mirrored.
|
||||
*
|
||||
* @param Swift_InputByteStream $is
|
||||
*/
|
||||
public function bind(Swift_InputByteStream $is)
|
||||
{
|
||||
$this->_mirrors[] = $is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an already bound stream.
|
||||
*
|
||||
* If $is is not bound, no errors will be raised.
|
||||
* If the stream currently has any buffered data it will be written to $is
|
||||
* before unbinding occurs.
|
||||
*
|
||||
* @param Swift_InputByteStream $is
|
||||
*/
|
||||
public function unbind(Swift_InputByteStream $is)
|
||||
{
|
||||
foreach ($this->_mirrors as $k => $stream) {
|
||||
if ($is === $stream) {
|
||||
unset($this->_mirrors[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the internal read pointer to $byteOffset in the stream.
|
||||
*
|
||||
* @param int $byteOffset
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setReadPointer($byteOffset)
|
||||
{
|
||||
if ($byteOffset > $this->_arraySize) {
|
||||
$byteOffset = $this->_arraySize;
|
||||
} elseif ($byteOffset < 0) {
|
||||
$byteOffset = 0;
|
||||
}
|
||||
|
||||
$this->_offset = $byteOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the contents of the stream (empty it) and set the internal pointer
|
||||
* to the beginning.
|
||||
*/
|
||||
public function flushBuffers()
|
||||
{
|
||||
$this->_offset = 0;
|
||||
$this->_array = array();
|
||||
$this->_arraySize = 0;
|
||||
|
||||
foreach ($this->_mirrors as $stream) {
|
||||
$stream->flushBuffers();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,229 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allows reading and writing of bytes to and from a file.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream implements Swift_FileStream
|
||||
{
|
||||
/** The internal pointer offset */
|
||||
private $_offset = 0;
|
||||
|
||||
/** The path to the file */
|
||||
private $_path;
|
||||
|
||||
/** The mode this file is opened in for writing */
|
||||
private $_mode;
|
||||
|
||||
/** A lazy-loaded resource handle for reading the file */
|
||||
private $_reader;
|
||||
|
||||
/** A lazy-loaded resource handle for writing the file */
|
||||
private $_writer;
|
||||
|
||||
/** If magic_quotes_runtime is on, this will be true */
|
||||
private $_quotes = false;
|
||||
|
||||
/** If stream is seekable true/false, or null if not known */
|
||||
private $_seekable = null;
|
||||
|
||||
/**
|
||||
* Create a new FileByteStream for $path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param bool $writable if true
|
||||
*/
|
||||
public function __construct($path, $writable = false)
|
||||
{
|
||||
if (empty($path)) {
|
||||
throw new Swift_IoException('The path cannot be empty');
|
||||
}
|
||||
$this->_path = $path;
|
||||
$this->_mode = $writable ? 'w+b' : 'rb';
|
||||
|
||||
if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) {
|
||||
$this->_quotes = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the complete path to the file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
return $this->_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads $length bytes from the stream into a string and moves the pointer
|
||||
* through the stream by $length.
|
||||
*
|
||||
* If less bytes exist than are requested the
|
||||
* remaining bytes are given instead. If no bytes are remaining at all, boolean
|
||||
* false is returned.
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return string|bool
|
||||
*
|
||||
* @throws Swift_IoException
|
||||
*/
|
||||
public function read($length)
|
||||
{
|
||||
$fp = $this->_getReadHandle();
|
||||
if (!feof($fp)) {
|
||||
if ($this->_quotes) {
|
||||
ini_set('magic_quotes_runtime', 0);
|
||||
}
|
||||
$bytes = fread($fp, $length);
|
||||
if ($this->_quotes) {
|
||||
ini_set('magic_quotes_runtime', 1);
|
||||
}
|
||||
$this->_offset = ftell($fp);
|
||||
|
||||
// If we read one byte after reaching the end of the file
|
||||
// feof() will return false and an empty string is returned
|
||||
if ($bytes === '' && feof($fp)) {
|
||||
$this->_resetReadHandle();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
$this->_resetReadHandle();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the internal read pointer to $byteOffset in the stream.
|
||||
*
|
||||
* @param int $byteOffset
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setReadPointer($byteOffset)
|
||||
{
|
||||
if (isset($this->_reader)) {
|
||||
$this->_seekReadStreamToPosition($byteOffset);
|
||||
}
|
||||
$this->_offset = $byteOffset;
|
||||
}
|
||||
|
||||
/** Just write the bytes to the file */
|
||||
protected function _commit($bytes)
|
||||
{
|
||||
fwrite($this->_getWriteHandle(), $bytes);
|
||||
$this->_resetReadHandle();
|
||||
}
|
||||
|
||||
/** Not used */
|
||||
protected function _flush()
|
||||
{
|
||||
}
|
||||
|
||||
/** Get the resource for reading */
|
||||
private function _getReadHandle()
|
||||
{
|
||||
if (!isset($this->_reader)) {
|
||||
if (!$this->_reader = fopen($this->_path, 'rb')) {
|
||||
throw new Swift_IoException(
|
||||
'Unable to open file for reading [' . $this->_path . ']'
|
||||
);
|
||||
}
|
||||
if ($this->_offset <> 0) {
|
||||
$this->_getReadStreamSeekableStatus();
|
||||
$this->_seekReadStreamToPosition($this->_offset);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_reader;
|
||||
}
|
||||
|
||||
/** Get the resource for writing */
|
||||
private function _getWriteHandle()
|
||||
{
|
||||
if (!isset($this->_writer)) {
|
||||
if (!$this->_writer = fopen($this->_path, $this->_mode)) {
|
||||
throw new Swift_IoException(
|
||||
'Unable to open file for writing [' . $this->_path . ']'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_writer;
|
||||
}
|
||||
|
||||
/** Force a reload of the resource for reading */
|
||||
private function _resetReadHandle()
|
||||
{
|
||||
if (isset($this->_reader)) {
|
||||
fclose($this->_reader);
|
||||
$this->_reader = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if ReadOnly Stream is seekable */
|
||||
private function _getReadStreamSeekableStatus()
|
||||
{
|
||||
$metas = stream_get_meta_data($this->_reader);
|
||||
$this->_seekable = $metas['seekable'];
|
||||
}
|
||||
|
||||
/** Streams in a readOnly stream ensuring copy if needed */
|
||||
private function _seekReadStreamToPosition($offset)
|
||||
{
|
||||
if ($this->_seekable===null) {
|
||||
$this->_getReadStreamSeekableStatus();
|
||||
}
|
||||
if ($this->_seekable === false) {
|
||||
$currentPos = ftell($this->_reader);
|
||||
if ($currentPos<$offset) {
|
||||
$toDiscard = $offset-$currentPos;
|
||||
fread($this->_reader, $toDiscard);
|
||||
|
||||
return;
|
||||
}
|
||||
$this->_copyReadStream();
|
||||
}
|
||||
fseek($this->_reader, $offset, SEEK_SET);
|
||||
}
|
||||
|
||||
/** Copy a readOnly Stream to ensure seekability */
|
||||
private function _copyReadStream()
|
||||
{
|
||||
if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b')) {
|
||||
/* We have opened a php:// Stream Should work without problem */
|
||||
} elseif (function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) {
|
||||
/* We have opened a tmpfile */
|
||||
} else {
|
||||
throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available');
|
||||
}
|
||||
$currentPos = ftell($this->_reader);
|
||||
fclose($this->_reader);
|
||||
$source = fopen($this->_path, 'rb');
|
||||
if (!$source) {
|
||||
throw new Swift_IoException('Unable to open file for copying [' . $this->_path . ']');
|
||||
}
|
||||
fseek($tmpFile, 0, SEEK_SET);
|
||||
while (!feof($source)) {
|
||||
fwrite($tmpFile, fread($source, 4096));
|
||||
}
|
||||
fseek($tmpFile, $currentPos, SEEK_SET);
|
||||
fclose($source);
|
||||
$this->_reader = $tmpFile;
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Romain-Geissler
|
||||
*/
|
||||
class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByteStream
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$filePath = tempnam(sys_get_temp_dir(), 'FileByteStream');
|
||||
|
||||
if ($filePath === false) {
|
||||
throw new Swift_IoException('Failed to retrieve temporary file name.');
|
||||
}
|
||||
|
||||
parent::__construct($filePath, true);
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
if (($content = file_get_contents($this->getPath())) === false) {
|
||||
throw new Swift_IoException('Failed to get temporary file content.');
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (file_exists($this->getPath())) {
|
||||
@unlink($this->getPath());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Analyzes characters for a specific character set.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
* @author Xavier De Cock <xdecock@gmail.com>
|
||||
*/
|
||||
interface Swift_CharacterReader
|
||||
{
|
||||
const MAP_TYPE_INVALID = 0x01;
|
||||
const MAP_TYPE_FIXED_LEN = 0x02;
|
||||
const MAP_TYPE_POSITIONS = 0x03;
|
||||
|
||||
/**
|
||||
* Returns the complete character map
|
||||
*
|
||||
* @param string $string
|
||||
* @param int $startOffset
|
||||
* @param array $currentMap
|
||||
* @param mixed $ignoredChars
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars);
|
||||
|
||||
/**
|
||||
* Returns the mapType, see constants.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getMapType();
|
||||
|
||||
/**
|
||||
* Returns an integer which specifies how many more bytes to read.
|
||||
*
|
||||
* A positive integer indicates the number of more bytes to fetch before invoking
|
||||
* this method again.
|
||||
*
|
||||
* A value of zero means this is already a valid character.
|
||||
* A value of -1 means this cannot possibly be a valid character.
|
||||
*
|
||||
* @param integer[] $bytes
|
||||
* @param int $size
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function validateByteSequence($bytes, $size);
|
||||
|
||||
/**
|
||||
* Returns the number of bytes which should be read to start each character.
|
||||
*
|
||||
* For fixed width character sets this should be the number of octets-per-character.
|
||||
* For multibyte character sets this will probably be 1.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getInitialByteSize();
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides fixed-width byte sizes for reading fixed-width character sets.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
* @author Xavier De Cock <xdecock@gmail.com>
|
||||
*/
|
||||
class Swift_CharacterReader_GenericFixedWidthReader implements Swift_CharacterReader
|
||||
{
|
||||
/**
|
||||
* The number of bytes in a single character.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_width;
|
||||
|
||||
/**
|
||||
* Creates a new GenericFixedWidthReader using $width bytes per character.
|
||||
*
|
||||
* @param int $width
|
||||
*/
|
||||
public function __construct($width)
|
||||
{
|
||||
$this->_width = $width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the complete character map.
|
||||
*
|
||||
* @param string $string
|
||||
* @param int $startOffset
|
||||
* @param array $currentMap
|
||||
* @param mixed $ignoredChars
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
|
||||
{
|
||||
$strlen = strlen($string);
|
||||
// % and / are CPU intensive, so, maybe find a better way
|
||||
$ignored = $strlen % $this->_width;
|
||||
$ignoredChars = substr($string, - $ignored);
|
||||
$currentMap = $this->_width;
|
||||
|
||||
return ($strlen - $ignored) / $this->_width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mapType.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getMapType()
|
||||
{
|
||||
return self::MAP_TYPE_FIXED_LEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integer which specifies how many more bytes to read.
|
||||
*
|
||||
* A positive integer indicates the number of more bytes to fetch before invoking
|
||||
* this method again.
|
||||
*
|
||||
* A value of zero means this is already a valid character.
|
||||
* A value of -1 means this cannot possibly be a valid character.
|
||||
*
|
||||
* @param string $bytes
|
||||
* @param int $size
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function validateByteSequence($bytes, $size)
|
||||
{
|
||||
$needed = $this->_width - $size;
|
||||
|
||||
return ($needed > -1) ? $needed : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes which should be read to start each character.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getInitialByteSize()
|
||||
{
|
||||
return $this->_width;
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Analyzes US-ASCII characters.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_CharacterReader_UsAsciiReader implements Swift_CharacterReader
|
||||
{
|
||||
/**
|
||||
* Returns the complete character map.
|
||||
*
|
||||
* @param string $string
|
||||
* @param int $startOffset
|
||||
* @param array $currentMap
|
||||
* @param string $ignoredChars
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
|
||||
{
|
||||
$strlen=strlen($string);
|
||||
$ignoredChars='';
|
||||
for ($i = 0; $i < $strlen; ++$i) {
|
||||
if ($string[$i]>"\x07F") { // Invalid char
|
||||
$currentMap[$i+$startOffset]=$string[$i];
|
||||
}
|
||||
}
|
||||
|
||||
return $strlen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns mapType
|
||||
*
|
||||
* @return int mapType
|
||||
*/
|
||||
public function getMapType()
|
||||
{
|
||||
return self::MAP_TYPE_INVALID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integer which specifies how many more bytes to read.
|
||||
*
|
||||
* A positive integer indicates the number of more bytes to fetch before invoking
|
||||
* this method again.
|
||||
* A value of zero means this is already a valid character.
|
||||
* A value of -1 means this cannot possibly be a valid character.
|
||||
*
|
||||
* @param string $bytes
|
||||
* @param int $size
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function validateByteSequence($bytes, $size)
|
||||
{
|
||||
$byte = reset($bytes);
|
||||
if (1 == count($bytes) && $byte >= 0x00 && $byte <= 0x7F) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes which should be read to start each character.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getInitialByteSize()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Analyzes UTF-8 characters.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
* @author Xavier De Cock <xdecock@gmail.com>
|
||||
*/
|
||||
class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader
|
||||
{
|
||||
/** Pre-computed for optimization */
|
||||
private static $length_map=array(
|
||||
// N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x0N
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1N
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x2N
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3N
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x4N
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5N
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x6N
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7N
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x8N
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9N
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xAN
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBN
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xCN
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDN
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEN
|
||||
4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0 // 0xFN
|
||||
);
|
||||
|
||||
private static $s_length_map=array(
|
||||
"\x00"=>1, "\x01"=>1, "\x02"=>1, "\x03"=>1, "\x04"=>1, "\x05"=>1, "\x06"=>1, "\x07"=>1,
|
||||
"\x08"=>1, "\x09"=>1, "\x0a"=>1, "\x0b"=>1, "\x0c"=>1, "\x0d"=>1, "\x0e"=>1, "\x0f"=>1,
|
||||
"\x10"=>1, "\x11"=>1, "\x12"=>1, "\x13"=>1, "\x14"=>1, "\x15"=>1, "\x16"=>1, "\x17"=>1,
|
||||
"\x18"=>1, "\x19"=>1, "\x1a"=>1, "\x1b"=>1, "\x1c"=>1, "\x1d"=>1, "\x1e"=>1, "\x1f"=>1,
|
||||
"\x20"=>1, "\x21"=>1, "\x22"=>1, "\x23"=>1, "\x24"=>1, "\x25"=>1, "\x26"=>1, "\x27"=>1,
|
||||
"\x28"=>1, "\x29"=>1, "\x2a"=>1, "\x2b"=>1, "\x2c"=>1, "\x2d"=>1, "\x2e"=>1, "\x2f"=>1,
|
||||
"\x30"=>1, "\x31"=>1, "\x32"=>1, "\x33"=>1, "\x34"=>1, "\x35"=>1, "\x36"=>1, "\x37"=>1,
|
||||
"\x38"=>1, "\x39"=>1, "\x3a"=>1, "\x3b"=>1, "\x3c"=>1, "\x3d"=>1, "\x3e"=>1, "\x3f"=>1,
|
||||
"\x40"=>1, "\x41"=>1, "\x42"=>1, "\x43"=>1, "\x44"=>1, "\x45"=>1, "\x46"=>1, "\x47"=>1,
|
||||
"\x48"=>1, "\x49"=>1, "\x4a"=>1, "\x4b"=>1, "\x4c"=>1, "\x4d"=>1, "\x4e"=>1, "\x4f"=>1,
|
||||
"\x50"=>1, "\x51"=>1, "\x52"=>1, "\x53"=>1, "\x54"=>1, "\x55"=>1, "\x56"=>1, "\x57"=>1,
|
||||
"\x58"=>1, "\x59"=>1, "\x5a"=>1, "\x5b"=>1, "\x5c"=>1, "\x5d"=>1, "\x5e"=>1, "\x5f"=>1,
|
||||
"\x60"=>1, "\x61"=>1, "\x62"=>1, "\x63"=>1, "\x64"=>1, "\x65"=>1, "\x66"=>1, "\x67"=>1,
|
||||
"\x68"=>1, "\x69"=>1, "\x6a"=>1, "\x6b"=>1, "\x6c"=>1, "\x6d"=>1, "\x6e"=>1, "\x6f"=>1,
|
||||
"\x70"=>1, "\x71"=>1, "\x72"=>1, "\x73"=>1, "\x74"=>1, "\x75"=>1, "\x76"=>1, "\x77"=>1,
|
||||
"\x78"=>1, "\x79"=>1, "\x7a"=>1, "\x7b"=>1, "\x7c"=>1, "\x7d"=>1, "\x7e"=>1, "\x7f"=>1,
|
||||
"\x80"=>0, "\x81"=>0, "\x82"=>0, "\x83"=>0, "\x84"=>0, "\x85"=>0, "\x86"=>0, "\x87"=>0,
|
||||
"\x88"=>0, "\x89"=>0, "\x8a"=>0, "\x8b"=>0, "\x8c"=>0, "\x8d"=>0, "\x8e"=>0, "\x8f"=>0,
|
||||
"\x90"=>0, "\x91"=>0, "\x92"=>0, "\x93"=>0, "\x94"=>0, "\x95"=>0, "\x96"=>0, "\x97"=>0,
|
||||
"\x98"=>0, "\x99"=>0, "\x9a"=>0, "\x9b"=>0, "\x9c"=>0, "\x9d"=>0, "\x9e"=>0, "\x9f"=>0,
|
||||
"\xa0"=>0, "\xa1"=>0, "\xa2"=>0, "\xa3"=>0, "\xa4"=>0, "\xa5"=>0, "\xa6"=>0, "\xa7"=>0,
|
||||
"\xa8"=>0, "\xa9"=>0, "\xaa"=>0, "\xab"=>0, "\xac"=>0, "\xad"=>0, "\xae"=>0, "\xaf"=>0,
|
||||
"\xb0"=>0, "\xb1"=>0, "\xb2"=>0, "\xb3"=>0, "\xb4"=>0, "\xb5"=>0, "\xb6"=>0, "\xb7"=>0,
|
||||
"\xb8"=>0, "\xb9"=>0, "\xba"=>0, "\xbb"=>0, "\xbc"=>0, "\xbd"=>0, "\xbe"=>0, "\xbf"=>0,
|
||||
"\xc0"=>2, "\xc1"=>2, "\xc2"=>2, "\xc3"=>2, "\xc4"=>2, "\xc5"=>2, "\xc6"=>2, "\xc7"=>2,
|
||||
"\xc8"=>2, "\xc9"=>2, "\xca"=>2, "\xcb"=>2, "\xcc"=>2, "\xcd"=>2, "\xce"=>2, "\xcf"=>2,
|
||||
"\xd0"=>2, "\xd1"=>2, "\xd2"=>2, "\xd3"=>2, "\xd4"=>2, "\xd5"=>2, "\xd6"=>2, "\xd7"=>2,
|
||||
"\xd8"=>2, "\xd9"=>2, "\xda"=>2, "\xdb"=>2, "\xdc"=>2, "\xdd"=>2, "\xde"=>2, "\xdf"=>2,
|
||||
"\xe0"=>3, "\xe1"=>3, "\xe2"=>3, "\xe3"=>3, "\xe4"=>3, "\xe5"=>3, "\xe6"=>3, "\xe7"=>3,
|
||||
"\xe8"=>3, "\xe9"=>3, "\xea"=>3, "\xeb"=>3, "\xec"=>3, "\xed"=>3, "\xee"=>3, "\xef"=>3,
|
||||
"\xf0"=>4, "\xf1"=>4, "\xf2"=>4, "\xf3"=>4, "\xf4"=>4, "\xf5"=>4, "\xf6"=>4, "\xf7"=>4,
|
||||
"\xf8"=>5, "\xf9"=>5, "\xfa"=>5, "\xfb"=>5, "\xfc"=>6, "\xfd"=>6, "\xfe"=>0, "\xff"=>0,
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the complete character map.
|
||||
*
|
||||
* @param string $string
|
||||
* @param int $startOffset
|
||||
* @param array $currentMap
|
||||
* @param mixed $ignoredChars
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
|
||||
{
|
||||
if (!isset($currentMap['i']) || ! isset($currentMap['p'])) {
|
||||
$currentMap['p'] = $currentMap['i'] = array();
|
||||
}
|
||||
|
||||
$strlen=strlen($string);
|
||||
$charPos=count($currentMap['p']);
|
||||
$foundChars=0;
|
||||
$invalid=false;
|
||||
for ($i = 0; $i < $strlen; ++$i) {
|
||||
$char = $string[$i];
|
||||
$size = self::$s_length_map[$char];
|
||||
if ($size == 0) {
|
||||
/* char is invalid, we must wait for a resync */
|
||||
$invalid = true;
|
||||
continue;
|
||||
} else {
|
||||
if ($invalid == true) {
|
||||
/* We mark the chars as invalid and start a new char */
|
||||
$currentMap['p'][$charPos + $foundChars] = $startOffset + $i;
|
||||
$currentMap['i'][$charPos + $foundChars] = true;
|
||||
++$foundChars;
|
||||
$invalid = false;
|
||||
}
|
||||
if (($i + $size) > $strlen) {
|
||||
$ignoredChars = substr($string, $i);
|
||||
break;
|
||||
}
|
||||
for ($j = 1; $j < $size; ++$j) {
|
||||
$char = $string[$i + $j];
|
||||
if ($char > "\x7F" && $char < "\xC0") {
|
||||
// Valid - continue parsing
|
||||
} else {
|
||||
/* char is invalid, we must wait for a resync */
|
||||
$invalid = true;
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
/* Ok we got a complete char here */
|
||||
$currentMap['p'][$charPos + $foundChars] = $startOffset + $i + $size;
|
||||
$i += $j - 1;
|
||||
++$foundChars;
|
||||
}
|
||||
}
|
||||
|
||||
return $foundChars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns mapType.
|
||||
*
|
||||
* @return int mapType
|
||||
*/
|
||||
public function getMapType()
|
||||
{
|
||||
return self::MAP_TYPE_POSITIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integer which specifies how many more bytes to read.
|
||||
*
|
||||
* A positive integer indicates the number of more bytes to fetch before invoking
|
||||
* this method again.
|
||||
* A value of zero means this is already a valid character.
|
||||
* A value of -1 means this cannot possibly be a valid character.
|
||||
*
|
||||
* @param string $bytes
|
||||
* @param int $size
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function validateByteSequence($bytes, $size)
|
||||
{
|
||||
if ($size<1) {
|
||||
return -1;
|
||||
}
|
||||
$needed = self::$length_map[$bytes[0]] - $size;
|
||||
|
||||
return ($needed > -1)
|
||||
? $needed
|
||||
: -1
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes which should be read to start each character.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getInitialByteSize()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A factory for creating CharacterReaders.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
interface Swift_CharacterReaderFactory
|
||||
{
|
||||
/**
|
||||
* Returns a CharacterReader suitable for the charset applied.
|
||||
*
|
||||
* @param string $charset
|
||||
*
|
||||
* @return Swift_CharacterReader
|
||||
*/
|
||||
public function getReaderFor($charset);
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Standard factory for creating CharacterReaders.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_CharacterReaderFactory_SimpleCharacterReaderFactory implements Swift_CharacterReaderFactory
|
||||
{
|
||||
/**
|
||||
* A map of charset patterns to their implementation classes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $_map = array();
|
||||
|
||||
/**
|
||||
* Factories which have already been loaded.
|
||||
*
|
||||
* @var Swift_CharacterReaderFactory[]
|
||||
*/
|
||||
private static $_loaded = array();
|
||||
|
||||
/**
|
||||
* Creates a new CharacterReaderFactory.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->init();
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
$this->init();
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
if (count(self::$_map) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$prefix = 'Swift_CharacterReader_';
|
||||
|
||||
$singleByte = array(
|
||||
'class' => $prefix . 'GenericFixedWidthReader',
|
||||
'constructor' => array(1)
|
||||
);
|
||||
|
||||
$doubleByte = array(
|
||||
'class' => $prefix . 'GenericFixedWidthReader',
|
||||
'constructor' => array(2)
|
||||
);
|
||||
|
||||
$fourBytes = array(
|
||||
'class' => $prefix . 'GenericFixedWidthReader',
|
||||
'constructor' => array(4)
|
||||
);
|
||||
|
||||
// Utf-8
|
||||
self::$_map['utf-?8'] = array(
|
||||
'class' => $prefix . 'Utf8Reader',
|
||||
'constructor' => array()
|
||||
);
|
||||
|
||||
//7-8 bit charsets
|
||||
self::$_map['(us-)?ascii'] = $singleByte;
|
||||
self::$_map['(iso|iec)-?8859-?[0-9]+'] = $singleByte;
|
||||
self::$_map['windows-?125[0-9]'] = $singleByte;
|
||||
self::$_map['cp-?[0-9]+'] = $singleByte;
|
||||
self::$_map['ansi'] = $singleByte;
|
||||
self::$_map['macintosh'] = $singleByte;
|
||||
self::$_map['koi-?7'] = $singleByte;
|
||||
self::$_map['koi-?8-?.+'] = $singleByte;
|
||||
self::$_map['mik'] = $singleByte;
|
||||
self::$_map['(cork|t1)'] = $singleByte;
|
||||
self::$_map['v?iscii'] = $singleByte;
|
||||
|
||||
//16 bits
|
||||
self::$_map['(ucs-?2|utf-?16)'] = $doubleByte;
|
||||
|
||||
//32 bits
|
||||
self::$_map['(ucs-?4|utf-?32)'] = $fourBytes;
|
||||
|
||||
// Fallback
|
||||
self::$_map['.*'] = $singleByte;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CharacterReader suitable for the charset applied.
|
||||
*
|
||||
* @param string $charset
|
||||
*
|
||||
* @return Swift_CharacterReader
|
||||
*/
|
||||
public function getReaderFor($charset)
|
||||
{
|
||||
$charset = trim(strtolower($charset));
|
||||
foreach (self::$_map as $pattern => $spec) {
|
||||
$re = '/^' . $pattern . '$/D';
|
||||
if (preg_match($re, $charset)) {
|
||||
if (!array_key_exists($pattern, self::$_loaded)) {
|
||||
$reflector = new ReflectionClass($spec['class']);
|
||||
if ($reflector->getConstructor()) {
|
||||
$reader = $reflector->newInstanceArgs($spec['constructor']);
|
||||
} else {
|
||||
$reader = $reflector->newInstance();
|
||||
}
|
||||
self::$_loaded[$pattern] = $reader;
|
||||
}
|
||||
|
||||
return self::$_loaded[$pattern];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An abstract means of reading and writing data in terms of characters as opposed
|
||||
* to bytes.
|
||||
*
|
||||
* Classes implementing this interface may use a subsystem which requires less
|
||||
* memory than working with large strings of data.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
interface Swift_CharacterStream
|
||||
{
|
||||
/**
|
||||
* Set the character set used in this CharacterStream.
|
||||
*
|
||||
* @param string $charset
|
||||
*/
|
||||
public function setCharacterSet($charset);
|
||||
|
||||
/**
|
||||
* Set the CharacterReaderFactory for multi charset support.
|
||||
*
|
||||
* @param Swift_CharacterReaderFactory $factory
|
||||
*/
|
||||
public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory);
|
||||
|
||||
/**
|
||||
* Overwrite this character stream using the byte sequence in the byte stream.
|
||||
*
|
||||
* @param Swift_OutputByteStream $os output stream to read from
|
||||
*/
|
||||
public function importByteStream(Swift_OutputByteStream $os);
|
||||
|
||||
/**
|
||||
* Import a string a bytes into this CharacterStream, overwriting any existing
|
||||
* data in the stream.
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function importString($string);
|
||||
|
||||
/**
|
||||
* Read $length characters from the stream and move the internal pointer
|
||||
* $length further into the stream.
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function read($length);
|
||||
|
||||
/**
|
||||
* Read $length characters from the stream and return a 1-dimensional array
|
||||
* containing there octet values.
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public function readBytes($length);
|
||||
|
||||
/**
|
||||
* Write $chars to the end of the stream.
|
||||
*
|
||||
* @param string $chars
|
||||
*/
|
||||
public function write($chars);
|
||||
|
||||
/**
|
||||
* Move the internal pointer to $charOffset in the stream.
|
||||
*
|
||||
* @param int $charOffset
|
||||
*/
|
||||
public function setPointer($charOffset);
|
||||
|
||||
/**
|
||||
* Empty the stream and reset the internal pointer.
|
||||
*/
|
||||
public function flushContents();
|
||||
}
|
|
@ -1,294 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A CharacterStream implementation which stores characters in an internal array.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_CharacterStream_ArrayCharacterStream implements Swift_CharacterStream
|
||||
{
|
||||
/** A map of byte values and their respective characters */
|
||||
private static $_charMap;
|
||||
|
||||
/** A map of characters and their derivative byte values */
|
||||
private static $_byteMap;
|
||||
|
||||
/** The char reader (lazy-loaded) for the current charset */
|
||||
private $_charReader;
|
||||
|
||||
/** A factory for creating CharacterReader instances */
|
||||
private $_charReaderFactory;
|
||||
|
||||
/** The character set this stream is using */
|
||||
private $_charset;
|
||||
|
||||
/** Array of characters */
|
||||
private $_array = array();
|
||||
|
||||
/** Size of the array of character */
|
||||
private $_array_size = array();
|
||||
|
||||
/** The current character offset in the stream */
|
||||
private $_offset = 0;
|
||||
|
||||
/**
|
||||
* Create a new CharacterStream with the given $chars, if set.
|
||||
*
|
||||
* @param Swift_CharacterReaderFactory $factory for loading validators
|
||||
* @param string $charset used in the stream
|
||||
*/
|
||||
public function __construct(Swift_CharacterReaderFactory $factory, $charset)
|
||||
{
|
||||
self::_initializeMaps();
|
||||
$this->setCharacterReaderFactory($factory);
|
||||
$this->setCharacterSet($charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the character set used in this CharacterStream.
|
||||
*
|
||||
* @param string $charset
|
||||
*/
|
||||
public function setCharacterSet($charset)
|
||||
{
|
||||
$this->_charset = $charset;
|
||||
$this->_charReader = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CharacterReaderFactory for multi charset support.
|
||||
*
|
||||
* @param Swift_CharacterReaderFactory $factory
|
||||
*/
|
||||
public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory)
|
||||
{
|
||||
$this->_charReaderFactory = $factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite this character stream using the byte sequence in the byte stream.
|
||||
*
|
||||
* @param Swift_OutputByteStream $os output stream to read from
|
||||
*/
|
||||
public function importByteStream(Swift_OutputByteStream $os)
|
||||
{
|
||||
if (!isset($this->_charReader)) {
|
||||
$this->_charReader = $this->_charReaderFactory
|
||||
->getReaderFor($this->_charset);
|
||||
}
|
||||
|
||||
$startLength = $this->_charReader->getInitialByteSize();
|
||||
while (false !== $bytes = $os->read($startLength)) {
|
||||
$c = array();
|
||||
for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) {
|
||||
$c[] = self::$_byteMap[$bytes[$i]];
|
||||
}
|
||||
$size = count($c);
|
||||
$need = $this->_charReader
|
||||
->validateByteSequence($c, $size);
|
||||
if ($need > 0 &&
|
||||
false !== $bytes = $os->read($need))
|
||||
{
|
||||
for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) {
|
||||
$c[] = self::$_byteMap[$bytes[$i]];
|
||||
}
|
||||
}
|
||||
$this->_array[] = $c;
|
||||
++$this->_array_size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Import a string a bytes into this CharacterStream, overwriting any existing
|
||||
* data in the stream.
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function importString($string)
|
||||
{
|
||||
$this->flushContents();
|
||||
$this->write($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read $length characters from the stream and move the internal pointer
|
||||
* $length further into the stream.
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function read($length)
|
||||
{
|
||||
if ($this->_offset == $this->_array_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't use array slice
|
||||
$arrays = array();
|
||||
$end = $length + $this->_offset;
|
||||
for ($i = $this->_offset; $i < $end; ++$i) {
|
||||
if (!isset($this->_array[$i])) {
|
||||
break;
|
||||
}
|
||||
$arrays[] = $this->_array[$i];
|
||||
}
|
||||
$this->_offset += $i - $this->_offset; // Limit function calls
|
||||
$chars = false;
|
||||
foreach ($arrays as $array) {
|
||||
$chars .= implode('', array_map('chr', $array));
|
||||
}
|
||||
|
||||
return $chars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read $length characters from the stream and return a 1-dimensional array
|
||||
* containing there octet values.
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return integer[]
|
||||
*/
|
||||
public function readBytes($length)
|
||||
{
|
||||
if ($this->_offset == $this->_array_size) {
|
||||
return false;
|
||||
}
|
||||
$arrays = array();
|
||||
$end = $length + $this->_offset;
|
||||
for ($i = $this->_offset; $i < $end; ++$i) {
|
||||
if (!isset($this->_array[$i])) {
|
||||
break;
|
||||
}
|
||||
$arrays[] = $this->_array[$i];
|
||||
}
|
||||
$this->_offset += ($i - $this->_offset); // Limit function calls
|
||||
|
||||
return call_user_func_array('array_merge', $arrays);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write $chars to the end of the stream.
|
||||
*
|
||||
* @param string $chars
|
||||
*/
|
||||
public function write($chars)
|
||||
{
|
||||
if (!isset($this->_charReader)) {
|
||||
$this->_charReader = $this->_charReaderFactory->getReaderFor(
|
||||
$this->_charset);
|
||||
}
|
||||
|
||||
$startLength = $this->_charReader->getInitialByteSize();
|
||||
|
||||
$fp = fopen('php://memory', 'w+b');
|
||||
fwrite($fp, $chars);
|
||||
unset($chars);
|
||||
fseek($fp, 0, SEEK_SET);
|
||||
|
||||
$buffer = array(0);
|
||||
$buf_pos = 1;
|
||||
$buf_len = 1;
|
||||
$has_datas = true;
|
||||
do {
|
||||
$bytes = array();
|
||||
// Buffer Filing
|
||||
if ($buf_len - $buf_pos < $startLength) {
|
||||
$buf = array_splice($buffer, $buf_pos);
|
||||
$new = $this->_reloadBuffer($fp, 100);
|
||||
if ($new) {
|
||||
$buffer = array_merge($buf, $new);
|
||||
$buf_len = count($buffer);
|
||||
$buf_pos = 0;
|
||||
} else {
|
||||
$has_datas = false;
|
||||
}
|
||||
}
|
||||
if ($buf_len - $buf_pos > 0) {
|
||||
$size = 0;
|
||||
for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i) {
|
||||
++$size;
|
||||
$bytes[] = $buffer[$buf_pos++];
|
||||
}
|
||||
$need = $this->_charReader->validateByteSequence(
|
||||
$bytes, $size);
|
||||
if ($need > 0) {
|
||||
if ($buf_len - $buf_pos < $need) {
|
||||
$new = $this->_reloadBuffer($fp, $need);
|
||||
|
||||
if ($new) {
|
||||
$buffer = array_merge($buffer, $new);
|
||||
$buf_len = count($buffer);
|
||||
}
|
||||
}
|
||||
for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i) {
|
||||
$bytes[] = $buffer[$buf_pos++];
|
||||
}
|
||||
}
|
||||
$this->_array[] = $bytes;
|
||||
++$this->_array_size;
|
||||
}
|
||||
} while ($has_datas);
|
||||
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the internal pointer to $charOffset in the stream.
|
||||
*
|
||||
* @param int $charOffset
|
||||
*/
|
||||
public function setPointer($charOffset)
|
||||
{
|
||||
if ($charOffset > $this->_array_size) {
|
||||
$charOffset = $this->_array_size;
|
||||
} elseif ($charOffset < 0) {
|
||||
$charOffset = 0;
|
||||
}
|
||||
$this->_offset = $charOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty the stream and reset the internal pointer.
|
||||
*/
|
||||
public function flushContents()
|
||||
{
|
||||
$this->_offset = 0;
|
||||
$this->_array = array();
|
||||
$this->_array_size = 0;
|
||||
}
|
||||
|
||||
private function _reloadBuffer($fp, $len)
|
||||
{
|
||||
if (!feof($fp) && ($bytes = fread($fp, $len)) !== false) {
|
||||
$buf = array();
|
||||
for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) {
|
||||
$buf[] = self::$_byteMap[$bytes[$i]];
|
||||
}
|
||||
|
||||
return $buf;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function _initializeMaps()
|
||||
{
|
||||
if (!isset(self::$_charMap)) {
|
||||
self::$_charMap = array();
|
||||
for ($byte = 0; $byte < 256; ++$byte) {
|
||||
self::$_charMap[$byte] = chr($byte);
|
||||
}
|
||||
self::$_byteMap = array_flip(self::$_charMap);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,275 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A CharacterStream implementation which stores characters in an internal array.
|
||||
*
|
||||
* @author Xavier De Cock <xdecock@gmail.com>
|
||||
*/
|
||||
|
||||
class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream
|
||||
{
|
||||
/**
|
||||
* The char reader (lazy-loaded) for the current charset.
|
||||
*
|
||||
* @var Swift_CharacterReader
|
||||
*/
|
||||
private $_charReader;
|
||||
|
||||
/**
|
||||
* A factory for creating CharacterReader instances.
|
||||
*
|
||||
* @var Swift_CharacterReaderFactory
|
||||
*/
|
||||
private $_charReaderFactory;
|
||||
|
||||
/**
|
||||
* The character set this stream is using.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_charset;
|
||||
|
||||
/**
|
||||
* The data's stored as-is.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_datas = '';
|
||||
|
||||
/**
|
||||
* Number of bytes in the stream
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_datasSize = 0;
|
||||
|
||||
/**
|
||||
* Map.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
private $_map;
|
||||
|
||||
/**
|
||||
* Map Type.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_mapType = 0;
|
||||
|
||||
/**
|
||||
* Number of characters in the stream.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_charCount = 0;
|
||||
|
||||
/**
|
||||
* Position in the stream.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_currentPos = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Swift_CharacterReaderFactory $factory
|
||||
* @param string $charset
|
||||
*/
|
||||
public function __construct(Swift_CharacterReaderFactory $factory, $charset)
|
||||
{
|
||||
$this->setCharacterReaderFactory($factory);
|
||||
$this->setCharacterSet($charset);
|
||||
}
|
||||
|
||||
/* -- Changing parameters of the stream -- */
|
||||
|
||||
/**
|
||||
* Set the character set used in this CharacterStream.
|
||||
*
|
||||
* @param string $charset
|
||||
*/
|
||||
public function setCharacterSet($charset)
|
||||
{
|
||||
$this->_charset = $charset;
|
||||
$this->_charReader = null;
|
||||
$this->_mapType = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CharacterReaderFactory for multi charset support.
|
||||
*
|
||||
* @param Swift_CharacterReaderFactory $factory
|
||||
*/
|
||||
public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory)
|
||||
{
|
||||
$this->_charReaderFactory = $factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Swift_CharacterStream::flushContents()
|
||||
*/
|
||||
public function flushContents()
|
||||
{
|
||||
$this->_datas = null;
|
||||
$this->_map = null;
|
||||
$this->_charCount = 0;
|
||||
$this->_currentPos = 0;
|
||||
$this->_datasSize = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Swift_CharacterStream::importByteStream()
|
||||
*
|
||||
* @param Swift_OutputByteStream $os
|
||||
*/
|
||||
public function importByteStream(Swift_OutputByteStream $os)
|
||||
{
|
||||
$this->flushContents();
|
||||
$blocks=512;
|
||||
$os->setReadPointer(0);
|
||||
while(false!==($read = $os->read($blocks)))
|
||||
$this->write($read);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Swift_CharacterStream::importString()
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function importString($string)
|
||||
{
|
||||
$this->flushContents();
|
||||
$this->write($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Swift_CharacterStream::read()
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function read($length)
|
||||
{
|
||||
if ($this->_currentPos>=$this->_charCount) {
|
||||
return false;
|
||||
}
|
||||
$ret=false;
|
||||
$length = ($this->_currentPos+$length > $this->_charCount)
|
||||
? $this->_charCount - $this->_currentPos
|
||||
: $length;
|
||||
switch ($this->_mapType) {
|
||||
case Swift_CharacterReader::MAP_TYPE_FIXED_LEN:
|
||||
$len = $length*$this->_map;
|
||||
$ret = substr($this->_datas,
|
||||
$this->_currentPos * $this->_map,
|
||||
$len);
|
||||
$this->_currentPos += $length;
|
||||
break;
|
||||
|
||||
case Swift_CharacterReader::MAP_TYPE_INVALID:
|
||||
$end = $this->_currentPos + $length;
|
||||
$end = $end > $this->_charCount
|
||||
?$this->_charCount
|
||||
:$end;
|
||||
$ret = '';
|
||||
for (; $this->_currentPos < $length; ++$this->_currentPos) {
|
||||
if (isset ($this->_map[$this->_currentPos])) {
|
||||
$ret .= '?';
|
||||
} else {
|
||||
$ret .= $this->_datas[$this->_currentPos];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Swift_CharacterReader::MAP_TYPE_POSITIONS:
|
||||
$end = $this->_currentPos + $length;
|
||||
$end = $end > $this->_charCount
|
||||
?$this->_charCount
|
||||
:$end;
|
||||
$ret = '';
|
||||
$start = 0;
|
||||
if ($this->_currentPos>0) {
|
||||
$start = $this->_map['p'][$this->_currentPos-1];
|
||||
}
|
||||
$to = $start;
|
||||
for (; $this->_currentPos < $end; ++$this->_currentPos) {
|
||||
if (isset($this->_map['i'][$this->_currentPos])) {
|
||||
$ret .= substr($this->_datas, $start, $to - $start).'?';
|
||||
$start = $this->_map['p'][$this->_currentPos];
|
||||
} else {
|
||||
$to = $this->_map['p'][$this->_currentPos];
|
||||
}
|
||||
}
|
||||
$ret .= substr($this->_datas, $start, $to - $start);
|
||||
break;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Swift_CharacterStream::readBytes()
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @return integer[]
|
||||
*/
|
||||
public function readBytes($length)
|
||||
{
|
||||
$read=$this->read($length);
|
||||
if ($read!==false) {
|
||||
$ret = array_map('ord', str_split($read, 1));
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Swift_CharacterStream::setPointer()
|
||||
*
|
||||
* @param int $charOffset
|
||||
*/
|
||||
public function setPointer($charOffset)
|
||||
{
|
||||
if ($this->_charCount<$charOffset) {
|
||||
$charOffset=$this->_charCount;
|
||||
}
|
||||
$this->_currentPos = $charOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Swift_CharacterStream::write()
|
||||
*
|
||||
* @param string $chars
|
||||
*/
|
||||
public function write($chars)
|
||||
{
|
||||
if (!isset($this->_charReader)) {
|
||||
$this->_charReader = $this->_charReaderFactory->getReaderFor(
|
||||
$this->_charset);
|
||||
$this->_map = array();
|
||||
$this->_mapType = $this->_charReader->getMapType();
|
||||
}
|
||||
$ignored='';
|
||||
$this->_datas .= $chars;
|
||||
$this->_charCount += $this->_charReader->getCharPositions(substr($this->_datas, $this->_datasSize), $this->_datasSize, $this->_map, $ignored);
|
||||
if ($ignored!==false) {
|
||||
$this->_datasSize=strlen($this->_datas)-strlen($ignored);
|
||||
} else {
|
||||
$this->_datasSize=strlen($this->_datas);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2009 Fabien Potencier <fabien.potencier@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base class for Spools (implements time and message limits).
|
||||
*
|
||||
* @author Fabien Potencier
|
||||
*/
|
||||
abstract class Swift_ConfigurableSpool implements Swift_Spool
|
||||
{
|
||||
/** The maximum number of messages to send per flush */
|
||||
private $_message_limit;
|
||||
|
||||
/** The time limit per flush */
|
||||
private $_time_limit;
|
||||
|
||||
/**
|
||||
* Sets the maximum number of messages to send per flush.
|
||||
*
|
||||
* @param int $limit
|
||||
*/
|
||||
public function setMessageLimit($limit)
|
||||
{
|
||||
$this->_message_limit = (int) $limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of messages to send per flush.
|
||||
*
|
||||
* @return int The limit
|
||||
*/
|
||||
public function getMessageLimit()
|
||||
{
|
||||
return $this->_message_limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time limit (in seconds) per flush.
|
||||
*
|
||||
* @param int $limit The limit
|
||||
*/
|
||||
public function setTimeLimit($limit)
|
||||
{
|
||||
$this->_time_limit = (int) $limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time limit (in seconds) per flush.
|
||||
*
|
||||
* @return int The limit
|
||||
*/
|
||||
public function getTimeLimit()
|
||||
{
|
||||
return $this->_time_limit;
|
||||
}
|
||||
}
|
|
@ -1,370 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dependency Injection container.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_DependencyContainer
|
||||
{
|
||||
/** Constant for literal value types */
|
||||
const TYPE_VALUE = 0x0001;
|
||||
|
||||
/** Constant for new instance types */
|
||||
const TYPE_INSTANCE = 0x0010;
|
||||
|
||||
/** Constant for shared instance types */
|
||||
const TYPE_SHARED = 0x0100;
|
||||
|
||||
/** Constant for aliases */
|
||||
const TYPE_ALIAS = 0x1000;
|
||||
|
||||
/** Singleton instance */
|
||||
private static $_instance = null;
|
||||
|
||||
/** The data container */
|
||||
private $_store = array();
|
||||
|
||||
/** The current endpoint in the data container */
|
||||
private $_endPoint;
|
||||
|
||||
/**
|
||||
* Constructor should not be used.
|
||||
*
|
||||
* Use {@link getInstance()} instead.
|
||||
*/
|
||||
public function __construct() { }
|
||||
|
||||
/**
|
||||
* Returns a singleton of the DependencyContainer.
|
||||
*
|
||||
* @return Swift_DependencyContainer
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if (!isset(self::$_instance)) {
|
||||
self::$_instance = new self();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the names of all items stored in the Container.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function listItems()
|
||||
{
|
||||
return array_keys($this->_store);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if an item is registered in this container with the given name.
|
||||
*
|
||||
* @see register()
|
||||
*
|
||||
* @param string $itemName
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has($itemName)
|
||||
{
|
||||
return array_key_exists($itemName, $this->_store)
|
||||
&& isset($this->_store[$itemName]['lookupType']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the item with the given $itemName.
|
||||
*
|
||||
* @see register()
|
||||
*
|
||||
* @param string $itemName
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws Swift_DependencyException If the dependency is not found
|
||||
*/
|
||||
public function lookup($itemName)
|
||||
{
|
||||
if (!$this->has($itemName)) {
|
||||
throw new Swift_DependencyException(
|
||||
'Cannot lookup dependency "' . $itemName . '" since it is not registered.'
|
||||
);
|
||||
}
|
||||
|
||||
switch ($this->_store[$itemName]['lookupType']) {
|
||||
case self::TYPE_ALIAS:
|
||||
return $this->_createAlias($itemName);
|
||||
case self::TYPE_VALUE:
|
||||
return $this->_getValue($itemName);
|
||||
case self::TYPE_INSTANCE:
|
||||
return $this->_createNewInstance($itemName);
|
||||
case self::TYPE_SHARED:
|
||||
return $this->_createSharedInstance($itemName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an array of arguments passed to the constructor of $itemName.
|
||||
*
|
||||
* @param string $itemName
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function createDependenciesFor($itemName)
|
||||
{
|
||||
$args = array();
|
||||
if (isset($this->_store[$itemName]['args'])) {
|
||||
$args = $this->_resolveArgs($this->_store[$itemName]['args']);
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new dependency with $itemName.
|
||||
*
|
||||
* This method returns the current DependencyContainer instance because it
|
||||
* requires the use of the fluid interface to set the specific details for the
|
||||
* dependency.
|
||||
* @see asNewInstanceOf(), asSharedInstanceOf(), asValue()
|
||||
*
|
||||
* @param string $itemName
|
||||
*
|
||||
* @return Swift_DependencyContainer
|
||||
*/
|
||||
public function register($itemName)
|
||||
{
|
||||
$this->_store[$itemName] = array();
|
||||
$this->_endPoint =& $this->_store[$itemName];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the previously registered item as a literal value.
|
||||
*
|
||||
* {@link register()} must be called before this will work.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return Swift_DependencyContainer
|
||||
*/
|
||||
public function asValue($value)
|
||||
{
|
||||
$endPoint =& $this->_getEndPoint();
|
||||
$endPoint['lookupType'] = self::TYPE_VALUE;
|
||||
$endPoint['value'] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the previously registered item as an alias of another item.
|
||||
*
|
||||
* @param string $lookup
|
||||
*
|
||||
* @return Swift_DependencyContainer
|
||||
*/
|
||||
public function asAliasOf($lookup)
|
||||
{
|
||||
$endPoint =& $this->_getEndPoint();
|
||||
$endPoint['lookupType'] = self::TYPE_ALIAS;
|
||||
$endPoint['ref'] = $lookup;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the previously registered item as a new instance of $className.
|
||||
*
|
||||
* {@link register()} must be called before this will work.
|
||||
* Any arguments can be set with {@link withDependencies()},
|
||||
* {@link addConstructorValue()} or {@link addConstructorLookup()}.
|
||||
*
|
||||
* @see withDependencies(), addConstructorValue(), addConstructorLookup()
|
||||
*
|
||||
* @param string $className
|
||||
*
|
||||
* @return Swift_DependencyContainer
|
||||
*/
|
||||
public function asNewInstanceOf($className)
|
||||
{
|
||||
$endPoint =& $this->_getEndPoint();
|
||||
$endPoint['lookupType'] = self::TYPE_INSTANCE;
|
||||
$endPoint['className'] = $className;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the previously registered item as a shared instance of $className.
|
||||
*
|
||||
* {@link register()} must be called before this will work.
|
||||
*
|
||||
* @param string $className
|
||||
*
|
||||
* @return Swift_DependencyContainer
|
||||
*/
|
||||
public function asSharedInstanceOf($className)
|
||||
{
|
||||
$endPoint =& $this->_getEndPoint();
|
||||
$endPoint['lookupType'] = self::TYPE_SHARED;
|
||||
$endPoint['className'] = $className;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a list of injected dependencies for the previously registered item.
|
||||
*
|
||||
* This method takes an array of lookup names.
|
||||
*
|
||||
* @see addConstructorValue(), addConstructorLookup()
|
||||
*
|
||||
* @param array $lookups
|
||||
*
|
||||
* @return Swift_DependencyContainer
|
||||
*/
|
||||
public function withDependencies(array $lookups)
|
||||
{
|
||||
$endPoint =& $this->_getEndPoint();
|
||||
$endPoint['args'] = array();
|
||||
foreach ($lookups as $lookup) {
|
||||
$this->addConstructorLookup($lookup);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a literal (non looked up) value for the constructor of the
|
||||
* previously registered item.
|
||||
*
|
||||
* @see withDependencies(), addConstructorLookup()
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return Swift_DependencyContainer
|
||||
*/
|
||||
public function addConstructorValue($value)
|
||||
{
|
||||
$endPoint =& $this->_getEndPoint();
|
||||
if (!isset($endPoint['args'])) {
|
||||
$endPoint['args'] = array();
|
||||
}
|
||||
$endPoint['args'][] = array('type' => 'value', 'item' => $value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a dependency lookup for the constructor of the previously
|
||||
* registered item.
|
||||
*
|
||||
* @see withDependencies(), addConstructorValue()
|
||||
*
|
||||
* @param string $lookup
|
||||
*
|
||||
* @return Swift_DependencyContainer
|
||||
*/
|
||||
public function addConstructorLookup($lookup)
|
||||
{
|
||||
$endPoint =& $this->_getEndPoint();
|
||||
if (!isset($this->_endPoint['args'])) {
|
||||
$endPoint['args'] = array();
|
||||
}
|
||||
$endPoint['args'][] = array('type' => 'lookup', 'item' => $lookup);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get the literal value with $itemName */
|
||||
private function _getValue($itemName)
|
||||
{
|
||||
return $this->_store[$itemName]['value'];
|
||||
}
|
||||
|
||||
/** Resolve an alias to another item */
|
||||
private function _createAlias($itemName)
|
||||
{
|
||||
return $this->lookup($this->_store[$itemName]['ref']);
|
||||
}
|
||||
|
||||
/** Create a fresh instance of $itemName */
|
||||
private function _createNewInstance($itemName)
|
||||
{
|
||||
$reflector = new ReflectionClass($this->_store[$itemName]['className']);
|
||||
if ($reflector->getConstructor()) {
|
||||
return $reflector->newInstanceArgs(
|
||||
$this->createDependenciesFor($itemName)
|
||||
);
|
||||
} else {
|
||||
return $reflector->newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
/** Create and register a shared instance of $itemName */
|
||||
private function _createSharedInstance($itemName)
|
||||
{
|
||||
if (!isset($this->_store[$itemName]['instance'])) {
|
||||
$this->_store[$itemName]['instance'] = $this->_createNewInstance($itemName);
|
||||
}
|
||||
|
||||
return $this->_store[$itemName]['instance'];
|
||||
}
|
||||
|
||||
/** Get the current endpoint in the store */
|
||||
private function &_getEndPoint()
|
||||
{
|
||||
if (!isset($this->_endPoint)) {
|
||||
throw new BadMethodCallException(
|
||||
'Component must first be registered by calling register()'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->_endPoint;
|
||||
}
|
||||
|
||||
/** Get an argument list with dependencies resolved */
|
||||
private function _resolveArgs(array $args)
|
||||
{
|
||||
$resolved = array();
|
||||
foreach ($args as $argDefinition) {
|
||||
switch ($argDefinition['type']) {
|
||||
case 'lookup':
|
||||
$resolved[] = $this->_lookupRecursive($argDefinition['item']);
|
||||
break;
|
||||
case 'value':
|
||||
$resolved[] = $argDefinition['item'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $resolved;
|
||||
}
|
||||
|
||||
/** Resolve a single dependency with an collections */
|
||||
private function _lookupRecursive($item)
|
||||
{
|
||||
if (is_array($item)) {
|
||||
$collection = array();
|
||||
foreach ($item as $k => $v) {
|
||||
$collection[$k] = $this->_lookupRecursive($v);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
} else {
|
||||
return $this->lookup($item);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DependencyException gets thrown when a requested dependency is missing.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_DependencyException extends Swift_SwiftException
|
||||
{
|
||||
/**
|
||||
* Create a new DependencyException with $message.
|
||||
*
|
||||
* @param string $message
|
||||
*/
|
||||
public function __construct($message)
|
||||
{
|
||||
parent::__construct($message);
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An embedded file, in a multipart message.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_EmbeddedFile extends Swift_Mime_EmbeddedFile
|
||||
{
|
||||
/**
|
||||
* Create a new EmbeddedFile.
|
||||
*
|
||||
* Details may be optionally provided to the constructor.
|
||||
*
|
||||
* @param string|Swift_OutputByteStream $data
|
||||
* @param string $filename
|
||||
* @param string $contentType
|
||||
*/
|
||||
public function __construct($data = null, $filename = null, $contentType = null)
|
||||
{
|
||||
call_user_func_array(
|
||||
array($this, 'Swift_Mime_EmbeddedFile::__construct'),
|
||||
Swift_DependencyContainer::getInstance()
|
||||
->createDependenciesFor('mime.embeddedfile')
|
||||
);
|
||||
|
||||
$this->setBody($data);
|
||||
$this->setFilename($filename);
|
||||
if ($contentType) {
|
||||
$this->setContentType($contentType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new EmbeddedFile.
|
||||
*
|
||||
* @param string|Swift_OutputByteStream $data
|
||||
* @param string $filename
|
||||
* @param string $contentType
|
||||
*
|
||||
* @return Swift_Mime_EmbeddedFile
|
||||
*/
|
||||
public static function newInstance($data = null, $filename = null, $contentType = null)
|
||||
{
|
||||
return new self($data, $filename, $contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new EmbeddedFile from a filesystem path.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return Swift_Mime_EmbeddedFile
|
||||
*/
|
||||
public static function fromPath($path)
|
||||
{
|
||||
return self::newInstance()->setFile(
|
||||
new Swift_ByteStream_FileByteStream($path)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface for all Encoder schemes.
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
interface Swift_Encoder extends Swift_Mime_CharsetObserver
|
||||
{
|
||||
/**
|
||||
* Encode a given string to produce an encoded string.
|
||||
*
|
||||
* @param string $string
|
||||
* @param int $firstLineOffset if first line needs to be shorter
|
||||
* @param int $maxLineLength - 0 indicates the default length for this encoding
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0);
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles Base 64 Encoding in Swift Mailer.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_Encoder_Base64Encoder implements Swift_Encoder
|
||||
{
|
||||
/**
|
||||
* Takes an unencoded string and produces a Base64 encoded string from it.
|
||||
*
|
||||
* Base64 encoded strings have a maximum line length of 76 characters.
|
||||
* If the first line needs to be shorter, indicate the difference with
|
||||
* $firstLineOffset.
|
||||
*
|
||||
* @param string $string to encode
|
||||
* @param int $firstLineOffset
|
||||
* @param int $maxLineLength optional, 0 indicates the default of 76 bytes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
|
||||
{
|
||||
if (0 >= $maxLineLength || 76 < $maxLineLength) {
|
||||
$maxLineLength = 76;
|
||||
}
|
||||
|
||||
$encodedString = base64_encode($string);
|
||||
$firstLine = '';
|
||||
|
||||
if (0 != $firstLineOffset) {
|
||||
$firstLine = substr(
|
||||
$encodedString, 0, $maxLineLength - $firstLineOffset
|
||||
) . "\r\n";
|
||||
$encodedString = substr(
|
||||
$encodedString, $maxLineLength - $firstLineOffset
|
||||
);
|
||||
}
|
||||
|
||||
return $firstLine . trim(chunk_split($encodedString, $maxLineLength, "\r\n"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
public function charsetChanged($charset)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,282 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles Quoted Printable (QP) Encoding in Swift Mailer.
|
||||
*
|
||||
* Possibly the most accurate RFC 2045 QP implementation found in PHP.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_Encoder_QpEncoder implements Swift_Encoder
|
||||
{
|
||||
/**
|
||||
* The CharacterStream used for reading characters (as opposed to bytes).
|
||||
*
|
||||
* @var Swift_CharacterStream
|
||||
*/
|
||||
protected $_charStream;
|
||||
|
||||
/**
|
||||
* A filter used if input should be canonicalized.
|
||||
*
|
||||
* @var Swift_StreamFilter
|
||||
*/
|
||||
protected $_filter;
|
||||
|
||||
/**
|
||||
* Pre-computed QP for HUGE optimization.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected static $_qpMap = array(
|
||||
0 => '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04',
|
||||
5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09',
|
||||
10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E',
|
||||
15 => '=0F', 16 => '=10', 17 => '=11', 18 => '=12', 19 => '=13',
|
||||
20 => '=14', 21 => '=15', 22 => '=16', 23 => '=17', 24 => '=18',
|
||||
25 => '=19', 26 => '=1A', 27 => '=1B', 28 => '=1C', 29 => '=1D',
|
||||
30 => '=1E', 31 => '=1F', 32 => '=20', 33 => '=21', 34 => '=22',
|
||||
35 => '=23', 36 => '=24', 37 => '=25', 38 => '=26', 39 => '=27',
|
||||
40 => '=28', 41 => '=29', 42 => '=2A', 43 => '=2B', 44 => '=2C',
|
||||
45 => '=2D', 46 => '=2E', 47 => '=2F', 48 => '=30', 49 => '=31',
|
||||
50 => '=32', 51 => '=33', 52 => '=34', 53 => '=35', 54 => '=36',
|
||||
55 => '=37', 56 => '=38', 57 => '=39', 58 => '=3A', 59 => '=3B',
|
||||
60 => '=3C', 61 => '=3D', 62 => '=3E', 63 => '=3F', 64 => '=40',
|
||||
65 => '=41', 66 => '=42', 67 => '=43', 68 => '=44', 69 => '=45',
|
||||
70 => '=46', 71 => '=47', 72 => '=48', 73 => '=49', 74 => '=4A',
|
||||
75 => '=4B', 76 => '=4C', 77 => '=4D', 78 => '=4E', 79 => '=4F',
|
||||
80 => '=50', 81 => '=51', 82 => '=52', 83 => '=53', 84 => '=54',
|
||||
85 => '=55', 86 => '=56', 87 => '=57', 88 => '=58', 89 => '=59',
|
||||
90 => '=5A', 91 => '=5B', 92 => '=5C', 93 => '=5D', 94 => '=5E',
|
||||
95 => '=5F', 96 => '=60', 97 => '=61', 98 => '=62', 99 => '=63',
|
||||
100 => '=64', 101 => '=65', 102 => '=66', 103 => '=67', 104 => '=68',
|
||||
105 => '=69', 106 => '=6A', 107 => '=6B', 108 => '=6C', 109 => '=6D',
|
||||
110 => '=6E', 111 => '=6F', 112 => '=70', 113 => '=71', 114 => '=72',
|
||||
115 => '=73', 116 => '=74', 117 => '=75', 118 => '=76', 119 => '=77',
|
||||
120 => '=78', 121 => '=79', 122 => '=7A', 123 => '=7B', 124 => '=7C',
|
||||
125 => '=7D', 126 => '=7E', 127 => '=7F', 128 => '=80', 129 => '=81',
|
||||
130 => '=82', 131 => '=83', 132 => '=84', 133 => '=85', 134 => '=86',
|
||||
135 => '=87', 136 => '=88', 137 => '=89', 138 => '=8A', 139 => '=8B',
|
||||
140 => '=8C', 141 => '=8D', 142 => '=8E', 143 => '=8F', 144 => '=90',
|
||||
145 => '=91', 146 => '=92', 147 => '=93', 148 => '=94', 149 => '=95',
|
||||
150 => '=96', 151 => '=97', 152 => '=98', 153 => '=99', 154 => '=9A',
|
||||
155 => '=9B', 156 => '=9C', 157 => '=9D', 158 => '=9E', 159 => '=9F',
|
||||
160 => '=A0', 161 => '=A1', 162 => '=A2', 163 => '=A3', 164 => '=A4',
|
||||
165 => '=A5', 166 => '=A6', 167 => '=A7', 168 => '=A8', 169 => '=A9',
|
||||
170 => '=AA', 171 => '=AB', 172 => '=AC', 173 => '=AD', 174 => '=AE',
|
||||
175 => '=AF', 176 => '=B0', 177 => '=B1', 178 => '=B2', 179 => '=B3',
|
||||
180 => '=B4', 181 => '=B5', 182 => '=B6', 183 => '=B7', 184 => '=B8',
|
||||
185 => '=B9', 186 => '=BA', 187 => '=BB', 188 => '=BC', 189 => '=BD',
|
||||
190 => '=BE', 191 => '=BF', 192 => '=C0', 193 => '=C1', 194 => '=C2',
|
||||
195 => '=C3', 196 => '=C4', 197 => '=C5', 198 => '=C6', 199 => '=C7',
|
||||
200 => '=C8', 201 => '=C9', 202 => '=CA', 203 => '=CB', 204 => '=CC',
|
||||
205 => '=CD', 206 => '=CE', 207 => '=CF', 208 => '=D0', 209 => '=D1',
|
||||
210 => '=D2', 211 => '=D3', 212 => '=D4', 213 => '=D5', 214 => '=D6',
|
||||
215 => '=D7', 216 => '=D8', 217 => '=D9', 218 => '=DA', 219 => '=DB',
|
||||
220 => '=DC', 221 => '=DD', 222 => '=DE', 223 => '=DF', 224 => '=E0',
|
||||
225 => '=E1', 226 => '=E2', 227 => '=E3', 228 => '=E4', 229 => '=E5',
|
||||
230 => '=E6', 231 => '=E7', 232 => '=E8', 233 => '=E9', 234 => '=EA',
|
||||
235 => '=EB', 236 => '=EC', 237 => '=ED', 238 => '=EE', 239 => '=EF',
|
||||
240 => '=F0', 241 => '=F1', 242 => '=F2', 243 => '=F3', 244 => '=F4',
|
||||
245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9',
|
||||
250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE',
|
||||
255 => '=FF'
|
||||
);
|
||||
|
||||
protected static $_safeMapShare = array();
|
||||
|
||||
/**
|
||||
* A map of non-encoded ascii characters.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $_safeMap = array();
|
||||
|
||||
/**
|
||||
* Creates a new QpEncoder for the given CharacterStream.
|
||||
*
|
||||
* @param Swift_CharacterStream $charStream to use for reading characters
|
||||
* @param Swift_StreamFilter $filter if input should be canonicalized
|
||||
*/
|
||||
public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null)
|
||||
{
|
||||
$this->_charStream = $charStream;
|
||||
if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) {
|
||||
$this->initSafeMap();
|
||||
self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap;
|
||||
} else {
|
||||
$this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()];
|
||||
}
|
||||
$this->_filter = $filter;
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
return array('_charStream', '_filter');
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) {
|
||||
$this->initSafeMap();
|
||||
self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap;
|
||||
} else {
|
||||
$this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()];
|
||||
}
|
||||
}
|
||||
|
||||
protected function getSafeMapShareId()
|
||||
{
|
||||
return get_class($this);
|
||||
}
|
||||
|
||||
protected function initSafeMap()
|
||||
{
|
||||
foreach (array_merge(
|
||||
array(0x09, 0x20), range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte)
|
||||
{
|
||||
$this->_safeMap[$byte] = chr($byte);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an unencoded string and produces a QP encoded string from it.
|
||||
*
|
||||
* QP encoded strings have a maximum line length of 76 characters.
|
||||
* If the first line needs to be shorter, indicate the difference with
|
||||
* $firstLineOffset.
|
||||
*
|
||||
* @param string $string to encode
|
||||
* @param int $firstLineOffset, optional
|
||||
* @param int $maxLineLength, optional 0 indicates the default of 76 chars
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
|
||||
{
|
||||
if ($maxLineLength > 76 || $maxLineLength <= 0) {
|
||||
$maxLineLength = 76;
|
||||
}
|
||||
|
||||
$thisLineLength = $maxLineLength - $firstLineOffset;
|
||||
|
||||
$lines = array();
|
||||
$lNo = 0;
|
||||
$lines[$lNo] = '';
|
||||
$currentLine =& $lines[$lNo++];
|
||||
$size=$lineLen=0;
|
||||
|
||||
$this->_charStream->flushContents();
|
||||
$this->_charStream->importString($string);
|
||||
|
||||
// Fetching more than 4 chars at one is slower, as is fetching fewer bytes
|
||||
// Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6
|
||||
// bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes
|
||||
while (false !== $bytes = $this->_nextSequence()) {
|
||||
// If we're filtering the input
|
||||
if (isset($this->_filter)) {
|
||||
// If we can't filter because we need more bytes
|
||||
while ($this->_filter->shouldBuffer($bytes)) {
|
||||
// Then collect bytes into the buffer
|
||||
if (false === $moreBytes = $this->_nextSequence(1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($moreBytes as $b) {
|
||||
$bytes[] = $b;
|
||||
}
|
||||
}
|
||||
// And filter them
|
||||
$bytes = $this->_filter->filter($bytes);
|
||||
}
|
||||
|
||||
$enc = $this->_encodeByteSequence($bytes, $size);
|
||||
if ($currentLine && $lineLen+$size >= $thisLineLength) {
|
||||
$lines[$lNo] = '';
|
||||
$currentLine =& $lines[$lNo++];
|
||||
$thisLineLength = $maxLineLength;
|
||||
$lineLen=0;
|
||||
}
|
||||
$lineLen+=$size;
|
||||
$currentLine .= $enc;
|
||||
}
|
||||
|
||||
return $this->_standardize(implode("=\r\n", $lines));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the charset used.
|
||||
*
|
||||
* @param string $charset
|
||||
*/
|
||||
public function charsetChanged($charset)
|
||||
{
|
||||
$this->_charStream->setCharacterSet($charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the given byte array into a verbatim QP form.
|
||||
*
|
||||
* @param integer[] $bytes
|
||||
* @param int $size
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _encodeByteSequence(array $bytes, &$size)
|
||||
{
|
||||
$ret = '';
|
||||
$size=0;
|
||||
foreach ($bytes as $b) {
|
||||
if (isset($this->_safeMap[$b])) {
|
||||
$ret .= $this->_safeMap[$b];
|
||||
++$size;
|
||||
} else {
|
||||
$ret .= self::$_qpMap[$b];
|
||||
$size+=3;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next sequence of bytes to read from the char stream.
|
||||
*
|
||||
* @param int $size number of bytes to read
|
||||
*
|
||||
* @return integer[]
|
||||
*/
|
||||
protected function _nextSequence($size = 4)
|
||||
{
|
||||
return $this->_charStream->readBytes($size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure CRLF is correct and HT/SPACE are in valid places.
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _standardize($string)
|
||||
{
|
||||
$string = str_replace(array("\t=0D=0A", " =0D=0A", "=0D=0A"),
|
||||
array("=09\r\n", "=20\r\n", "\r\n"), $string
|
||||
);
|
||||
switch ($end = ord(substr($string, -1))) {
|
||||
case 0x09:
|
||||
case 0x20:
|
||||
$string = substr_replace($string, self::$_qpMap[$end], -1);
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles RFC 2231 specified Encoding in Swift Mailer.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_Encoder_Rfc2231Encoder implements Swift_Encoder
|
||||
{
|
||||
/**
|
||||
* A character stream to use when reading a string as characters instead of bytes.
|
||||
*
|
||||
* @var Swift_CharacterStream
|
||||
*/
|
||||
private $_charStream;
|
||||
|
||||
/**
|
||||
* Creates a new Rfc2231Encoder using the given character stream instance.
|
||||
*
|
||||
* @param Swift_CharacterStream
|
||||
*/
|
||||
public function __construct(Swift_CharacterStream $charStream)
|
||||
{
|
||||
$this->_charStream = $charStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an unencoded string and produces a string encoded according to
|
||||
* RFC 2231 from it.
|
||||
*
|
||||
* @param string $string
|
||||
* @param int $firstLineOffset
|
||||
* @param int $maxLineLength optional, 0 indicates the default of 75 bytes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
|
||||
{
|
||||
$lines = array(); $lineCount = 0;
|
||||
$lines[] = '';
|
||||
$currentLine =& $lines[$lineCount++];
|
||||
|
||||
if (0 >= $maxLineLength) {
|
||||
$maxLineLength = 75;
|
||||
}
|
||||
|
||||
$this->_charStream->flushContents();
|
||||
$this->_charStream->importString($string);
|
||||
|
||||
$thisLineLength = $maxLineLength - $firstLineOffset;
|
||||
|
||||
while (false !== $char = $this->_charStream->read(4)) {
|
||||
$encodedChar = rawurlencode($char);
|
||||
if (0 != strlen($currentLine)
|
||||
&& strlen($currentLine . $encodedChar) > $thisLineLength)
|
||||
{
|
||||
$lines[] = '';
|
||||
$currentLine =& $lines[$lineCount++];
|
||||
$thisLineLength = $maxLineLength;
|
||||
}
|
||||
$currentLine .= $encodedChar;
|
||||
}
|
||||
|
||||
return implode("\r\n", $lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the charset used.
|
||||
*
|
||||
* @param string $charset
|
||||
*/
|
||||
public function charsetChanged($charset)
|
||||
{
|
||||
$this->_charStream->setCharacterSet($charset);
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides quick access to each encoding type.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_Encoding
|
||||
{
|
||||
/**
|
||||
* Get the Encoder that provides 7-bit encoding.
|
||||
*
|
||||
* @return Swift_Mime_ContentEncoder
|
||||
*/
|
||||
public static function get7BitEncoding()
|
||||
{
|
||||
return self::_lookup('mime.7bitcontentencoder');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Encoder that provides 8-bit encoding.
|
||||
*
|
||||
* @return Swift_Mime_ContentEncoder
|
||||
*/
|
||||
public static function get8BitEncoding()
|
||||
{
|
||||
return self::_lookup('mime.8bitcontentencoder');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Encoder that provides Quoted-Printable (QP) encoding.
|
||||
*
|
||||
* @return Swift_Mime_ContentEncoder
|
||||
*/
|
||||
public static function getQpEncoding()
|
||||
{
|
||||
return self::_lookup('mime.qpcontentencoder');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Encoder that provides Base64 encoding.
|
||||
*
|
||||
* @return Swift_Mime_ContentEncoder
|
||||
*/
|
||||
public static function getBase64Encoding()
|
||||
{
|
||||
return self::_lookup('mime.base64contentencoder');
|
||||
}
|
||||
|
||||
// -- Private Static Methods
|
||||
|
||||
private static function _lookup($key)
|
||||
{
|
||||
return Swift_DependencyContainer::getInstance()->lookup($key);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue