├── .gitignore ├── .vscode └── tasks.json ├── README.md ├── dist └── main.js ├── docs ├── demos │ ├── .gitignore │ ├── build │ │ ├── asset-manifest.json │ │ ├── index.html │ │ └── static │ │ │ └── js │ │ │ ├── main.bcb31a39.js │ │ │ └── main.bcb31a39.js.map │ ├── package.json │ ├── public │ │ └── index.html │ └── src │ │ ├── actions │ │ ├── index.js │ │ ├── types.js │ │ └── users │ │ │ ├── GetUsersBatch.js │ │ │ ├── ReceivedUsersBatch.js │ │ │ └── SetFetchingUsersStatus.js │ │ ├── components │ │ ├── layouts │ │ │ └── ListItem.js │ │ └── views │ │ │ └── Main.js │ │ ├── configureStore.js │ │ ├── epics │ │ ├── index.js │ │ └── users │ │ │ └── GetUsersBatch.js │ │ ├── index.js │ │ └── reducers │ │ ├── index.js │ │ └── users │ │ ├── IsFetchingUsers.js │ │ └── Users.js └── gen │ ├── ListView.html │ ├── classes.list.html │ ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 │ ├── img │ ├── glyphicons-halflings-white.png │ └── glyphicons-halflings.png │ ├── index.html │ ├── quicksearch.html │ ├── scripts │ ├── docstrap.lib.js │ ├── fulltext-search-ui.js │ ├── fulltext-search.js │ ├── lunr.min.js │ ├── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── jquery.min.js │ │ ├── lang-css.js │ │ └── prettify.js │ ├── sunlight.js │ └── toc.js │ └── styles │ ├── darkstrap.css │ ├── prettify-tomorrow.css │ ├── site.cerulean.css │ ├── site.cosmo.css │ ├── site.cyborg.css │ ├── site.darkly.css │ ├── site.darkstrap.css │ ├── site.dibs-bootstrap.css │ ├── site.flatly.css │ ├── site.journal.css │ ├── site.lumen.css │ ├── site.paper.css │ ├── site.readable.css │ ├── site.sandstone.css │ ├── site.simplex.css │ ├── site.slate.css │ ├── site.spacelab.css │ ├── site.superhero.css │ ├── site.united.css │ ├── site.yeti.css │ ├── sunlight.dark.css │ └── sunlight.default.css ├── gulpfile.js ├── library ├── ListView.js ├── ListViewDataSource.js └── main.js ├── package.json ├── webpack.config.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # testing 7 | coverage 8 | 9 | # misc 10 | .DS_Store 11 | .env 12 | npm-debug.log 13 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "0.1.0", 5 | "command": "gulp", 6 | "isBuildCommand": true, 7 | "args": [], 8 | "showOutput": "silent" 9 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # clarity-react-infinite-list 2 | 3 | ![NPM version](https://img.shields.io/npm/v/clarity-react-infinite-list.svg?style=flat) 4 | ![NPM license](https://img.shields.io/npm/l/clarity-react-infinite-list.svg?style=flat) 5 | ![NPM total downloads](https://img.shields.io/npm/dt/clarity-react-infinite-list.svg?style=flat) 6 | ![NPM monthly downloads](https://img.shields.io/npm/dm/clarity-react-infinite-list.svg?style=flat) 7 | 8 | A browser efficient infinite list for React apps that allows loading of items with differing heights and sizes. 9 | The minimal API is to create a `ListViewDataSource` from `clarity-react-infinite-list`, populate it with an array of data, and add a `ListView` component 10 | with that data source and a `renderRow` callback which takes an item from the data source and returns a renderable component. 11 | 12 | ## Install 13 | ```bash 14 | npm install clarity-react-infinite-list 15 | ``` 16 | 17 | ## Demos 18 | [Github API Data](https://sourcedecoded.github.io/clarity-react-infinite-list/demos/build/index.html) 19 | 20 | ## Features 21 | * Lazy load and fetch data from API requests in batches. 22 | * Infinite number of items and batches 23 | * Items can have dynamic heights and sizes, that do not have to be declared before hand. 24 | * Add in a custom loading component. 25 | 26 | ## Dependencies 27 | ### Version 15.x.x 28 | * `react` 29 | * `react-dom` 30 | 31 | ## Minimal Example 32 | ```js 33 | import React, { Component } from "react"; 34 | import { connect } from "react-redux"; 35 | import { getUsersBatch, setFetchingUsersStatus } from "../../actions"; 36 | import { ListView, ListViewDataSource } from "clarity-react-infinite-list"; 37 | import ListItem from "../layouts/ListItem"; 38 | 39 | const styles = {...}; 40 | 41 | class Main extends Component { 42 | constructor(props) { 43 | super(props); 44 | 45 | this.state = { 46 | dataSource: new ListViewDataSource(30), 47 | lastUserId: 0 48 | }; 49 | 50 | this._renderRow = this._renderRow.bind(this); 51 | this._onEndReached = this._onEndReached.bind(this); 52 | this._loadingComponent = this._loadingComponent.bind(this); 53 | } 54 | 55 | _renderRow(rowData, rowId) { 56 | return ( 57 | 58 | ); 59 | } 60 | 61 | _onEndReached() { 62 | if (!this.props.isFetchingUsers) { 63 | this.props.setFetchingUsersStatus(true); 64 | this.props.getUsersBatch(this.state.lastUserId); 65 | } 66 | } 67 | 68 | _loadingComponent() { 69 | return ( 70 |
Loading...
71 | ); 72 | } 73 | 74 | componentWillMount() { 75 | this.props.setFetchingUsersStatus(true); 76 | this.props.getUsersBatch(this.state.lastUserId); 77 | } 78 | 79 | componentWillReceiveProps(nextProps) { 80 | if (nextProps.users[nextProps.users.length - 1] && this.state.lastUserId !== nextProps.users[nextProps.users.length - 1].id) { 81 | this.setState({ 82 | dataSource: this.state.dataSource.cloneWithRows(nextProps.users), 83 | lastUserId: nextProps.users[nextProps.users.length - 1].id, 84 | }); 85 | } 86 | } 87 | 88 | render() { 89 | return ( 90 |
91 |
92 | Clarity React Infinite Scroll Example 93 |
94 | this.listView = listView} /> 101 |
102 | ); 103 | } 104 | } 105 | 106 | const mapStateToProps = (state) => { 107 | return { 108 | users: state.users, 109 | isFetchingUsers: state.isFetchingUsers 110 | }; 111 | }; 112 | 113 | const mapDispatchToProps = { 114 | getUsersBatch, 115 | setFetchingUsersStatus 116 | }; 117 | 118 | export default connect(mapStateToProps, mapDispatchToProps)(Main); 119 | ``` 120 | 121 | ## Props 122 | #### `dataSource` ListViewDataSource 123 | * An instance of `ListViewDataSource`to use. 124 | 125 | #### `renderRow` function(rowData, rowId) => renderableComponent 126 | * Takes a data entry from the data source and its id and should return a renderable component to be rendered as the row. 127 | 128 | #### `onEndReached` function() 129 | * Called when the list has been scrolled to within the `onEndReachedThreshold` of the bottom. 130 | 131 | #### `loadingComponent` function() => renderableComponent 132 | * Should return a renderable component, to be displayed at bottom of list when loading new batches. 133 | 134 | #### `onEndReachedThreshold` number 135 | * Threshold in pixels for calling `onEndReached` 136 | 137 | ## Methods 138 | #### `scrollTo(topPosition: number)` 139 | * Scrolls to the given topPosition of the `ListView`. 140 | 141 | #### `isScrollbarActive()` 142 | * Returns a boolean of whether or not the `ListView` has enough content to have an active vertical scrollbar. 143 | 144 | #### `digBatches()` 145 | * Manually dig batches from the props.onEndReached function. -------------------------------------------------------------------------------- /docs/demos/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # testing 7 | coverage 8 | 9 | # misc 10 | .DS_Store 11 | .env 12 | npm-debug.log 13 | -------------------------------------------------------------------------------- /docs/demos/build/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "main.js": "static/js/main.bcb31a39.js", 3 | "main.js.map": "static/js/main.bcb31a39.js.map" 4 | } -------------------------------------------------------------------------------- /docs/demos/build/index.html: -------------------------------------------------------------------------------- 1 | Clarity React Infinite List Demo
-------------------------------------------------------------------------------- /docs/demos/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demos", 3 | "version": "0.1.0", 4 | "private": false, 5 | "devDependencies": { 6 | "react-scripts": "0.8.5" 7 | }, 8 | "dependencies": { 9 | "clarity-react-infinite-list": "^1.0.1", 10 | "react": "^15.4.2", 11 | "react-dom": "^15.4.2", 12 | "react-redux": "^5.0.2", 13 | "redux": "^3.6.0", 14 | "redux-observable": "^0.13.0", 15 | "rxjs": "^5.1.0" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test --env=jsdom", 21 | "eject": "react-scripts eject" 22 | }, 23 | "homepage": "https://sourcedecoded.github.io/clarity-react-infinite-list/demos/build/" 24 | } 25 | -------------------------------------------------------------------------------- /docs/demos/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Clarity React Infinite List Demo 8 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/demos/src/actions/index.js: -------------------------------------------------------------------------------- 1 | import getUsersBatch from "./users/GetUsersBatch"; 2 | import receivedUsersBatch from "./users/ReceivedUsersBatch"; 3 | import setFetchingUsersStatus from "./users/SetFetchingUsersStatus"; 4 | 5 | export { 6 | getUsersBatch, 7 | receivedUsersBatch, 8 | setFetchingUsersStatus 9 | }; -------------------------------------------------------------------------------- /docs/demos/src/actions/types.js: -------------------------------------------------------------------------------- 1 | export const GET_USERS_BATCH = "GET_USERS_BATCH"; 2 | export const RECEIVED_USERS_BATCH = "RECEIVED_USERS_BATCH"; 3 | export const SET_FETCHING_USERS_STATUS = "SET_FETCHING_USERS_STATUS"; -------------------------------------------------------------------------------- /docs/demos/src/actions/users/GetUsersBatch.js: -------------------------------------------------------------------------------- 1 | import * as ActionTypes from "../types"; 2 | 3 | export default function getUsersBatch(lastUserId) { 4 | return { 5 | type: ActionTypes.GET_USERS_BATCH, 6 | payload: { 7 | lastUserId 8 | } 9 | }; 10 | }; -------------------------------------------------------------------------------- /docs/demos/src/actions/users/ReceivedUsersBatch.js: -------------------------------------------------------------------------------- 1 | import * as ActionTypes from "../types"; 2 | 3 | export default function receivedUsersBatch(users) { 4 | return { 5 | type: ActionTypes.RECEIVED_USERS_BATCH, 6 | payload: { 7 | users 8 | } 9 | }; 10 | }; -------------------------------------------------------------------------------- /docs/demos/src/actions/users/SetFetchingUsersStatus.js: -------------------------------------------------------------------------------- 1 | import * as ActionTypes from "../types"; 2 | 3 | export default function setFetchingUsersStatus(isFetchingUsers) { 4 | return { 5 | type: ActionTypes.SET_FETCHING_USERS_STATUS, 6 | payload: { 7 | isFetchingUsers 8 | } 9 | }; 10 | }; -------------------------------------------------------------------------------- /docs/demos/src/components/layouts/ListItem.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const styles = { 4 | container: { 5 | padding: "16px", 6 | maxWidth: "400px", 7 | color: "#757575", 8 | margin: "0 auto 16px auto", 9 | borderRadius: "3px", 10 | backgroundColor: "#fff", 11 | textAlign: "center" 12 | }, 13 | profileImage: { 14 | height: "60px", 15 | width: "60px", 16 | borderRadius: "50%" 17 | }, 18 | profileName: { 19 | padding: "6px 0 12px 0", 20 | fontSize: "14px", 21 | color: "#616161" 22 | }, 23 | spaceEater: { 24 | height: "20px", 25 | backgroundColor: "#e9ebee", 26 | marginBottom: "8px" 27 | } 28 | }; 29 | 30 | const getSpaceEaters = (numSpaceEaters) => { 31 | let spaceEaters = []; 32 | 33 | for (let i = 0; i < numSpaceEaters; i++) { 34 | spaceEaters.push(
); 35 | } 36 | 37 | return spaceEaters; 38 | }; 39 | 40 | const ListItem = props => { 41 | const spaceEaters = getSpaceEaters(props.rowData.numSpaceEaters); 42 | 43 | return ( 44 |
45 | 46 |
{props.rowData.login}
47 | {spaceEaters} 48 |
49 | ); 50 | }; 51 | 52 | export default ListItem; -------------------------------------------------------------------------------- /docs/demos/src/components/views/Main.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { connect } from "react-redux"; 3 | import { getUsersBatch, setFetchingUsersStatus } from "../../actions"; 4 | import { ListView, ListViewDataSource } from "clarity-react-infinite-list"; 5 | import ListItem from "../layouts/ListItem"; 6 | 7 | const styles = { 8 | container: { 9 | position: "absolute", 10 | top: 0, 11 | left: 0, 12 | width: "100%", 13 | height: "100%" 14 | }, 15 | header: { 16 | boxShadow: "0 1px 8px rgba(0,0,0,.3)", 17 | fontSize: "18px", 18 | textAlign: "center", 19 | height: "80px", 20 | lineHeight: "80px", 21 | color: "#f2f2f2", 22 | backgroundColor: "#1e88e5", 23 | position: "relative", 24 | zIndex: "2", 25 | whiteSpace: "nowrap", 26 | overflow: "hidden", 27 | textOverflow: "ellipsis" 28 | }, 29 | listView: { 30 | paddingTop: "16px", 31 | position: "absolute", 32 | top: "80px", 33 | bottom: "0", 34 | left: "0", 35 | right: "0", 36 | overflowY: "scroll", 37 | WebkitOverflowScrolling: "touch" 38 | }, 39 | loading: { 40 | textAlign: "center", 41 | paddingBottom: "16px" 42 | } 43 | }; 44 | 45 | class Main extends Component { 46 | constructor(props) { 47 | super(props); 48 | 49 | this.state = { 50 | dataSource: new ListViewDataSource(30), 51 | lastUserId: 0 52 | }; 53 | 54 | this._renderRow = this._renderRow.bind(this); 55 | this._onEndReached = this._onEndReached.bind(this); 56 | this._loadingComponent = this._loadingComponent.bind(this); 57 | } 58 | 59 | _renderRow(rowData, rowId) { 60 | return ( 61 | 62 | ); 63 | } 64 | 65 | _onEndReached() { 66 | if (!this.props.isFetchingUsers) { 67 | this.props.setFetchingUsersStatus(true); 68 | this.props.getUsersBatch(this.state.lastUserId); 69 | } 70 | } 71 | 72 | _loadingComponent() { 73 | return ( 74 |
Loading...
75 | ); 76 | } 77 | 78 | componentWillMount() { 79 | this.props.setFetchingUsersStatus(true); 80 | this.props.getUsersBatch(this.state.lastUserId); 81 | } 82 | 83 | componentWillReceiveProps(nextProps) { 84 | if (nextProps.users[nextProps.users.length - 1] && this.state.lastUserId !== nextProps.users[nextProps.users.length - 1].id) { 85 | this.setState({ 86 | dataSource: this.state.dataSource.cloneWithRows(nextProps.users), 87 | lastUserId: nextProps.users[nextProps.users.length - 1].id, 88 | }); 89 | } 90 | } 91 | 92 | render() { 93 | return ( 94 |
95 |
96 | Clarity React Infinite Scroll Example 97 |
98 | this.listView = listView} /> 105 |
106 | ); 107 | } 108 | } 109 | 110 | 111 | const mapStateToProps = (state) => { 112 | return { 113 | users: state.users, 114 | isFetchingUsers: state.isFetchingUsers 115 | }; 116 | }; 117 | 118 | const mapDispatchToProps = { 119 | getUsersBatch, 120 | setFetchingUsersStatus 121 | }; 122 | 123 | export default connect(mapStateToProps, mapDispatchToProps)(Main); -------------------------------------------------------------------------------- /docs/demos/src/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from "redux"; 2 | import { createEpicMiddleware } from "redux-observable"; 3 | import rootReducer from "./reducers"; 4 | import rootEpic from "./epics"; 5 | 6 | const epicMiddleware = createEpicMiddleware(rootEpic); 7 | 8 | export default function configureStore() { 9 | const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; 10 | const store = createStore( 11 | rootReducer, 12 | composeEnhancers( 13 | applyMiddleware( 14 | epicMiddleware 15 | ) 16 | ) 17 | ); 18 | return store; 19 | }; -------------------------------------------------------------------------------- /docs/demos/src/epics/index.js: -------------------------------------------------------------------------------- 1 | import { combineEpics } from "redux-observable"; 2 | import getUsersBatch from "./users/GetUsersBatch"; 3 | 4 | export default combineEpics( 5 | getUsersBatch 6 | ); -------------------------------------------------------------------------------- /docs/demos/src/epics/users/GetUsersBatch.js: -------------------------------------------------------------------------------- 1 | import * as ActionTypes from "../../actions/types"; 2 | import { receivedUsersBatch, setFetchingUsersStatus } from "../../actions"; 3 | 4 | export default function getUsersBatch(action$) { 5 | return action$.ofType(ActionTypes.GET_USERS_BATCH) 6 | .delay(1000).mergeMap(action => 7 | fetch(`https://api.github.com/users?since=${action.payload.lastUserId}`) 8 | .then(response => { 9 | return response.json(); 10 | }) 11 | .then(users => { 12 | return users.reduce((acc, user) => { 13 | const randNum = Math.round(Math.random() * 10) + 1; 14 | 15 | acc.push({ 16 | id: user.id, 17 | avatar_url: user.avatar_url, 18 | login: user.login, 19 | numSpaceEaters: randNum 20 | }); 21 | 22 | return acc; 23 | }, []); 24 | }) 25 | ) 26 | .flatMap(users => ([receivedUsersBatch(users), setFetchingUsersStatus(false)])); 27 | }; -------------------------------------------------------------------------------- /docs/demos/src/index.js: -------------------------------------------------------------------------------- 1 | import "rxjs"; 2 | import React from "react"; 3 | import ReactDOM from "react-dom"; 4 | import { Provider } from "react-redux"; 5 | import configureStore from "./configureStore"; 6 | import Main from "./components/views/Main"; 7 | 8 | ReactDOM.render( 9 | 10 |
11 | , 12 | document.getElementById("root") 13 | ); -------------------------------------------------------------------------------- /docs/demos/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from "redux"; 2 | import users from "./users/Users"; 3 | import isFetchingUsers from "./users/IsFetchingUsers"; 4 | 5 | export default combineReducers({ 6 | users, 7 | isFetchingUsers 8 | }); -------------------------------------------------------------------------------- /docs/demos/src/reducers/users/IsFetchingUsers.js: -------------------------------------------------------------------------------- 1 | import * as ActionTypes from "../../actions/types"; 2 | 3 | export default function isFetchingUsers(state = false, action) { 4 | if (action.type === ActionTypes.SET_FETCHING_USERS_STATUS) { 5 | return action.payload.isFetchingUsers; 6 | } else { 7 | return state; 8 | } 9 | }; -------------------------------------------------------------------------------- /docs/demos/src/reducers/users/Users.js: -------------------------------------------------------------------------------- 1 | import * as ActionTypes from "../../actions/types"; 2 | 3 | export default function users(state = [], action) { 4 | if (action.type === ActionTypes.RECEIVED_USERS_BATCH) { 5 | return action.payload.users; 6 | } else { 7 | return state; 8 | } 9 | }; -------------------------------------------------------------------------------- /docs/gen/ListView.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Documentation Class: ListView 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 57 | 58 | 59 |
60 |
61 | 62 | 63 |
64 | 65 |
66 | 67 | 68 |

Class: ListView

69 |
70 | 71 |
72 | 73 |

74 | ListView 75 |

76 | 77 |

Infinite List View

78 | 79 | 80 |
81 | 82 | 83 |
84 |
85 | 86 | 87 |
88 |
89 |

new ListView()

90 | 91 | 92 |
93 |
94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 |
106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 |
142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 |
158 | 159 | 160 |
161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 |

Methods

176 | 177 |
178 | 179 |
180 |
181 |

digBatches()

182 | 183 | 184 |
185 |
186 | 187 | 188 |
189 |

Manually dig batches from the props.onEndReached function.

190 |
191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 |
202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 |
238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 |
254 | 255 | 256 | 257 |
258 |
259 |

isScrollbarActive()

260 | 261 | 262 |
263 |
264 | 265 | 266 |
267 |

Checks if content inside of scrollbar is long enough to have an active scrollbar.

268 |
269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 |
280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 |
316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 |
332 | 333 | 334 | 335 |
336 |
337 |

scrollTo(topPosition)

338 | 339 | 340 |
341 |
342 | 343 | 344 |
345 |

Changes the scrollTop to the topPosition provided.

346 |
347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 |
Parameters:
356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 |
NameTypeDescription
topPosition 384 | 385 | 386 | number 387 | 388 | 389 | 390 | 391 |

The desired scroll top position.

403 | 404 | 405 | 406 | 407 |
408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 |
444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 |
460 | 461 |
462 | 463 | 464 | 465 | 466 | 467 |
468 | 469 |
470 | 471 | 472 | 473 | 474 |
475 |
476 | 477 |
478 | 479 | 480 |
481 | 482 |
483 | 484 | 485 |
486 |
487 | 488 | 489 | 503 | 504 | 505 |
506 | 507 | 508 | 509 | Documentation generated by JSDoc 3.4.3 510 | 511 | on October 27th 2017, 3:19:51 pm 512 | 513 | using the DocStrap template. 514 | 515 |
516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 599 | 600 | 601 | 602 | -------------------------------------------------------------------------------- /docs/gen/classes.list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Documentation Classes 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 57 | 58 | 59 |
60 |
61 | 62 | 63 |
64 | 65 |
66 | 67 | 68 |

Classes

69 |
70 | 71 |
72 | 73 |

74 | 75 |

76 | 77 | 78 |
79 | 80 | 81 |
82 |
83 | 84 | 85 | 86 | 87 |
88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 |
124 | 125 | 126 | 127 | 128 |
129 | 130 | 131 | 132 | 133 | 134 | 135 |

Classes

136 | 137 |
138 |
ListView
139 |
140 |
141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 |
155 | 156 |
157 | 158 | 159 | 160 | 161 |
162 |
163 | 164 |
165 | 166 | 167 |
168 | 169 |
170 | 171 | 172 |
173 |
174 | 175 | 176 | 190 | 191 | 192 |
193 | 194 | 195 | 196 | Documentation generated by JSDoc 3.4.3 197 | 198 | on October 27th 2017, 3:19:51 pm 199 | 200 | using the DocStrap template. 201 | 202 |
203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 286 | 287 | 288 | 289 | -------------------------------------------------------------------------------- /docs/gen/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SourceDecoded/clarity-react-infinite-list/5eef251d71c110375e8528646a1896ccdb20640d/docs/gen/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /docs/gen/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SourceDecoded/clarity-react-infinite-list/5eef251d71c110375e8528646a1896ccdb20640d/docs/gen/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /docs/gen/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SourceDecoded/clarity-react-infinite-list/5eef251d71c110375e8528646a1896ccdb20640d/docs/gen/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /docs/gen/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SourceDecoded/clarity-react-infinite-list/5eef251d71c110375e8528646a1896ccdb20640d/docs/gen/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /docs/gen/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SourceDecoded/clarity-react-infinite-list/5eef251d71c110375e8528646a1896ccdb20640d/docs/gen/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /docs/gen/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SourceDecoded/clarity-react-infinite-list/5eef251d71c110375e8528646a1896ccdb20640d/docs/gen/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /docs/gen/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Documentation Index 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 57 | 58 | 59 |
60 |
61 | 62 | 63 |
64 | 65 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
89 |

clarity-react-infinite-list

NPM version 90 | NPM license 91 | NPM total downloads 92 | NPM monthly downloads

93 |

A browser efficient infinite list for React apps that allows loading of items with differing heights and sizes. 94 | The minimal API is to create a ListViewDataSource from clarity-react-infinite-list, populate it with an array of data, and add a ListView component 95 | with that data source and a renderRow callback which takes an item from the data source and returns a renderable component.

96 |

Install

npm install clarity-react-infinite-list

Demos

Github API Data

97 |

Features

    98 |
  • Lazy load and fetch data from API requests in batches.
  • 99 |
  • Infinite number of items and batches
  • 100 |
  • Items can have dynamic heights and sizes, that do not have to be declared before hand.
  • 101 |
  • Add in a custom loading component.
  • 102 |
103 |

Dependencies

Version 15.x.x

    104 |
  • react
  • 105 |
  • react-dom
  • 106 |
107 |

Minimal Example

import React, { Component } from "react";
108 | import { connect } from "react-redux";
109 | import { getUsersBatch, setFetchingUsersStatus } from "../../actions";
110 | import { ListView, ListViewDataSource } from "clarity-react-infinite-list";
111 | import ListItem from "../layouts/ListItem";
112 | 
113 | const styles = {...};
114 | 
115 | class Main extends Component {
116 |     constructor(props) {
117 |         super(props);
118 | 
119 |         this.state = {
120 |             dataSource: new ListViewDataSource(30),
121 |             lastUserId: 0
122 |         };
123 | 
124 |         this._renderRow = this._renderRow.bind(this);
125 |         this._onEndReached = this._onEndReached.bind(this);
126 |         this._loadingComponent = this._loadingComponent.bind(this);
127 |     }
128 | 
129 |     _renderRow(rowData, rowId) {
130 |         return (
131 |             <ListItem key={rowId} rowData={rowData} rowId={rowId} />
132 |         );
133 |     }
134 | 
135 |     _onEndReached() {
136 |         if (!this.props.isFetchingUsers) {
137 |             this.props.setFetchingUsersStatus(true);
138 |             this.props.getUsersBatch(this.state.lastUserId);
139 |         }
140 |     }
141 | 
142 |     _loadingComponent() {
143 |         return (
144 |             <div style={styles.loading}>Loading...</div>
145 |         );
146 |     }
147 | 
148 |     componentWillMount() {
149 |         this.props.setFetchingUsersStatus(true);
150 |         this.props.getUsersBatch(this.state.lastUserId);
151 |     }
152 | 
153 |     componentWillReceiveProps(nextProps) {
154 |         if (nextProps.users[nextProps.users.length - 1] && this.state.lastUserId !== nextProps.users[nextProps.users.length - 1].id) {
155 |             this.setState({
156 |                 dataSource: this.state.dataSource.cloneWithRows(nextProps.users),
157 |                 lastUserId: nextProps.users[nextProps.users.length - 1].id,
158 |             });
159 |         }
160 |     }
161 | 
162 |     render() {
163 |         return (
164 |             <div style={styles.container}>
165 |                 <div style={styles.header}>
166 |                     Clarity React Infinite Scroll Example
167 |                 </div>
168 |                 <ListView style={styles.listView}
169 |                     dataSource={this.state.dataSource}
170 |                     renderRow={this._renderRow}
171 |                     onEndReached={this._onEndReached}
172 |                     loadingComponent={this._loadingComponent}
173 |                     onEndReachedThreshold={5000}
174 |                     ref={listView => this.listView = listView} />
175 |             </div>
176 |         );
177 |     }
178 | }
179 | 
180 | const mapStateToProps = (state) => {
181 |     return {
182 |         users: state.users,
183 |         isFetchingUsers: state.isFetchingUsers
184 |     };
185 | };
186 | 
187 | const mapDispatchToProps = {
188 |     getUsersBatch,
189 |     setFetchingUsersStatus
190 | };
191 | 
192 | export default connect(mapStateToProps, mapDispatchToProps)(Main);

Props

dataSource ListViewDataSource

    193 |
  • An instance of ListViewDataSourceto use.
  • 194 |
195 |

renderRow function(rowData, rowId) => renderableComponent

    196 |
  • Takes a data entry from the data source and its id and should return a renderable component to be rendered as the row.
  • 197 |
198 |

onEndReached function()

    199 |
  • Called when the list has been scrolled to within the onEndReachedThreshold of the bottom.
  • 200 |
201 |

loadingComponent function() => renderableComponent

    202 |
  • Should return a renderable component, to be displayed at bottom of list when loading new batches.
  • 203 |
204 |

onEndReachedThreshold number

    205 |
  • Threshold in pixels for calling onEndReached
  • 206 |
207 |

Methods

scrollTo(topPosition: number)

    208 |
  • Scrolls to the given topPosition of the ListView.
  • 209 |
210 |

isScrollbarActive()

    211 |
  • Returns a boolean of whether or not the ListView has enough content to have an active vertical scrollbar.
  • 212 |
213 |

digBatches()

    214 |
  • Manually dig batches from the props.onEndReached function.
  • 215 |
216 |
217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 |
225 |
226 | 227 |
228 | 229 | 230 |
231 | 232 |
233 | 234 | 235 |
236 |
237 | 238 | 239 | 253 | 254 | 255 |
256 | 257 | 258 | 259 | Documentation generated by JSDoc 3.4.3 260 | 261 | on October 27th 2017, 3:19:51 pm 262 | 263 | using the DocStrap template. 264 | 265 |
266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 349 | 350 | 351 | 352 | -------------------------------------------------------------------------------- /docs/gen/quicksearch.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/gen/scripts/fulltext-search-ui.js: -------------------------------------------------------------------------------- 1 | window.SearcherDisplay = (function($) { 2 | /** 3 | * This class provides support for displaying quick search text results to users. 4 | */ 5 | function SearcherDisplay() { } 6 | 7 | SearcherDisplay.prototype.init = function() { 8 | this._displayQuickSearch(); 9 | }; 10 | 11 | /** 12 | * This method creates the quick text search entry in navigation menu and wires all required events. 13 | */ 14 | SearcherDisplay.prototype._displayQuickSearch = function() { 15 | var quickSearch = $(document.createElement("iframe")), 16 | body = $("body"), 17 | self = this; 18 | 19 | quickSearch.attr("src", "quicksearch.html"); 20 | quickSearch.css("width", "0px"); 21 | quickSearch.css("height", "0px"); 22 | 23 | body.append(quickSearch); 24 | 25 | $(window).on("message", function(msg) { 26 | var msgData = msg.originalEvent.data; 27 | 28 | if (msgData.msgid != "docstrap.quicksearch.done") { 29 | return; 30 | } 31 | 32 | var results = msgData.results || []; 33 | 34 | self._displaySearchResults(results); 35 | }); 36 | 37 | function startSearch() { 38 | var searchTerms = $('#search-input').prop("value"); 39 | if (searchTerms) { 40 | quickSearch[0].contentWindow.postMessage({ 41 | "searchTerms": searchTerms, 42 | "msgid": "docstrap.quicksearch.start" 43 | }, "*"); 44 | } 45 | } 46 | 47 | $('#search-input').on('keyup', function(evt) { 48 | if (evt.keyCode != 13) { 49 | return; 50 | } 51 | startSearch(); 52 | return false; 53 | }); 54 | $('#search-submit').on('click', function() { 55 | startSearch(); 56 | return false; 57 | }); 58 | }; 59 | 60 | /** 61 | * This method displays the quick text search results in a modal dialog. 62 | */ 63 | SearcherDisplay.prototype._displaySearchResults = function(results) { 64 | var resultsHolder = $($("#searchResults").find(".modal-body")), 65 | fragment = document.createDocumentFragment(), 66 | resultsList = document.createElement("ul"); 67 | 68 | resultsHolder.empty(); 69 | 70 | for (var idx = 0; idx < results.length; idx++) { 71 | var result = results[idx], 72 | item = document.createElement("li"), 73 | link = document.createElement("a"); 74 | 75 | link.href = result.id; 76 | link.innerHTML = result.title; 77 | 78 | item.appendChild(link) 79 | resultsList.appendChild(item); 80 | } 81 | 82 | fragment.appendChild(resultsList); 83 | resultsHolder.append(fragment); 84 | 85 | $("#searchResults").modal({"show": true}); 86 | }; 87 | 88 | return new SearcherDisplay(); 89 | })($); 90 | -------------------------------------------------------------------------------- /docs/gen/scripts/fulltext-search.js: -------------------------------------------------------------------------------- 1 | window.Searcher = (function() { 2 | function Searcher() { 3 | this._index = lunr(function () { 4 | this.field('title', {boost: 10}) 5 | this.field('body') 6 | this.ref('id') 7 | }) ; 8 | 9 | this._indexContent = undefined; 10 | } 11 | 12 | Searcher.prototype.init = function() { 13 | var self = this; 14 | 15 | $("script[type='text/x-docstrap-searchdb']").each(function(idx, item) { 16 | self._indexContent = JSON.parse(item.innerHTML); 17 | 18 | for (var entryId in self._indexContent) { 19 | self._index.add(self._indexContent[entryId]); 20 | } 21 | }); 22 | }; 23 | 24 | Searcher.prototype.search = function(searchTerm) { 25 | var results = [], 26 | searchResults = this._index.search(searchTerm); 27 | 28 | for (var idx = 0; idx < searchResults.length; idx++) { 29 | results.push(this._indexContent[searchResults[idx].ref]) 30 | } 31 | 32 | return results; 33 | }; 34 | 35 | return new Searcher(); 36 | })(); -------------------------------------------------------------------------------- /docs/gen/scripts/lunr.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.7.1 3 | * Copyright (C) 2016 Oliver Nightingale 4 | * @license MIT 5 | */ 6 | !function(){var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.7.1",t.utils={},t.utils.warn=function(t){return function(e){t.console&&console.warn&&console.warn(e)}}(this),t.utils.asString=function(t){return void 0===t||null===t?"":t.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var t=Array.prototype.slice.call(arguments),e=t.pop(),n=t;if("function"!=typeof e)throw new TypeError("last argument must be a function");n.forEach(function(t){this.hasHandler(t)||(this.events[t]=[]),this.events[t].push(e)},this)},t.EventEmitter.prototype.removeListener=function(t,e){if(this.hasHandler(t)){var n=this.events[t].indexOf(e);this.events[t].splice(n,1),this.events[t].length||delete this.events[t]}},t.EventEmitter.prototype.emit=function(t){if(this.hasHandler(t)){var e=Array.prototype.slice.call(arguments,1);this.events[t].forEach(function(t){t.apply(void 0,e)})}},t.EventEmitter.prototype.hasHandler=function(t){return t in this.events},t.tokenizer=function(e){return arguments.length&&null!=e&&void 0!=e?Array.isArray(e)?e.map(function(e){return t.utils.asString(e).toLowerCase()}):e.toString().trim().toLowerCase().split(t.tokenizer.seperator):[]},t.tokenizer.seperator=/[\s\-]+/,t.tokenizer.load=function(t){var e=this.registeredFunctions[t];if(!e)throw new Error("Cannot load un-registered function: "+t);return e},t.tokenizer.label="default",t.tokenizer.registeredFunctions={"default":t.tokenizer},t.tokenizer.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing tokenizer: "+n),e.label=n,this.registeredFunctions[n]=e},t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.registeredFunctions[e];if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");i+=1,this._stack.splice(i,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");this._stack.splice(i,0,n)},t.Pipeline.prototype.remove=function(t){var e=this._stack.indexOf(t);-1!=e&&this._stack.splice(e,1)},t.Pipeline.prototype.run=function(t){for(var e=[],n=t.length,i=this._stack.length,r=0;n>r;r++){for(var o=t[r],s=0;i>s&&(o=this._stack[s](o,r,t),void 0!==o&&""!==o);s++);void 0!==o&&""!==o&&e.push(o)}return e},t.Pipeline.prototype.reset=function(){this._stack=[]},t.Pipeline.prototype.toJSON=function(){return this._stack.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Vector=function(){this._magnitude=null,this.list=void 0,this.length=0},t.Vector.Node=function(t,e,n){this.idx=t,this.val=e,this.next=n},t.Vector.prototype.insert=function(e,n){this._magnitude=void 0;var i=this.list;if(!i)return this.list=new t.Vector.Node(e,n,i),this.length++;if(en.idx?n=n.next:(i+=e.val*n.val,e=e.next,n=n.next);return i},t.Vector.prototype.similarity=function(t){return this.dot(t)/(this.magnitude()*t.magnitude())},t.SortedSet=function(){this.length=0,this.elements=[]},t.SortedSet.load=function(t){var e=new this;return e.elements=t,e.length=t.length,e},t.SortedSet.prototype.add=function(){var t,e;for(t=0;t1;){if(o===t)return r;t>o&&(e=r),o>t&&(n=r),i=n-e,r=e+Math.floor(i/2),o=this.elements[r]}return o===t?r:-1},t.SortedSet.prototype.locationFor=function(t){for(var e=0,n=this.elements.length,i=n-e,r=e+Math.floor(i/2),o=this.elements[r];i>1;)t>o&&(e=r),o>t&&(n=r),i=n-e,r=e+Math.floor(i/2),o=this.elements[r];return o>t?r:t>o?r+1:void 0},t.SortedSet.prototype.intersect=function(e){for(var n=new t.SortedSet,i=0,r=0,o=this.length,s=e.length,a=this.elements,h=e.elements;;){if(i>o-1||r>s-1)break;a[i]!==h[r]?a[i]h[r]&&r++:(n.add(a[i]),i++,r++)}return n},t.SortedSet.prototype.clone=function(){var e=new t.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},t.SortedSet.prototype.union=function(t){var e,n,i;this.length>=t.length?(e=this,n=t):(e=t,n=this),i=e.clone();for(var r=0,o=n.toArray();rp;p++)c[p]===a&&d++;h+=d/f*l.boost}}this.tokenStore.add(a,{ref:o,tf:h})}n&&this.eventEmitter.emit("add",e,this)},t.Index.prototype.remove=function(t,e){var n=t[this._ref],e=void 0===e?!0:e;if(this.documentStore.has(n)){var i=this.documentStore.get(n);this.documentStore.remove(n),i.forEach(function(t){this.tokenStore.remove(t,n)},this),e&&this.eventEmitter.emit("remove",t,this)}},t.Index.prototype.update=function(t,e){var e=void 0===e?!0:e;this.remove(t,!1),this.add(t,!1),e&&this.eventEmitter.emit("update",t,this)},t.Index.prototype.idf=function(t){var e="@"+t;if(Object.prototype.hasOwnProperty.call(this._idfCache,e))return this._idfCache[e];var n=this.tokenStore.count(t),i=1;return n>0&&(i=1+Math.log(this.documentStore.length/n)),this._idfCache[e]=i},t.Index.prototype.search=function(e){var n=this.pipeline.run(this.tokenizerFn(e)),i=new t.Vector,r=[],o=this._fields.reduce(function(t,e){return t+e.boost},0),s=n.some(function(t){return this.tokenStore.has(t)},this);if(!s)return[];n.forEach(function(e,n,s){var a=1/s.length*this._fields.length*o,h=this,u=this.tokenStore.expand(e).reduce(function(n,r){var o=h.corpusTokens.indexOf(r),s=h.idf(r),u=1,l=new t.SortedSet;if(r!==e){var c=Math.max(3,r.length-e.length);u=1/Math.log(c)}o>-1&&i.insert(o,a*s*u);for(var f=h.tokenStore.get(r),d=Object.keys(f),p=d.length,v=0;p>v;v++)l.add(f[d[v]].ref);return n.union(l)},new t.SortedSet);r.push(u)},this);var a=r.reduce(function(t,e){return t.intersect(e)});return a.map(function(t){return{ref:t,score:i.similarity(this.documentVector(t))}},this).sort(function(t,e){return e.score-t.score})},t.Index.prototype.documentVector=function(e){for(var n=this.documentStore.get(e),i=n.length,r=new t.Vector,o=0;i>o;o++){var s=n.elements[o],a=this.tokenStore.get(s)[e].tf,h=this.idf(s);r.insert(this.corpusTokens.indexOf(s),a*h)}return r},t.Index.prototype.toJSON=function(){return{version:t.version,fields:this._fields,ref:this._ref,tokenizer:this.tokenizerFn.label,documentStore:this.documentStore.toJSON(),tokenStore:this.tokenStore.toJSON(),corpusTokens:this.corpusTokens.toJSON(),pipeline:this.pipeline.toJSON()}},t.Index.prototype.use=function(t){var e=Array.prototype.slice.call(arguments,1);e.unshift(this),t.apply(this,e)},t.Store=function(){this.store={},this.length=0},t.Store.load=function(e){var n=new this;return n.length=e.length,n.store=Object.keys(e.store).reduce(function(n,i){return n[i]=t.SortedSet.load(e.store[i]),n},{}),n},t.Store.prototype.set=function(t,e){this.has(t)||this.length++,this.store[t]=e},t.Store.prototype.get=function(t){return this.store[t]},t.Store.prototype.has=function(t){return t in this.store},t.Store.prototype.remove=function(t){this.has(t)&&(delete this.store[t],this.length--)},t.Store.prototype.toJSON=function(){return{store:this.store,length:this.length}},t.stemmer=function(){var t={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},e={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",r=n+"[^aeiouy]*",o=i+"[aeiou]*",s="^("+r+")?"+o+r,a="^("+r+")?"+o+r+"("+o+")?$",h="^("+r+")?"+o+r+o+r,u="^("+r+")?"+i,l=new RegExp(s),c=new RegExp(h),f=new RegExp(a),d=new RegExp(u),p=/^(.+?)(ss|i)es$/,v=/^(.+?)([^s])s$/,g=/^(.+?)eed$/,m=/^(.+?)(ed|ing)$/,y=/.$/,S=/(at|bl|iz)$/,w=new RegExp("([^aeiouylsz])\\1$"),k=new RegExp("^"+r+i+"[^aeiouwxy]$"),x=/^(.+?[^aeiou])y$/,b=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,E=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,F=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,_=/^(.+?)(s|t)(ion)$/,z=/^(.+?)e$/,O=/ll$/,P=new RegExp("^"+r+i+"[^aeiouwxy]$"),T=function(n){var i,r,o,s,a,h,u;if(n.length<3)return n;if(o=n.substr(0,1),"y"==o&&(n=o.toUpperCase()+n.substr(1)),s=p,a=v,s.test(n)?n=n.replace(s,"$1$2"):a.test(n)&&(n=n.replace(a,"$1$2")),s=g,a=m,s.test(n)){var T=s.exec(n);s=l,s.test(T[1])&&(s=y,n=n.replace(s,""))}else if(a.test(n)){var T=a.exec(n);i=T[1],a=d,a.test(i)&&(n=i,a=S,h=w,u=k,a.test(n)?n+="e":h.test(n)?(s=y,n=n.replace(s,"")):u.test(n)&&(n+="e"))}if(s=x,s.test(n)){var T=s.exec(n);i=T[1],n=i+"i"}if(s=b,s.test(n)){var T=s.exec(n);i=T[1],r=T[2],s=l,s.test(i)&&(n=i+t[r])}if(s=E,s.test(n)){var T=s.exec(n);i=T[1],r=T[2],s=l,s.test(i)&&(n=i+e[r])}if(s=F,a=_,s.test(n)){var T=s.exec(n);i=T[1],s=c,s.test(i)&&(n=i)}else if(a.test(n)){var T=a.exec(n);i=T[1]+T[2],a=c,a.test(i)&&(n=i)}if(s=z,s.test(n)){var T=s.exec(n);i=T[1],s=c,a=f,h=P,(s.test(i)||a.test(i)&&!h.test(i))&&(n=i)}return s=O,a=c,s.test(n)&&a.test(n)&&(s=y,n=n.replace(s,"")),"y"==o&&(n=o.toLowerCase()+n.substr(1)),n};return T}(),t.Pipeline.registerFunction(t.stemmer,"stemmer"),t.generateStopWordFilter=function(t){var e=t.reduce(function(t,e){return t[e]=e,t},{});return function(t){return t&&e[t]!==t?t:void 0}},t.stopWordFilter=t.generateStopWordFilter(["a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your"]),t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter"),t.trimmer=function(t){return t.replace(/^\W+/,"").replace(/\W+$/,"")},t.Pipeline.registerFunction(t.trimmer,"trimmer"),t.TokenStore=function(){this.root={docs:{}},this.length=0},t.TokenStore.load=function(t){var e=new this;return e.root=t.root,e.length=t.length,e},t.TokenStore.prototype.add=function(t,e,n){var n=n||this.root,i=t.charAt(0),r=t.slice(1);return i in n||(n[i]={docs:{}}),0===r.length?(n[i].docs[e.ref]=e,void(this.length+=1)):this.add(r,e,n[i])},t.TokenStore.prototype.has=function(t){if(!t)return!1;for(var e=this.root,n=0;n)/], 11 | ["lit", /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i], 12 | ["lit", /^#[\da-f]{3,6}/i], 13 | ["pln", /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i], 14 | ["pun", /^[^\s\w"']+/] 15 | ]), ["css"]); 16 | PR.registerLangHandler(PR.createSimpleLexer([], [ 17 | ["kwd", /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i] 18 | ]), ["css-kw"]); 19 | PR.registerLangHandler(PR.createSimpleLexer([], [ 20 | ["str", /^[^"')]+/] 21 | ]), ["css-str"]); -------------------------------------------------------------------------------- /docs/gen/scripts/prettify/prettify.js: -------------------------------------------------------------------------------- 1 | var q = null; 2 | window.PR_SHOULD_USE_CONTINUATION = !0; 3 | (function() { 4 | function L(a) { 5 | function m(a) { 6 | var f = a.charCodeAt(0); 7 | if (f !== 92) return f; 8 | var b = a.charAt(1); 9 | return (f = r[b]) ? f : "0" <= b && b <= "7" ? parseInt(a.substring(1), 8) : b === "u" || b === "x" ? parseInt(a.substring(2), 16) : a.charCodeAt(1) 10 | } 11 | 12 | function e(a) { 13 | if (a < 32) return (a < 16 ? "\\x0" : "\\x") + a.toString(16); 14 | a = String.fromCharCode(a); 15 | if (a === "\\" || a === "-" || a === "[" || a === "]") a = "\\" + a; 16 | return a 17 | } 18 | 19 | function h(a) { 20 | for (var f = a.substring(1, a.length - 1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g), a = [], b = [], o = f[0] === "^", c = o ? 1 : 0, i = f.length; c < i; ++c) { 21 | var j = f[c]; 22 | if (/\\[bdsw]/i.test(j)) a.push(j); 23 | else { 24 | var j = m(j), 25 | d; 26 | c + 2 < i && "-" === f[c + 1] ? (d = m(f[c + 2]), c += 2) : d = j; 27 | b.push([j, d]); 28 | d < 65 || j > 122 || (d < 65 || j > 90 || b.push([Math.max(65, j) | 32, Math.min(d, 90) | 32]), d < 97 || j > 122 || b.push([Math.max(97, j) & -33, Math.min(d, 122) & -33])) 29 | } 30 | } 31 | b.sort(function(a, f) { 32 | return a[0] - f[0] || f[1] - a[1] 33 | }); 34 | f = []; 35 | j = [NaN, NaN]; 36 | for (c = 0; c < b.length; ++c) i = b[c], i[0] <= j[1] + 1 ? j[1] = Math.max(j[1], i[1]) : f.push(j = i); 37 | b = ["["]; 38 | o && b.push("^"); 39 | b.push.apply(b, a); 40 | for (c = 0; c < f.length; ++c) i = f[c], b.push(e(i[0])), i[1] > i[0] && (i[1] + 1 > i[0] && b.push("-"), b.push(e(i[1]))); 41 | b.push("]"); 42 | return b.join("") 43 | } 44 | 45 | function y(a) { 46 | for (var f = a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g), b = f.length, d = [], c = 0, i = 0; c < b; ++c) { 47 | var j = f[c]; 48 | j === "(" ? ++i : "\\" === j.charAt(0) && (j = +j.substring(1)) && j <= i && (d[j] = -1) 49 | } 50 | for (c = 1; c < d.length; ++c) - 1 === d[c] && (d[c] = ++t); 51 | for (i = c = 0; c < b; ++c) j = f[c], j === "(" ? (++i, d[i] === void 0 && (f[c] = "(?:")) : "\\" === j.charAt(0) && (j = +j.substring(1)) && j <= i && (f[c] = "\\" + d[i]); 52 | for (i = c = 0; c < b; ++c)"^" === f[c] && "^" !== f[c + 1] && (f[c] = ""); 53 | if (a.ignoreCase && s) for (c = 0; c < b; ++c) j = f[c], a = j.charAt(0), j.length >= 2 && a === "[" ? f[c] = h(j) : a !== "\\" && (f[c] = j.replace(/[A-Za-z]/g, function(a) { 54 | a = a.charCodeAt(0); 55 | return "[" + String.fromCharCode(a & -33, a | 32) + "]" 56 | })); 57 | return f.join("") 58 | } 59 | for (var t = 0, s = !1, l = !1, p = 0, d = a.length; p < d; ++p) { 60 | var g = a[p]; 61 | if (g.ignoreCase) l = !0; 62 | else if (/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi, ""))) { 63 | s = !0; 64 | l = !1; 65 | break 66 | } 67 | } 68 | for (var r = { 69 | b: 8, 70 | t: 9, 71 | n: 10, 72 | v: 11, 73 | f: 12, 74 | r: 13 75 | }, n = [], p = 0, d = a.length; p < d; ++p) { 76 | g = a[p]; 77 | if (g.global || g.multiline) throw Error("" + g); 78 | n.push("(?:" + y(g) + ")") 79 | } 80 | return RegExp(n.join("|"), l ? "gi" : "g") 81 | } 82 | 83 | function M(a) { 84 | function m(a) { 85 | switch (a.nodeType) { 86 | case 1: 87 | if (e.test(a.className)) break; 88 | for (var g = a.firstChild; g; g = g.nextSibling) m(g); 89 | g = a.nodeName; 90 | if ("BR" === g || "LI" === g) h[s] = "\n", t[s << 1] = y++, t[s++ << 1 | 1] = a; 91 | break; 92 | case 3: 93 | case 4: 94 | g = a.nodeValue, g.length && (g = p ? g.replace(/\r\n?/g, "\n") : g.replace(/[\t\n\r ]+/g, " "), h[s] = g, t[s << 1] = y, y += g.length, t[s++ << 1 | 1] = a) 95 | } 96 | } 97 | var e = /(?:^|\s)nocode(?:\s|$)/, 98 | h = [], 99 | y = 0, 100 | t = [], 101 | s = 0, 102 | l; 103 | a.currentStyle ? l = a.currentStyle.whiteSpace : window.getComputedStyle && (l = document.defaultView.getComputedStyle(a, q).getPropertyValue("white-space")); 104 | var p = l && "pre" === l.substring(0, 3); 105 | m(a); 106 | return { 107 | a: h.join("").replace(/\n$/, ""), 108 | c: t 109 | } 110 | } 111 | 112 | function B(a, m, e, h) { 113 | m && (a = { 114 | a: m, 115 | d: a 116 | }, e(a), h.push.apply(h, a.e)) 117 | } 118 | 119 | function x(a, m) { 120 | function e(a) { 121 | for (var l = a.d, p = [l, "pln"], d = 0, g = a.a.match(y) || [], r = {}, n = 0, z = g.length; n < z; ++n) { 122 | var f = g[n], 123 | b = r[f], 124 | o = void 0, 125 | c; 126 | if (typeof b === "string") c = !1; 127 | else { 128 | var i = h[f.charAt(0)]; 129 | if (i) o = f.match(i[1]), b = i[0]; 130 | else { 131 | for (c = 0; c < t; ++c) if (i = m[c], o = f.match(i[1])) { 132 | b = i[0]; 133 | break 134 | } 135 | o || (b = "pln") 136 | } 137 | if ((c = b.length >= 5 && "lang-" === b.substring(0, 5)) && !(o && typeof o[1] === "string")) c = !1, b = "src"; 138 | c || (r[f] = b) 139 | } 140 | i = d; 141 | d += f.length; 142 | if (c) { 143 | c = o[1]; 144 | var j = f.indexOf(c), 145 | k = j + c.length; 146 | o[2] && (k = f.length - o[2].length, j = k - c.length); 147 | b = b.substring(5); 148 | B(l + i, f.substring(0, j), e, p); 149 | B(l + i + j, c, C(b, c), p); 150 | B(l + i + k, f.substring(k), e, p) 151 | } else p.push(l + i, b) 152 | } 153 | a.e = p 154 | } 155 | var h = {}, 156 | y; 157 | (function() { 158 | for (var e = a.concat(m), l = [], p = {}, d = 0, g = e.length; d < g; ++d) { 159 | var r = e[d], 160 | n = r[3]; 161 | if (n) for (var k = n.length; --k >= 0;) h[n.charAt(k)] = r; 162 | r = r[1]; 163 | n = "" + r; 164 | p.hasOwnProperty(n) || (l.push(r), p[n] = q) 165 | } 166 | l.push(/[\S\s]/); 167 | y = L(l) 168 | })(); 169 | var t = m.length; 170 | return e 171 | } 172 | 173 | function u(a) { 174 | var m = [], 175 | e = []; 176 | a.tripleQuotedStrings ? m.push(["str", /^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/, q, "'\""]) : a.multiLineStrings ? m.push(["str", /^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, q, "'\"`"]) : m.push(["str", /^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/, q, "\"'"]); 177 | a.verbatimStrings && e.push(["str", /^@"(?:[^"]|"")*(?:"|$)/, q]); 178 | var h = a.hashComments; 179 | h && (a.cStyleComments ? (h > 1 ? m.push(["com", /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, q, "#"]) : m.push(["com", /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/, q, "#"]), e.push(["str", /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/, q])) : m.push(["com", /^#[^\n\r]*/, q, "#"])); 180 | a.cStyleComments && (e.push(["com", /^\/\/[^\n\r]*/, q]), e.push(["com", /^\/\*[\S\s]*?(?:\*\/|$)/, q])); 181 | a.regexLiterals && e.push(["lang-regex", /^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]); 182 | (h = a.types) && e.push(["typ", h]); 183 | a = ("" + a.keywords).replace(/^ | $/g, ""); 184 | a.length && e.push(["kwd", RegExp("^(?:" + a.replace(/[\s,]+/g, "|") + ")\\b"), q]); 185 | m.push(["pln", /^\s+/, q, " \r\n\t\xa0"]); 186 | e.push(["lit", /^@[$_a-z][\w$@]*/i, q], ["typ", /^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/, q], ["pln", /^[$_a-z][\w$@]*/i, q], ["lit", /^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i, q, "0123456789"], ["pln", /^\\[\S\s]?/, q], ["pun", /^.[^\s\w"-$'./@\\`]*/, q]); 187 | return x(m, e) 188 | } 189 | 190 | function D(a, m) { 191 | function e(a) { 192 | switch (a.nodeType) { 193 | case 1: 194 | if (k.test(a.className)) break; 195 | if ("BR" === a.nodeName) h(a), a.parentNode && a.parentNode.removeChild(a); 196 | else for (a = a.firstChild; a; a = a.nextSibling) e(a); 197 | break; 198 | case 3: 199 | case 4: 200 | if (p) { 201 | var b = a.nodeValue, 202 | d = b.match(t); 203 | if (d) { 204 | var c = b.substring(0, d.index); 205 | a.nodeValue = c; 206 | (b = b.substring(d.index + d[0].length)) && a.parentNode.insertBefore(s.createTextNode(b), a.nextSibling); 207 | h(a); 208 | c || a.parentNode.removeChild(a) 209 | } 210 | } 211 | } 212 | } 213 | 214 | function h(a) { 215 | function b(a, d) { 216 | var e = d ? a.cloneNode(!1) : a, 217 | f = a.parentNode; 218 | if (f) { 219 | var f = b(f, 1), 220 | g = a.nextSibling; 221 | f.appendChild(e); 222 | for (var h = g; h; h = g) g = h.nextSibling, f.appendChild(h) 223 | } 224 | return e 225 | } 226 | for (; !a.nextSibling;) if (a = a.parentNode, !a) return; 227 | for (var a = b(a.nextSibling, 0), e; 228 | (e = a.parentNode) && e.nodeType === 1;) a = e; 229 | d.push(a) 230 | } 231 | var k = /(?:^|\s)nocode(?:\s|$)/, 232 | t = /\r\n?|\n/, 233 | s = a.ownerDocument, 234 | l; 235 | a.currentStyle ? l = a.currentStyle.whiteSpace : window.getComputedStyle && (l = s.defaultView.getComputedStyle(a, q).getPropertyValue("white-space")); 236 | var p = l && "pre" === l.substring(0, 3); 237 | for (l = s.createElement("LI"); a.firstChild;) l.appendChild(a.firstChild); 238 | for (var d = [l], g = 0; g < d.length; ++g) e(d[g]); 239 | m === (m | 0) && d[0].setAttribute("value", m); 240 | var r = s.createElement("OL"); 241 | r.className = "linenums"; 242 | for (var n = Math.max(0, m - 1 | 0) || 0, g = 0, z = d.length; g < z; ++g) l = d[g], l.className = "L" + (g + n) % 10, l.firstChild || l.appendChild(s.createTextNode("\xa0")), r.appendChild(l); 243 | a.appendChild(r) 244 | } 245 | 246 | function k(a, m) { 247 | for (var e = m.length; --e >= 0;) { 248 | var h = m[e]; 249 | A.hasOwnProperty(h) ? window.console && console.warn("cannot override language handler %s", h) : A[h] = a 250 | } 251 | } 252 | 253 | function C(a, m) { 254 | if (!a || !A.hasOwnProperty(a)) a = /^\s*= o && (h += 2); 309 | e >= c && (a += 2) 310 | } 311 | } catch (w) { 312 | "console" in window && console.log(w && w.stack ? w.stack : w) 313 | } 314 | } 315 | var v = ["break,continue,do,else,for,if,return,while"], 316 | w = [ 317 | [v, "auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"], 318 | F = [w, "alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"], 319 | G = [w, "abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 320 | H = [G, "as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"], 321 | w = [w, "debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"], 322 | I = [v, "and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 323 | J = [v, "alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"], 324 | v = [v, "case,done,elif,esac,eval,fi,function,in,local,set,then,until"], 325 | K = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/, 326 | N = /\S/, 327 | O = u({ 328 | keywords: [F, H, w, "caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END" + I, J, v], 329 | hashComments: !0, 330 | cStyleComments: !0, 331 | multiLineStrings: !0, 332 | regexLiterals: !0 333 | }), 334 | A = {}; 335 | k(O, ["default-code"]); 336 | k(x([], [ 337 | ["pln", /^[^]*(?:>|$)/], 339 | ["com", /^<\!--[\S\s]*?(?:--\>|$)/], 340 | ["lang-", /^<\?([\S\s]+?)(?:\?>|$)/], 341 | ["lang-", /^<%([\S\s]+?)(?:%>|$)/], 342 | ["pun", /^(?:<[%?]|[%?]>)/], 343 | ["lang-", /^]*>([\S\s]+?)<\/xmp\b[^>]*>/i], 344 | ["lang-js", /^]*>([\S\s]*?)(<\/script\b[^>]*>)/i], 345 | ["lang-css", /^]*>([\S\s]*?)(<\/style\b[^>]*>)/i], 346 | ["lang-in.tag", /^(<\/?[a-z][^<>]*>)/i] 347 | ]), ["default-markup", "htm", "html", "mxml", "xhtml", "xml", "xsl"]); 348 | k(x([ 349 | ["pln", /^\s+/, q, " \t\r\n"], 350 | ["atv", /^(?:"[^"]*"?|'[^']*'?)/, q, "\"'"] 351 | ], [ 352 | ["tag", /^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i], 353 | ["atn", /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i], 354 | ["lang-uq.val", /^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/], 355 | ["pun", /^[/<->]+/], 356 | ["lang-js", /^on\w+\s*=\s*"([^"]+)"/i], 357 | ["lang-js", /^on\w+\s*=\s*'([^']+)'/i], 358 | ["lang-js", /^on\w+\s*=\s*([^\s"'>]+)/i], 359 | ["lang-css", /^style\s*=\s*"([^"]+)"/i], 360 | ["lang-css", /^style\s*=\s*'([^']+)'/i], 361 | ["lang-css", /^style\s*=\s*([^\s"'>]+)/i] 362 | ]), ["in.tag"]); 363 | k(x([], [ 364 | ["atv", /^[\S\s]+/] 365 | ]), ["uq.val"]); 366 | k(u({ 367 | keywords: F, 368 | hashComments: !0, 369 | cStyleComments: !0, 370 | types: K 371 | }), ["c", "cc", "cpp", "cxx", "cyc", "m"]); 372 | k(u({ 373 | keywords: "null,true,false" 374 | }), ["json"]); 375 | k(u({ 376 | keywords: H, 377 | hashComments: !0, 378 | cStyleComments: !0, 379 | verbatimStrings: !0, 380 | types: K 381 | }), ["cs"]); 382 | k(u({ 383 | keywords: G, 384 | cStyleComments: !0 385 | }), ["java"]); 386 | k(u({ 387 | keywords: v, 388 | hashComments: !0, 389 | multiLineStrings: !0 390 | }), ["bsh", "csh", "sh"]); 391 | k(u({ 392 | keywords: I, 393 | hashComments: !0, 394 | multiLineStrings: !0, 395 | tripleQuotedStrings: !0 396 | }), ["cv", "py"]); 397 | k(u({ 398 | keywords: "caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END", 399 | hashComments: !0, 400 | multiLineStrings: !0, 401 | regexLiterals: !0 402 | }), ["perl", "pl", "pm"]); 403 | k(u({ 404 | keywords: J, 405 | hashComments: !0, 406 | multiLineStrings: !0, 407 | regexLiterals: !0 408 | }), ["rb"]); 409 | k(u({ 410 | keywords: w, 411 | cStyleComments: !0, 412 | regexLiterals: !0 413 | }), ["js"]); 414 | k(u({ 415 | keywords: "all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 416 | hashComments: 3, 417 | cStyleComments: !0, 418 | multilineStrings: !0, 419 | tripleQuotedStrings: !0, 420 | regexLiterals: !0 421 | }), ["coffee"]); 422 | k(x([], [ 423 | ["str", /^[\S\s]+/] 424 | ]), ["regex"]); 425 | window.prettyPrintOne = function(a, m, e) { 426 | var h = document.createElement("PRE"); 427 | h.innerHTML = a; 428 | e && D(h, e); 429 | E({ 430 | g: m, 431 | i: e, 432 | h: h 433 | }); 434 | return h.innerHTML 435 | }; 436 | window.prettyPrint = function(a) { 437 | function m() { 438 | for (var e = window.PR_SHOULD_USE_CONTINUATION ? l.now() + 250 : Infinity; p < h.length && l.now() < e; p++) { 439 | var n = h[p], 440 | k = n.className; 441 | if (k.indexOf("prettyprint") >= 0) { 442 | var k = k.match(g), 443 | f, b; 444 | if (b = !k) { 445 | b = n; 446 | for (var o = void 0, c = b.firstChild; c; c = c.nextSibling) var i = c.nodeType, 447 | o = i === 1 ? o ? b : c : i === 3 ? N.test(c.nodeValue) ? b : o : o; 448 | b = (f = o === b ? void 0 : o) && "CODE" === f.tagName 449 | } 450 | b && (k = f.className.match(g)); 451 | k && (k = k[1]); 452 | b = !1; 453 | for (o = n.parentNode; o; o = o.parentNode) if ((o.tagName === "pre" || o.tagName === "code" || o.tagName === "xmp") && o.className && o.className.indexOf("prettyprint") >= 0) { 454 | b = !0; 455 | break 456 | } 457 | b || ((b = (b = n.className.match(/\blinenums\b(?::(\d+))?/)) ? b[1] && b[1].length ? +b[1] : !0 : !1) && D(n, b), d = { 458 | g: k, 459 | h: n, 460 | i: b 461 | }, E(d)) 462 | } 463 | } 464 | p < h.length ? setTimeout(m, 250) : a && a() 465 | } 466 | for (var e = [document.getElementsByTagName("pre"), document.getElementsByTagName("code"), document.getElementsByTagName("xmp")], h = [], k = 0; k < e.length; ++k) for (var t = 0, s = e[k].length; t < s; ++t) h.push(e[k][t]); 467 | var e = q, 468 | l = Date; 469 | l.now || (l = { 470 | now: function() { 471 | return +new Date 472 | } 473 | }); 474 | var p = 0, 475 | d, g = /\blang(?:uage)?-([\w.]+)(?!\S)/; 476 | m() 477 | }; 478 | window.PR = { 479 | createSimpleLexer: x, 480 | registerLangHandler: k, 481 | sourceDecorator: u, 482 | PR_ATTRIB_NAME: "atn", 483 | PR_ATTRIB_VALUE: "atv", 484 | PR_COMMENT: "com", 485 | PR_DECLARATION: "dec", 486 | PR_KEYWORD: "kwd", 487 | PR_LITERAL: "lit", 488 | PR_NOCODE: "nocode", 489 | PR_PLAIN: "pln", 490 | PR_PUNCTUATION: "pun", 491 | PR_SOURCE: "src", 492 | PR_STRING: "str", 493 | PR_TAG: "tag", 494 | PR_TYPE: "typ" 495 | } 496 | })(); -------------------------------------------------------------------------------- /docs/gen/scripts/sunlight.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sunlight 3 | * Intelligent syntax highlighting 4 | * 5 | * http://sunlightjs.com/ 6 | * 7 | * by Tommy Montgomery 8 | * Licensed under WTFPL 9 | */ 10 | (function(window, document, undefined){ 11 | 12 | var 13 | //http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html 14 | //we have to sniff this because IE requires \r 15 | isIe = !+"\v1", 16 | EOL = isIe ? "\r" : "\n", 17 | EMPTY = function() { return null; }, 18 | HIGHLIGHTED_NODE_COUNT = 0, 19 | DEFAULT_LANGUAGE = "plaintext", 20 | DEFAULT_CLASS_PREFIX = "sunlight-", 21 | 22 | //global sunlight variables 23 | defaultAnalyzer, 24 | getComputedStyle, 25 | globalOptions = { 26 | tabWidth: 4, 27 | classPrefix: DEFAULT_CLASS_PREFIX, 28 | showWhitespace: false, 29 | maxHeight: false 30 | }, 31 | languages = {}, 32 | languageDefaults = {}, 33 | events = { 34 | beforeHighlightNode: [], 35 | beforeHighlight: [], 36 | beforeTokenize: [], 37 | afterTokenize: [], 38 | beforeAnalyze: [], 39 | afterAnalyze: [], 40 | afterHighlight: [], 41 | afterHighlightNode: [] 42 | }; 43 | 44 | defaultAnalyzer = (function() { 45 | function defaultHandleToken(suffix) { 46 | return function(context) { 47 | var element = document.createElement("span"); 48 | element.className = context.options.classPrefix + suffix; 49 | element.appendChild(context.createTextNode(context.tokens[context.index])); 50 | return context.addNode(element) || true; 51 | }; 52 | } 53 | 54 | return { 55 | handleToken: function(context) { 56 | return defaultHandleToken(context.tokens[context.index].name)(context); 57 | }, 58 | 59 | //just append default content as a text node 60 | handle_default: function(context) { 61 | return context.addNode(context.createTextNode(context.tokens[context.index])); 62 | }, 63 | 64 | //this handles the named ident mayhem 65 | handle_ident: function(context) { 66 | var evaluate = function(rules, createRule) { 67 | var i; 68 | rules = rules || []; 69 | for (i = 0; i < rules.length; i++) { 70 | if (typeof(rules[i]) === "function") { 71 | if (rules[i](context)) { 72 | return defaultHandleToken("named-ident")(context); 73 | } 74 | } else if (createRule && createRule(rules[i])(context.tokens)) { 75 | return defaultHandleToken("named-ident")(context); 76 | } 77 | } 78 | 79 | return false; 80 | }; 81 | 82 | return evaluate(context.language.namedIdentRules.custom) 83 | || evaluate(context.language.namedIdentRules.follows, function(ruleData) { return createProceduralRule(context.index - 1, -1, ruleData, context.language.caseInsensitive); }) 84 | || evaluate(context.language.namedIdentRules.precedes, function(ruleData) { return createProceduralRule(context.index + 1, 1, ruleData, context.language.caseInsensitive); }) 85 | || evaluate(context.language.namedIdentRules.between, function(ruleData) { return createBetweenRule(context.index, ruleData.opener, ruleData.closer, context.language.caseInsensitive); }) 86 | || defaultHandleToken("ident")(context); 87 | } 88 | }; 89 | }()); 90 | 91 | languageDefaults = { 92 | analyzer: create(defaultAnalyzer), 93 | customTokens: [], 94 | namedIdentRules: {}, 95 | punctuation: /[^\w\s]/, 96 | numberParser: defaultNumberParser, 97 | caseInsensitive: false, 98 | doNotParse: /\s/, 99 | contextItems: {}, 100 | embeddedLanguages: {} 101 | }; 102 | 103 | //adapted from http://blargh.tommymontgomery.com/2010/04/get-computed-style-in-javascript/ 104 | getComputedStyle = (function() { 105 | var func = null; 106 | if (document.defaultView && document.defaultView.getComputedStyle) { 107 | func = document.defaultView.getComputedStyle; 108 | } else { 109 | func = function(element, anything) { 110 | return element["currentStyle"] || {}; 111 | }; 112 | } 113 | 114 | return function(element, style) { 115 | return func(element, null)[style]; 116 | } 117 | }()); 118 | 119 | //----------- 120 | //FUNCTIONS 121 | //----------- 122 | 123 | function createCodeReader(text) { 124 | var index = 0, 125 | line = 1, 126 | column = 1, 127 | length, 128 | EOF = undefined, 129 | currentChar, 130 | nextReadBeginsLine; 131 | 132 | text = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n"); //normalize line endings to unix 133 | 134 | length = text.length; 135 | currentChar = length > 0 ? text.charAt(0) : EOF; 136 | 137 | function getCharacters(count) { 138 | var value; 139 | if (count === 0) { 140 | return ""; 141 | } 142 | 143 | count = count || 1; 144 | 145 | value = text.substring(index + 1, index + count + 1); 146 | return value === "" ? EOF : value; 147 | } 148 | 149 | return { 150 | toString: function() { 151 | return "length: " + length + ", index: " + index + ", line: " + line + ", column: " + column + ", current: [" + currentChar + "]"; 152 | }, 153 | 154 | peek: function(count) { 155 | return getCharacters(count); 156 | }, 157 | 158 | substring: function() { 159 | return text.substring(index); 160 | }, 161 | 162 | peekSubstring: function() { 163 | return text.substring(index + 1); 164 | }, 165 | 166 | read: function(count) { 167 | var value = getCharacters(count), 168 | newlineCount, 169 | lastChar; 170 | 171 | if (value === "") { 172 | //this is a result of reading/peeking/doing nothing 173 | return value; 174 | } 175 | 176 | if (value !== EOF) { 177 | //advance index 178 | index += value.length; 179 | column += value.length; 180 | 181 | //update line count 182 | if (nextReadBeginsLine) { 183 | line++; 184 | column = 1; 185 | nextReadBeginsLine = false; 186 | } 187 | 188 | newlineCount = value.substring(0, value.length - 1).replace(/[^\n]/g, "").length; 189 | if (newlineCount > 0) { 190 | line += newlineCount; 191 | column = 1; 192 | } 193 | 194 | lastChar = last(value); 195 | if (lastChar === "\n") { 196 | nextReadBeginsLine = true; 197 | } 198 | 199 | currentChar = lastChar; 200 | } else { 201 | index = length; 202 | currentChar = EOF; 203 | } 204 | 205 | return value; 206 | }, 207 | 208 | text: function() { return text; }, 209 | 210 | getLine: function() { return line; }, 211 | getColumn: function() { return column; }, 212 | isEof: function() { return index >= length; }, 213 | isSol: function() { return column === 1; }, 214 | isSolWs: function() { 215 | var temp = index, 216 | c; 217 | if (column === 1) { 218 | return true; 219 | } 220 | 221 | //look backward until we find a newline or a non-whitespace character 222 | while ((c = text.charAt(--temp)) !== "") { 223 | if (c === "\n") { 224 | return true; 225 | } 226 | if (!/\s/.test(c)) { 227 | return false; 228 | } 229 | } 230 | 231 | return true; 232 | }, 233 | isEol: function() { return nextReadBeginsLine; }, 234 | EOF: EOF, 235 | current: function() { return currentChar; } 236 | }; 237 | } 238 | 239 | //http://javascript.crockford.com/prototypal.html 240 | function create(o) { 241 | function F() {} 242 | F.prototype = o; 243 | return new F(); 244 | } 245 | 246 | function appendAll(parent, children) { 247 | var i; 248 | for (i = 0; i < children.length; i++) { 249 | parent.appendChild(children[i]); 250 | } 251 | } 252 | 253 | //gets the last character in a string or the last element in an array 254 | function last(thing) { 255 | return thing.charAt ? thing.charAt(thing.length - 1) : thing[thing.length - 1]; 256 | } 257 | 258 | //array.contains() 259 | function contains(arr, value, caseInsensitive) { 260 | var i; 261 | if (arr.indexOf && !caseInsensitive) { 262 | return arr.indexOf(value) >= 0; 263 | } 264 | 265 | for (i = 0; i < arr.length; i++) { 266 | if (arr[i] === value) { 267 | return true; 268 | } 269 | 270 | if (caseInsensitive && typeof(arr[i]) === "string" && typeof(value) === "string" && arr[i].toUpperCase() === value.toUpperCase()) { 271 | return true; 272 | } 273 | } 274 | 275 | return false; 276 | } 277 | 278 | //non-recursively merges one object into the other 279 | function merge(defaultObject, objectToMerge) { 280 | var key; 281 | if (!objectToMerge) { 282 | return defaultObject; 283 | } 284 | 285 | for (key in objectToMerge) { 286 | defaultObject[key] = objectToMerge[key]; 287 | } 288 | 289 | return defaultObject; 290 | } 291 | 292 | function clone(object) { 293 | return merge({}, object); 294 | } 295 | 296 | //http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript/3561711#3561711 297 | function regexEscape(s) { 298 | return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); 299 | } 300 | 301 | function createProceduralRule(startIndex, direction, tokenRequirements, caseInsensitive) { 302 | tokenRequirements = tokenRequirements.slice(0); 303 | return function(tokens) { 304 | var tokenIndexStart = startIndex, 305 | j, 306 | expected, 307 | actual; 308 | 309 | if (direction === 1) { 310 | tokenRequirements.reverse(); 311 | } 312 | 313 | for (j = 0; j < tokenRequirements.length; j++) { 314 | actual = tokens[tokenIndexStart + (j * direction)]; 315 | expected = tokenRequirements[tokenRequirements.length - 1 - j]; 316 | 317 | if (actual === undefined) { 318 | if (expected["optional"] !== undefined && expected.optional) { 319 | tokenIndexStart -= direction; 320 | } else { 321 | return false; 322 | } 323 | } else if (actual.name === expected.token && (expected["values"] === undefined || contains(expected.values, actual.value, caseInsensitive))) { 324 | //derp 325 | continue; 326 | } else if (expected["optional"] !== undefined && expected.optional) { 327 | tokenIndexStart -= direction; //we need to reevaluate against this token again 328 | } else { 329 | return false; 330 | } 331 | } 332 | 333 | return true; 334 | }; 335 | } 336 | 337 | function createBetweenRule(startIndex, opener, closer, caseInsensitive) { 338 | return function(tokens) { 339 | var index = startIndex, 340 | token, 341 | success = false; 342 | 343 | //check to the left: if we run into a closer or never run into an opener, fail 344 | while ((token = tokens[--index]) !== undefined) { 345 | if (token.name === closer.token && contains(closer.values, token.value)) { 346 | if (token.name === opener.token && contains(opener.values, token.value, caseInsensitive)) { 347 | //if the closer is the same as the opener that's okay 348 | success = true; 349 | break; 350 | } 351 | 352 | return false; 353 | } 354 | 355 | if (token.name === opener.token && contains(opener.values, token.value, caseInsensitive)) { 356 | success = true; 357 | break; 358 | } 359 | } 360 | 361 | if (!success) { 362 | return false; 363 | } 364 | 365 | //check to the right for the closer 366 | index = startIndex; 367 | while ((token = tokens[++index]) !== undefined) { 368 | if (token.name === opener.token && contains(opener.values, token.value, caseInsensitive)) { 369 | if (token.name === closer.token && contains(closer.values, token.value, caseInsensitive)) { 370 | //if the closer is the same as the opener that's okay 371 | success = true; 372 | break; 373 | } 374 | 375 | return false; 376 | } 377 | 378 | if (token.name === closer.token && contains(closer.values, token.value, caseInsensitive)) { 379 | success = true; 380 | break; 381 | } 382 | } 383 | 384 | return success; 385 | }; 386 | } 387 | 388 | function matchWord(context, wordMap, tokenName, doNotRead) { 389 | var current = context.reader.current(), 390 | i, 391 | word, 392 | peek, 393 | line = context.reader.getLine(), 394 | column = context.reader.getColumn(); 395 | 396 | wordMap = wordMap || []; 397 | if (context.language.caseInsensitive) { 398 | current = current.toUpperCase(); 399 | } 400 | 401 | if (!wordMap[current]) { 402 | return null; 403 | } 404 | 405 | wordMap = wordMap[current]; 406 | for (i = 0; i < wordMap.length; i++) { 407 | word = wordMap[i].value; 408 | 409 | peek = current + context.reader.peek(word.length); 410 | if (word === peek || wordMap[i].regex.test(peek)) { 411 | return context.createToken( 412 | tokenName, 413 | context.reader.current() + context.reader[doNotRead ? "peek" : "read"](word.length - 1), 414 | line, 415 | column 416 | ); 417 | } 418 | } 419 | 420 | return null; 421 | } 422 | 423 | //gets the next token in the specified direction while matcher matches the current token 424 | function getNextWhile(tokens, index, direction, matcher) { 425 | var count = 1, 426 | token; 427 | 428 | direction = direction || 1; 429 | while (token = tokens[index + (direction * count++)]) { 430 | if (!matcher(token)) { 431 | return token; 432 | } 433 | } 434 | 435 | return undefined; 436 | } 437 | 438 | //this is crucial for performance 439 | function createHashMap(wordMap, boundary, caseInsensitive) { 440 | //creates a hash table where the hash is the first character of the word 441 | var newMap = { }, 442 | i, 443 | word, 444 | firstChar; 445 | 446 | for (i = 0; i < wordMap.length; i++) { 447 | word = caseInsensitive ? wordMap[i].toUpperCase() : wordMap[i]; 448 | firstChar = word.charAt(0); 449 | if (!newMap[firstChar]) { 450 | newMap[firstChar] = []; 451 | } 452 | 453 | newMap[firstChar].push({ value: word, regex: new RegExp("^" + regexEscape(word) + boundary, caseInsensitive ? "i" : "") }); 454 | } 455 | 456 | return newMap; 457 | } 458 | 459 | function defaultNumberParser(context) { 460 | var current = context.reader.current(), 461 | number, 462 | line = context.reader.getLine(), 463 | column = context.reader.getColumn(), 464 | allowDecimal = true, 465 | peek; 466 | 467 | if (!/\d/.test(current)) { 468 | //is it a decimal followed by a number? 469 | if (current !== "." || !/\d/.test(context.reader.peek())) { 470 | return null; 471 | } 472 | 473 | //decimal without leading zero 474 | number = current + context.reader.read(); 475 | allowDecimal = false; 476 | } else { 477 | number = current; 478 | if (current === "0" && context.reader.peek() !== ".") { 479 | //hex or octal 480 | allowDecimal = false; 481 | } 482 | } 483 | 484 | //easy way out: read until it's not a number or letter 485 | //this will work for hex (0xef), octal (012), decimal and scientific notation (1e3) 486 | //anything else and you're on your own 487 | 488 | while ((peek = context.reader.peek()) !== context.reader.EOF) { 489 | if (!/[A-Za-z0-9]/.test(peek)) { 490 | if (peek === "." && allowDecimal && /\d$/.test(context.reader.peek(2))) { 491 | number += context.reader.read(); 492 | allowDecimal = false; 493 | continue; 494 | } 495 | 496 | break; 497 | } 498 | 499 | number += context.reader.read(); 500 | } 501 | 502 | return context.createToken("number", number, line, column); 503 | } 504 | 505 | function fireEvent(eventName, highlighter, eventContext) { 506 | var delegates = events[eventName] || [], 507 | i; 508 | 509 | for (i = 0; i < delegates.length; i++) { 510 | delegates[i].call(highlighter, eventContext); 511 | } 512 | } 513 | 514 | function Highlighter(options) { 515 | this.options = merge(clone(globalOptions), options); 516 | } 517 | 518 | Highlighter.prototype = (function() { 519 | var parseNextToken = (function() { 520 | function isIdentMatch(context) { 521 | return context.language.identFirstLetter && context.language.identFirstLetter.test(context.reader.current()); 522 | } 523 | 524 | //token parsing functions 525 | function parseKeyword(context) { 526 | return matchWord(context, context.language.keywords, "keyword"); 527 | } 528 | 529 | function parseCustomTokens(context) { 530 | var tokenName, 531 | token; 532 | if (context.language.customTokens === undefined) { 533 | return null; 534 | } 535 | 536 | for (tokenName in context.language.customTokens) { 537 | token = matchWord(context, context.language.customTokens[tokenName], tokenName); 538 | if (token !== null) { 539 | return token; 540 | } 541 | } 542 | 543 | return null; 544 | } 545 | 546 | function parseOperator(context) { 547 | return matchWord(context, context.language.operators, "operator"); 548 | } 549 | 550 | function parsePunctuation(context) { 551 | var current = context.reader.current(); 552 | if (context.language.punctuation.test(regexEscape(current))) { 553 | return context.createToken("punctuation", current, context.reader.getLine(), context.reader.getColumn()); 554 | } 555 | 556 | return null; 557 | } 558 | 559 | function parseIdent(context) { 560 | var ident, 561 | peek, 562 | line = context.reader.getLine(), 563 | column = context.reader.getColumn(); 564 | 565 | if (!isIdentMatch(context)) { 566 | return null; 567 | } 568 | 569 | ident = context.reader.current(); 570 | while ((peek = context.reader.peek()) !== context.reader.EOF) { 571 | if (!context.language.identAfterFirstLetter.test(peek)) { 572 | break; 573 | } 574 | 575 | ident += context.reader.read(); 576 | } 577 | 578 | return context.createToken("ident", ident, line, column); 579 | } 580 | 581 | function parseDefault(context) { 582 | if (context.defaultData.text === "") { 583 | //new default token 584 | context.defaultData.line = context.reader.getLine(); 585 | context.defaultData.column = context.reader.getColumn(); 586 | } 587 | 588 | context.defaultData.text += context.reader.current(); 589 | return null; 590 | } 591 | 592 | function parseScopes(context) { 593 | var current = context.reader.current(), 594 | tokenName, 595 | specificScopes, 596 | j, 597 | opener, 598 | line, 599 | column, 600 | continuation, 601 | value; 602 | 603 | for (tokenName in context.language.scopes) { 604 | specificScopes = context.language.scopes[tokenName]; 605 | for (j = 0; j < specificScopes.length; j++) { 606 | opener = specificScopes[j][0]; 607 | 608 | value = current + context.reader.peek(opener.length - 1); 609 | 610 | if (opener !== value && (!context.language.caseInsensitive || value.toUpperCase() !== opener.toUpperCase())) { 611 | continue; 612 | } 613 | 614 | line = context.reader.getLine(), column = context.reader.getColumn(); 615 | context.reader.read(opener.length - 1); 616 | continuation = getScopeReaderFunction(specificScopes[j], tokenName); 617 | return continuation(context, continuation, value, line, column); 618 | } 619 | } 620 | 621 | return null; 622 | } 623 | 624 | function parseNumber(context) { 625 | return context.language.numberParser(context); 626 | } 627 | 628 | function parseCustomRules(context) { 629 | var customRules = context.language.customParseRules, 630 | i, 631 | token; 632 | 633 | if (customRules === undefined) { 634 | return null; 635 | } 636 | 637 | for (i = 0; i < customRules.length; i++) { 638 | token = customRules[i](context); 639 | if (token) { 640 | return token; 641 | } 642 | } 643 | 644 | return null; 645 | } 646 | 647 | return function(context) { 648 | if (context.language.doNotParse.test(context.reader.current())) { 649 | return parseDefault(context); 650 | } 651 | 652 | return parseCustomRules(context) 653 | || parseCustomTokens(context) 654 | || parseKeyword(context) 655 | || parseScopes(context) 656 | || parseIdent(context) 657 | || parseNumber(context) 658 | || parseOperator(context) 659 | || parsePunctuation(context) 660 | || parseDefault(context); 661 | } 662 | }()); 663 | 664 | function getScopeReaderFunction(scope, tokenName) { 665 | var escapeSequences = scope[2] || [], 666 | closerLength = scope[1].length, 667 | closer = typeof(scope[1]) === "string" ? new RegExp(regexEscape(scope[1])) : scope[1].regex, 668 | zeroWidth = scope[3] || false; 669 | 670 | //processCurrent indicates that this is being called from a continuation 671 | //which means that we need to process the current char, rather than peeking at the next 672 | return function(context, continuation, buffer, line, column, processCurrent) { 673 | var foundCloser = false; 674 | buffer = buffer || ""; 675 | 676 | processCurrent = processCurrent ? 1 : 0; 677 | 678 | function process(processCurrent) { 679 | //check for escape sequences 680 | var peekValue, 681 | current = context.reader.current(), 682 | i; 683 | 684 | for (i = 0; i < escapeSequences.length; i++) { 685 | peekValue = (processCurrent ? current : "") + context.reader.peek(escapeSequences[i].length - processCurrent); 686 | if (peekValue === escapeSequences[i]) { 687 | buffer += context.reader.read(peekValue.length - processCurrent); 688 | return true; 689 | } 690 | } 691 | 692 | peekValue = (processCurrent ? current : "") + context.reader.peek(closerLength - processCurrent); 693 | if (closer.test(peekValue)) { 694 | foundCloser = true; 695 | return false; 696 | } 697 | 698 | buffer += processCurrent ? current : context.reader.read(); 699 | return true; 700 | }; 701 | 702 | if (!processCurrent || process(true)) { 703 | while (context.reader.peek() !== context.reader.EOF && process(false)) { } 704 | } 705 | 706 | if (processCurrent) { 707 | buffer += context.reader.current(); 708 | context.reader.read(); 709 | } else { 710 | buffer += zeroWidth || context.reader.peek() === context.reader.EOF ? "" : context.reader.read(closerLength); 711 | } 712 | 713 | if (!foundCloser) { 714 | //we need to signal to the context that this scope was never properly closed 715 | //this has significance for partial parses (e.g. for nested languages) 716 | context.continuation = continuation; 717 | } 718 | 719 | return context.createToken(tokenName, buffer, line, column); 720 | }; 721 | } 722 | 723 | //called before processing the current 724 | function switchToEmbeddedLanguageIfNecessary(context) { 725 | var i, 726 | embeddedLanguage; 727 | 728 | for (i = 0; i < context.language.embeddedLanguages.length; i++) { 729 | if (!languages[context.language.embeddedLanguages[i].language]) { 730 | //unregistered language 731 | continue; 732 | } 733 | 734 | embeddedLanguage = clone(context.language.embeddedLanguages[i]); 735 | 736 | if (embeddedLanguage.switchTo(context)) { 737 | embeddedLanguage.oldItems = clone(context.items); 738 | context.embeddedLanguageStack.push(embeddedLanguage); 739 | context.language = languages[embeddedLanguage.language]; 740 | context.items = merge(context.items, clone(context.language.contextItems)); 741 | break; 742 | } 743 | } 744 | } 745 | 746 | //called after processing the current 747 | function switchBackFromEmbeddedLanguageIfNecessary(context) { 748 | var current = last(context.embeddedLanguageStack), 749 | lang; 750 | 751 | if (current && current.switchBack(context)) { 752 | context.language = languages[current.parentLanguage]; 753 | lang = context.embeddedLanguageStack.pop(); 754 | 755 | //restore old items 756 | context.items = clone(lang.oldItems); 757 | lang.oldItems = {}; 758 | } 759 | } 760 | 761 | function tokenize(unhighlightedCode, language, partialContext, options) { 762 | var tokens = [], 763 | context, 764 | continuation, 765 | token; 766 | 767 | fireEvent("beforeTokenize", this, { code: unhighlightedCode, language: language }); 768 | context = { 769 | reader: createCodeReader(unhighlightedCode), 770 | language: language, 771 | items: clone(language.contextItems), 772 | token: function(index) { return tokens[index]; }, 773 | getAllTokens: function() { return tokens.slice(0); }, 774 | count: function() { return tokens.length; }, 775 | options: options, 776 | embeddedLanguageStack: [], 777 | 778 | defaultData: { 779 | text: "", 780 | line: 1, 781 | column: 1 782 | }, 783 | createToken: function(name, value, line, column) { 784 | return { 785 | name: name, 786 | line: line, 787 | value: isIe ? value.replace(/\n/g, "\r") : value, 788 | column: column, 789 | language: this.language.name 790 | }; 791 | } 792 | }; 793 | 794 | //if continuation is given, then we need to pick up where we left off from a previous parse 795 | //basically it indicates that a scope was never closed, so we need to continue that scope 796 | if (partialContext.continuation) { 797 | continuation = partialContext.continuation; 798 | partialContext.continuation = null; 799 | tokens.push(continuation(context, continuation, "", context.reader.getLine(), context.reader.getColumn(), true)); 800 | } 801 | 802 | while (!context.reader.isEof()) { 803 | switchToEmbeddedLanguageIfNecessary(context); 804 | token = parseNextToken(context); 805 | 806 | //flush default data if needed (in pretty much all languages this is just whitespace) 807 | if (token !== null) { 808 | if (context.defaultData.text !== "") { 809 | tokens.push(context.createToken("default", context.defaultData.text, context.defaultData.line, context.defaultData.column)); 810 | context.defaultData.text = ""; 811 | } 812 | 813 | if (token[0] !== undefined) { 814 | //multiple tokens 815 | tokens = tokens.concat(token); 816 | } else { 817 | //single token 818 | tokens.push(token); 819 | } 820 | } 821 | 822 | switchBackFromEmbeddedLanguageIfNecessary(context); 823 | context.reader.read(); 824 | } 825 | 826 | //append the last default token, if necessary 827 | if (context.defaultData.text !== "") { 828 | tokens.push(context.createToken("default", context.defaultData.text, context.defaultData.line, context.defaultData.column)); 829 | } 830 | 831 | fireEvent("afterTokenize", this, { code: unhighlightedCode, parserContext: context }); 832 | return context; 833 | } 834 | 835 | function createAnalyzerContext(parserContext, partialContext, options) { 836 | var nodes = [], 837 | prepareText = function() { 838 | var nbsp, tab; 839 | if (options.showWhitespace) { 840 | nbsp = String.fromCharCode(0xB7); 841 | tab = new Array(options.tabWidth).join(String.fromCharCode(0x2014)) + String.fromCharCode(0x2192); 842 | } else { 843 | nbsp = String.fromCharCode(0xA0); 844 | tab = new Array(options.tabWidth + 1).join(nbsp); 845 | } 846 | 847 | return function(token) { 848 | var value = token.value.split(" ").join(nbsp), 849 | tabIndex, 850 | lastNewlineColumn, 851 | actualColumn, 852 | tabLength; 853 | 854 | //tabstop madness: replace \t with the appropriate number of characters, depending on the tabWidth option and its relative position in the line 855 | while ((tabIndex = value.indexOf("\t")) >= 0) { 856 | lastNewlineColumn = value.lastIndexOf(EOL, tabIndex); 857 | actualColumn = lastNewlineColumn === -1 ? tabIndex : tabIndex - lastNewlineColumn - 1; 858 | tabLength = options.tabWidth - (actualColumn % options.tabWidth); //actual length of the TAB character 859 | 860 | value = value.substring(0, tabIndex) + tab.substring(options.tabWidth - tabLength) + value.substring(tabIndex + 1); 861 | } 862 | 863 | return value; 864 | }; 865 | }(); 866 | 867 | return { 868 | tokens: (partialContext.tokens || []).concat(parserContext.getAllTokens()), 869 | index: partialContext.index ? partialContext.index + 1 : 0, 870 | language: null, 871 | getAnalyzer: EMPTY, 872 | options: options, 873 | continuation: parserContext.continuation, 874 | addNode: function(node) { nodes.push(node); }, 875 | createTextNode: function(token) { return document.createTextNode(prepareText(token)); }, 876 | getNodes: function() { return nodes; }, 877 | resetNodes: function() { nodes = []; }, 878 | items: parserContext.items 879 | }; 880 | } 881 | 882 | //partialContext allows us to perform a partial parse, and then pick up where we left off at a later time 883 | //this functionality enables nested highlights (language within a language, e.g. PHP within HTML followed by more PHP) 884 | function highlightText(unhighlightedCode, languageId, partialContext) { 885 | var language = languages[languageId], 886 | analyzerContext; 887 | 888 | partialContext = partialContext || { }; 889 | if (language === undefined) { 890 | //use default language if one wasn't specified or hasn't been registered 891 | language = languages[DEFAULT_LANGUAGE]; 892 | } 893 | 894 | fireEvent("beforeHighlight", this, { code: unhighlightedCode, language: language, previousContext: partialContext }); 895 | 896 | analyzerContext = createAnalyzerContext( 897 | tokenize.call(this, unhighlightedCode, language, partialContext, this.options), 898 | partialContext, 899 | this.options 900 | ); 901 | 902 | analyze.call(this, analyzerContext, partialContext.index ? partialContext.index + 1 : 0); 903 | 904 | fireEvent("afterHighlight", this, { analyzerContext: analyzerContext }); 905 | 906 | return analyzerContext; 907 | } 908 | 909 | function createContainer(ctx) { 910 | var container = document.createElement("span"); 911 | container.className = ctx.options.classPrefix + ctx.language.name; 912 | return container; 913 | } 914 | 915 | function analyze(analyzerContext, startIndex) { 916 | var nodes, 917 | lastIndex, 918 | container, 919 | i, 920 | tokenName, 921 | func, 922 | language, 923 | analyzer; 924 | 925 | fireEvent("beforeAnalyze", this, { analyzerContext: analyzerContext }); 926 | 927 | if (analyzerContext.tokens.length > 0) { 928 | analyzerContext.language = languages[analyzerContext.tokens[0].language] || languages[DEFAULT_LANGUAGE];; 929 | nodes = []; 930 | lastIndex = 0; 931 | container = createContainer(analyzerContext); 932 | 933 | for (i = startIndex; i < analyzerContext.tokens.length; i++) { 934 | language = languages[analyzerContext.tokens[i].language] || languages[DEFAULT_LANGUAGE]; 935 | if (language.name !== analyzerContext.language.name) { 936 | appendAll(container, analyzerContext.getNodes()); 937 | analyzerContext.resetNodes(); 938 | 939 | nodes.push(container); 940 | analyzerContext.language = language; 941 | container = createContainer(analyzerContext); 942 | } 943 | 944 | analyzerContext.index = i; 945 | tokenName = analyzerContext.tokens[i].name; 946 | func = "handle_" + tokenName; 947 | 948 | analyzer = analyzerContext.getAnalyzer.call(analyzerContext) || analyzerContext.language.analyzer; 949 | analyzer[func] ? analyzer[func](analyzerContext) : analyzer.handleToken(analyzerContext); 950 | } 951 | 952 | //append the last nodes, and add the final nodes to the context 953 | appendAll(container, analyzerContext.getNodes()); 954 | nodes.push(container); 955 | analyzerContext.resetNodes(); 956 | for (i = 0; i < nodes.length; i++) { 957 | analyzerContext.addNode(nodes[i]); 958 | } 959 | } 960 | 961 | fireEvent("afterAnalyze", this, { analyzerContext: analyzerContext }); 962 | } 963 | 964 | return { 965 | //matches the language of the node to highlight 966 | matchSunlightNode: function() { 967 | var regex; 968 | 969 | return function(node) { 970 | if (!regex) { 971 | regex = new RegExp("(?:\\s|^)" + this.options.classPrefix + "highlight-(\\S+)(?:\\s|$)"); 972 | } 973 | 974 | return regex.exec(node.className); 975 | }; 976 | }(), 977 | 978 | //determines if the node has already been highlighted 979 | isAlreadyHighlighted: function() { 980 | var regex; 981 | return function(node) { 982 | if (!regex) { 983 | regex = new RegExp("(?:\\s|^)" + this.options.classPrefix + "highlighted(?:\\s|$)"); 984 | } 985 | 986 | return regex.test(node.className); 987 | }; 988 | }(), 989 | 990 | //highlights a block of text 991 | highlight: function(code, languageId) { return highlightText.call(this, code, languageId); }, 992 | 993 | //recursively highlights a DOM node 994 | highlightNode: function highlightRecursive(node) { 995 | var match, 996 | languageId, 997 | currentNodeCount, 998 | j, 999 | nodes, 1000 | k, 1001 | partialContext, 1002 | container, 1003 | codeContainer; 1004 | 1005 | if (this.isAlreadyHighlighted(node) || (match = this.matchSunlightNode(node)) === null) { 1006 | return; 1007 | } 1008 | 1009 | languageId = match[1]; 1010 | currentNodeCount = 0; 1011 | fireEvent("beforeHighlightNode", this, { node: node }); 1012 | for (j = 0; j < node.childNodes.length; j++) { 1013 | if (node.childNodes[j].nodeType === 3) { 1014 | //text nodes 1015 | partialContext = highlightText.call(this, node.childNodes[j].nodeValue, languageId, partialContext); 1016 | HIGHLIGHTED_NODE_COUNT++; 1017 | currentNodeCount = currentNodeCount || HIGHLIGHTED_NODE_COUNT; 1018 | nodes = partialContext.getNodes(); 1019 | 1020 | node.replaceChild(nodes[0], node.childNodes[j]); 1021 | for (k = 1; k < nodes.length; k++) { 1022 | node.insertBefore(nodes[k], nodes[k - 1].nextSibling); 1023 | } 1024 | } else if (node.childNodes[j].nodeType === 1) { 1025 | //element nodes 1026 | highlightRecursive.call(this, node.childNodes[j]); 1027 | } 1028 | } 1029 | 1030 | //indicate that this node has been highlighted 1031 | node.className += " " + this.options.classPrefix + "highlighted"; 1032 | 1033 | //if the node is block level, we put it in a container, otherwise we just leave it alone 1034 | if (getComputedStyle(node, "display") === "block") { 1035 | container = document.createElement("div"); 1036 | container.className = this.options.classPrefix + "container"; 1037 | 1038 | codeContainer = document.createElement("div"); 1039 | codeContainer.className = this.options.classPrefix + "code-container"; 1040 | 1041 | //apply max height if specified in options 1042 | if (this.options.maxHeight !== false) { 1043 | codeContainer.style.overflowY = "auto"; 1044 | codeContainer.style.maxHeight = this.options.maxHeight + (/^\d+$/.test(this.options.maxHeight) ? "px" : ""); 1045 | } 1046 | 1047 | container.appendChild(codeContainer); 1048 | 1049 | node.parentNode.insertBefore(codeContainer, node); 1050 | node.parentNode.removeChild(node); 1051 | codeContainer.appendChild(node); 1052 | 1053 | codeContainer.parentNode.insertBefore(container, codeContainer); 1054 | codeContainer.parentNode.removeChild(codeContainer); 1055 | container.appendChild(codeContainer); 1056 | } 1057 | 1058 | fireEvent("afterHighlightNode", this, { 1059 | container: container, 1060 | codeContainer: codeContainer, 1061 | node: node, 1062 | count: currentNodeCount 1063 | }); 1064 | } 1065 | }; 1066 | }()); 1067 | 1068 | //public facing object 1069 | window.Sunlight = { 1070 | version: "1.18", 1071 | Highlighter: Highlighter, 1072 | createAnalyzer: function() { return create(defaultAnalyzer); }, 1073 | globalOptions: globalOptions, 1074 | 1075 | highlightAll: function(options) { 1076 | var highlighter = new Highlighter(options), 1077 | tags = document.getElementsByTagName("*"), 1078 | i; 1079 | 1080 | for (i = 0; i < tags.length; i++) { 1081 | highlighter.highlightNode(tags[i]); 1082 | } 1083 | }, 1084 | 1085 | registerLanguage: function(languageId, languageData) { 1086 | var tokenName, 1087 | embeddedLanguages, 1088 | languageName; 1089 | 1090 | if (!languageId) { 1091 | throw "Languages must be registered with an identifier, e.g. \"php\" for PHP"; 1092 | } 1093 | 1094 | languageData = merge(merge({}, languageDefaults), languageData); 1095 | languageData.name = languageId; 1096 | 1097 | //transform keywords, operators and custom tokens into a hash map 1098 | languageData.keywords = createHashMap(languageData.keywords || [], "\\b", languageData.caseInsensitive); 1099 | languageData.operators = createHashMap(languageData.operators || [], "", languageData.caseInsensitive); 1100 | for (tokenName in languageData.customTokens) { 1101 | languageData.customTokens[tokenName] = createHashMap( 1102 | languageData.customTokens[tokenName].values, 1103 | languageData.customTokens[tokenName].boundary, 1104 | languageData.caseInsensitive 1105 | ); 1106 | } 1107 | 1108 | //convert the embedded language object to an easier-to-use array 1109 | embeddedLanguages = []; 1110 | for (languageName in languageData.embeddedLanguages) { 1111 | embeddedLanguages.push({ 1112 | parentLanguage: languageData.name, 1113 | language: languageName, 1114 | switchTo: languageData.embeddedLanguages[languageName].switchTo, 1115 | switchBack: languageData.embeddedLanguages[languageName].switchBack 1116 | }); 1117 | } 1118 | 1119 | languageData.embeddedLanguages = embeddedLanguages; 1120 | 1121 | languages[languageData.name] = languageData; 1122 | }, 1123 | 1124 | isRegistered: function(languageId) { return languages[languageId] !== undefined; }, 1125 | 1126 | bind: function(event, callback) { 1127 | if (!events[event]) { 1128 | throw "Unknown event \"" + event + "\""; 1129 | } 1130 | 1131 | events[event].push(callback); 1132 | }, 1133 | 1134 | util: { 1135 | last: last, 1136 | regexEscape: regexEscape, 1137 | eol: EOL, 1138 | clone: clone, 1139 | escapeSequences: ["\\n", "\\t", "\\r", "\\\\", "\\v", "\\f"], 1140 | contains: contains, 1141 | matchWord: matchWord, 1142 | createHashMap: createHashMap, 1143 | createBetweenRule: createBetweenRule, 1144 | createProceduralRule: createProceduralRule, 1145 | getNextNonWsToken: function(tokens, index) { return getNextWhile(tokens, index, 1, function(token) { return token.name === "default"; }); }, 1146 | getPreviousNonWsToken: function(tokens, index) { return getNextWhile(tokens, index, -1, function(token) { return token.name === "default"; }); }, 1147 | getNextWhile: function(tokens, index, matcher) { return getNextWhile(tokens, index, 1, matcher); }, 1148 | getPreviousWhile: function(tokens, index, matcher) { return getNextWhile(tokens, index, -1, matcher); }, 1149 | whitespace: { token: "default", optional: true }, 1150 | getComputedStyle: getComputedStyle 1151 | } 1152 | }; 1153 | 1154 | //register the default language 1155 | window.Sunlight.registerLanguage(DEFAULT_LANGUAGE, { punctuation: /(?!x)x/, numberParser: EMPTY }); 1156 | 1157 | }(this, document)); -------------------------------------------------------------------------------- /docs/gen/scripts/toc.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | var navbarHeight; 3 | var initialised = false; 4 | var navbarOffset; 5 | 6 | function elOffset($el) { 7 | return $el.offset().top - (navbarHeight + navbarOffset); 8 | } 9 | 10 | function scrollToHash(duringPageLoad) { 11 | var elScrollToId = location.hash.replace(/^#/, ''); 12 | var $el; 13 | 14 | function doScroll() { 15 | var offsetTop = elOffset($el); 16 | window.scrollTo(window.pageXOffset || window.scrollX, offsetTop); 17 | } 18 | 19 | if (elScrollToId) { 20 | $el = $(document.getElementById(elScrollToId)); 21 | 22 | if (!$el.length) { 23 | $el = $(document.getElementsByName(elScrollToId)); 24 | } 25 | 26 | if ($el.length) { 27 | if (duringPageLoad) { 28 | $(window).one('scroll', function() { 29 | setTimeout(doScroll, 100); 30 | }); 31 | } else { 32 | setTimeout(doScroll, 0); 33 | } 34 | } 35 | } 36 | } 37 | 38 | function init(opts) { 39 | if (initialised) { 40 | return; 41 | } 42 | initialised = true; 43 | navbarHeight = $('.navbar').height(); 44 | navbarOffset = opts.navbarOffset; 45 | 46 | // some browsers move the offset after changing location. 47 | // also catch external links coming in 48 | $(window).on("hashchange", scrollToHash.bind(null, false)); 49 | $(scrollToHash.bind(null, true)); 50 | } 51 | 52 | $.catchAnchorLinks = function(options) { 53 | var opts = $.extend({}, jQuery.fn.toc.defaults, options); 54 | init(opts); 55 | }; 56 | 57 | $.fn.toc = function(options) { 58 | var self = this; 59 | var opts = $.extend({}, jQuery.fn.toc.defaults, options); 60 | 61 | var container = $(opts.container); 62 | var tocs = []; 63 | var headings = $(opts.selectors, container); 64 | var headingOffsets = []; 65 | var activeClassName = 'active'; 66 | var ANCHOR_PREFIX = "__anchor"; 67 | var maxScrollTo; 68 | var visibleHeight; 69 | var headerHeight = 10; // so if the header is readable, its counted as shown 70 | init(); 71 | 72 | var scrollTo = function(e) { 73 | e.preventDefault(); 74 | var target = $(e.target); 75 | if (target.prop('tagName').toLowerCase() !== "a") { 76 | target = target.parent(); 77 | } 78 | var elScrollToId = target.attr('href').replace(/^#/, '') + ANCHOR_PREFIX; 79 | var $el = $(document.getElementById(elScrollToId)); 80 | 81 | var offsetTop = Math.min(maxScrollTo, elOffset($el)); 82 | 83 | $('body,html').animate({ scrollTop: offsetTop }, 400, 'swing', function() { 84 | location.hash = '#' + elScrollToId; 85 | }); 86 | 87 | $('a', self).removeClass(activeClassName); 88 | target.addClass(activeClassName); 89 | }; 90 | 91 | var calcHadingOffsets = function() { 92 | maxScrollTo = $("body").height() - $(window).height(); 93 | visibleHeight = $(window).height() - navbarHeight; 94 | headingOffsets = []; 95 | headings.each(function(i, heading) { 96 | var anchorSpan = $(heading).prev("span"); 97 | var top = 0; 98 | if (anchorSpan.length) { 99 | top = elOffset(anchorSpan); 100 | } 101 | headingOffsets.push(top > 0 ? top : 0); 102 | }); 103 | } 104 | 105 | //highlight on scroll 106 | var timeout; 107 | var highlightOnScroll = function(e) { 108 | if (!tocs.length) { 109 | return; 110 | } 111 | if (timeout) { 112 | clearTimeout(timeout); 113 | } 114 | timeout = setTimeout(function() { 115 | var top = $(window).scrollTop(), 116 | highlighted; 117 | for (var i = headingOffsets.length - 1; i >= 0; i--) { 118 | var isActive = tocs[i].hasClass(activeClassName); 119 | // at the end of the page, allow any shown header 120 | if (isActive && headingOffsets[i] >= maxScrollTo && top >= maxScrollTo) { 121 | return; 122 | } 123 | // if we have got to the first heading or the heading is the first one visible 124 | if (i === 0 || (headingOffsets[i] + headerHeight >= top && (headingOffsets[i - 1] + headerHeight <= top))) { 125 | // in the case that a heading takes up more than the visible height e.g. we are showing 126 | // only the one above, highlight the one above 127 | if (i > 0 && headingOffsets[i] - visibleHeight >= top) { 128 | i--; 129 | } 130 | $('a', self).removeClass(activeClassName); 131 | if (i >= 0) { 132 | highlighted = tocs[i].addClass(activeClassName); 133 | opts.onHighlight(highlighted); 134 | } 135 | break; 136 | } 137 | } 138 | }, 50); 139 | }; 140 | if (opts.highlightOnScroll) { 141 | $(window).bind('scroll', highlightOnScroll); 142 | $(window).bind('load resize', function() { 143 | calcHadingOffsets(); 144 | highlightOnScroll(); 145 | }); 146 | } 147 | 148 | return this.each(function() { 149 | //build TOC 150 | var el = $(this); 151 | var ul = $('
'); 152 | 153 | headings.each(function(i, heading) { 154 | var $h = $(heading); 155 | 156 | var anchor = $('').attr('id', opts.anchorName(i, heading, opts.prefix) + ANCHOR_PREFIX).insertBefore($h); 157 | 158 | var span = $('') 159 | .text(opts.headerText(i, heading, $h)); 160 | 161 | //build TOC item 162 | var a = $('') 163 | .append(span) 164 | .attr('href', '#' + opts.anchorName(i, heading, opts.prefix)) 165 | .bind('click', function(e) { 166 | scrollTo(e); 167 | el.trigger('selected', $(this).attr('href')); 168 | }); 169 | 170 | span.addClass(opts.itemClass(i, heading, $h, opts.prefix)); 171 | 172 | tocs.push(a); 173 | 174 | ul.append(a); 175 | }); 176 | el.html(ul); 177 | 178 | calcHadingOffsets(); 179 | }); 180 | }; 181 | 182 | 183 | jQuery.fn.toc.defaults = { 184 | container: 'body', 185 | selectors: 'h1,h2,h3', 186 | smoothScrolling: true, 187 | prefix: 'toc', 188 | onHighlight: function() {}, 189 | highlightOnScroll: true, 190 | navbarOffset: 0, 191 | anchorName: function(i, heading, prefix) { 192 | return prefix+i; 193 | }, 194 | headerText: function(i, heading, $heading) { 195 | return $heading.text(); 196 | }, 197 | itemClass: function(i, heading, $heading, prefix) { 198 | return prefix + '-' + $heading[0].tagName.toLowerCase(); 199 | } 200 | 201 | }; 202 | 203 | })(jQuery); 204 | -------------------------------------------------------------------------------- /docs/gen/styles/darkstrap.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Darkstrap v0.9.2 3 | * By danneu (http://github.com/danneu/darkstrap) 4 | * Based off Twitter Bootstrap v2.2.2 5 | */ 6 | 7 | tr.warning, 8 | tr.success, 9 | tr.error, 10 | tr.info { 11 | color: #fff; 12 | } 13 | 14 | body { 15 | color: #c6c6c6; 16 | background-color: #2f2f2f; 17 | } 18 | 19 | a:hover { 20 | color: #1ab2ff; 21 | } 22 | 23 | textarea, 24 | input[type="text"], 25 | input[type="password"], 26 | input[type="datetime"], 27 | input[type="datetime-local"], 28 | input[type="date"], 29 | input[type="month"], 30 | input[type="time"], 31 | input[type="week"], 32 | input[type="number"], 33 | input[type="email"], 34 | input[type="url"], 35 | input[type="search"], 36 | input[type="tel"], 37 | input[type="color"], 38 | .uneditable-input { 39 | background-color: #cccccc; 40 | } 41 | select { 42 | background-color: #cccccc; 43 | } 44 | 45 | .uneditable-input, 46 | .uneditable-textarea { 47 | background-color: #c9c9c9; 48 | } 49 | 50 | input:-moz-placeholder, 51 | textarea:-moz-placeholder { 52 | color: #666666; 53 | } 54 | input:-ms-input-placeholder, 55 | textarea:-ms-input-placeholder { 56 | color: #666666; 57 | } 58 | input::-webkit-input-placeholder, 59 | textarea::-webkit-input-placeholder { 60 | color: #666666; 61 | } 62 | 63 | .control-group.warning .input-prepend .add-on, 64 | .control-group.warning .input-append .add-on { 65 | background-color: #faa732; 66 | } 67 | 68 | .control-group.error .input-prepend .add-on, 69 | .control-group.error .input-append .add-on { 70 | background-color: #fc5b5e; 71 | } 72 | 73 | .control-group.success .input-prepend .add-on, 74 | .control-group.success .input-append .add-on { 75 | background-color: #5bb75b; 76 | } 77 | 78 | .control-group.info .input-prepend .add-on, 79 | .control-group.info .input-append .add-on { 80 | background-color: #3a87ad; 81 | } 82 | 83 | .form-actions { 84 | background-color: #444444; 85 | } 86 | .help-block, 87 | .help-inline { 88 | color: #ececec; 89 | } 90 | 91 | .table th, 92 | .table td { 93 | border-top: 1px solid #666666; 94 | } 95 | .table tbody + tbody { 96 | border-top: 2px solid #666666; 97 | } 98 | .table .table { 99 | background-color: #2f2f2f; 100 | } 101 | 102 | .table-bordered { 103 | border: 1px solid #666666; 104 | } 105 | .table-bordered th, 106 | .table-bordered td { 107 | border-left: 1px solid #666666; 108 | } 109 | .table-striped tbody > tr:nth-child(odd) > td, 110 | .table-striped tbody > tr:nth-child(odd) > th { 111 | background-color: #444444; 112 | } 113 | 114 | .table-hover tbody tr:hover td, 115 | .table-hover tbody tr:hover th { 116 | background-color: #666666; 117 | } 118 | 119 | 120 | .table tbody tr.success td { 121 | background-color: #5bb75b; 122 | } 123 | .table tbody tr.error td { 124 | background-color: #fc5b5e; 125 | } 126 | .table tbody tr.warning td { 127 | background-color: #faa732; 128 | } 129 | .table tbody tr.info td { 130 | background-color: #3a87ad; 131 | } 132 | 133 | .table-hover tbody tr.success:hover td { 134 | background-color: #4cad4c; 135 | } 136 | .table-hover tbody tr.error:hover td { 137 | background-color: #fc4245; 138 | } 139 | .table-hover tbody tr.warning:hover td { 140 | background-color: #f99c19; 141 | } 142 | .table-hover tbody tr.info:hover td { 143 | background-color: #34789a; 144 | } 145 | 146 | [class^="icon-"], 147 | [class*=" icon-"] { 148 | background-image: url("../img/glyphicons-halflings.png"); 149 | } 150 | 151 | .icon-white, 152 | .nav-pills > .active > a > [class^="icon-"], 153 | .nav-pills > .active > a > [class*=" icon-"], 154 | .nav-list > .active > a > [class^="icon-"], 155 | .nav-list > .active > a > [class*=" icon-"], 156 | .navbar-inverse .nav > .active > a > [class^="icon-"], 157 | .navbar-inverse .nav > .active > a > [class*=" icon-"], 158 | .dropdown-menu > li > a:hover > [class^="icon-"], 159 | .dropdown-menu > li > a:hover > [class*=" icon-"], 160 | .dropdown-menu > .active > a > [class^="icon-"], 161 | .dropdown-menu > .active > a > [class*=" icon-"], 162 | .dropdown-submenu:hover > a > [class^="icon-"], 163 | .dropdown-submenu:hover > a > [class*=" icon-"] { 164 | background-image: url("../img/glyphicons-halflings-white.png"); 165 | } 166 | 167 | 168 | .btn-link:hover { 169 | color: #1ab2ff; 170 | } 171 | 172 | .alert { 173 | background-color: #faa732; 174 | border: 1px solid #fa7d23; 175 | } 176 | 177 | 178 | .alert-success { 179 | background-color: #5bb75b; 180 | border-color: #5cad4c; 181 | } 182 | 183 | 184 | .alert-danger, 185 | .alert-error { 186 | background-color: #fc5b5e; 187 | border-color: #fc4c6d; 188 | } 189 | 190 | .alert-info { 191 | background-color: #3a87ad; 192 | border-color: #318292; 193 | } 194 | 195 | .nav-tabs > .active > a, 196 | .nav-tabs > .active > a:hover { 197 | background-color: #2f2f2f; 198 | } 199 | 200 | .nav .dropdown-toggle:hover .caret { 201 | border-top-color: #1ab2ff; 202 | border-bottom-color: #1ab2ff; 203 | } 204 | 205 | .navbar-inner { 206 | background-color: #363636; 207 | background-image: -moz-linear-gradient(top, #444444, #222222); 208 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); 209 | background-image: -webkit-linear-gradient(top, #444444, #222222); 210 | background-image: -o-linear-gradient(top, #444444, #222222); 211 | background-image: linear-gradient(to bottom, #444444, #222222); 212 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF444444', endColorstr='#FF222222', GradientType=0); 213 | border: 1px solid #030303; 214 | } 215 | .navbar .brand { 216 | color: #c6c6c6; 217 | text-shadow: 0 1px 0 #444444; 218 | } 219 | .navbar-text { 220 | color: #c6c6c6; 221 | } 222 | 223 | .navbar-link { 224 | color: #c6c6c6; 225 | } 226 | .navbar-link:hover { 227 | color: white; 228 | } 229 | 230 | .navbar .divider-vertical { 231 | border-left: 1px solid #222222; 232 | border-right: 1px solid #444444; 233 | } 234 | 235 | 236 | .navbar .nav > li > a { 237 | color: #c6c6c6; 238 | text-shadow: 0 1px 0 #444444; 239 | } 240 | 241 | .navbar .nav > li > a:focus, 242 | .navbar .nav > li > a:hover { 243 | color: white; 244 | } 245 | 246 | .navbar .nav > .active > a, 247 | .navbar .nav > .active > a:hover, 248 | .navbar .nav > .active > a:focus { 249 | color: white; 250 | background-color: #151515; 251 | } 252 | 253 | .navbar .btn-navbar { 254 | background-color: #292929; 255 | background-image: -moz-linear-gradient(top, #373737, #151515); 256 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#373737), to(#151515)); 257 | background-image: -webkit-linear-gradient(top, #373737, #151515); 258 | background-image: -o-linear-gradient(top, #373737, #151515); 259 | background-image: linear-gradient(to bottom, #373737, #151515); 260 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF373737', endColorstr='#FF151515', GradientType=0); 261 | border-color: #151515 #151515 black; 262 | *background-color: #151515; 263 | } 264 | .navbar .btn-navbar:hover, .navbar .btn-navbar:active, .navbar .btn-navbar.active, .navbar .btn-navbar.disabled, .navbar .btn-navbar[disabled] { 265 | background-color: #151515; 266 | *background-color: #090909; 267 | } 268 | .navbar .btn-navbar:active, .navbar .btn-navbar.active { 269 | background-color: black \9; 270 | } 271 | 272 | .navbar .nav li.dropdown > a:hover .caret { 273 | border-top-color: white; 274 | border-bottom-color: white; 275 | } 276 | 277 | .navbar .nav li.dropdown.open > .dropdown-toggle, 278 | .navbar .nav li.dropdown.active > .dropdown-toggle, 279 | .navbar .nav li.dropdown.open.active > .dropdown-toggle { 280 | background-color: #151515; 281 | color: white; 282 | } 283 | 284 | .navbar .nav li.dropdown > .dropdown-toggle .caret { 285 | border-top-color: #c6c6c6; 286 | border-bottom-color: #c6c6c6; 287 | } 288 | 289 | .navbar .nav li.dropdown.open > .dropdown-toggle .caret, 290 | .navbar .nav li.dropdown.active > .dropdown-toggle .caret, 291 | .navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { 292 | border-top-color: white; 293 | border-bottom-color: white; 294 | } 295 | 296 | .well { 297 | -webkit-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 298 | -moz-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 299 | box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 300 | background: #202020; 301 | background-color: rgba(0, 0, 0, 0.3); 302 | border: 0; 303 | } 304 | 305 | .darkwell, .breadcrumb, code, pre, select, 306 | input[type="text"], 307 | input[type="password"], 308 | input[type="datetime"], 309 | input[type="datetime-local"], 310 | input[type="date"], 311 | input[type="month"], 312 | input[type="time"], 313 | input[type="week"], 314 | input[type="number"], 315 | input[type="email"], 316 | input[type="url"], 317 | input[type="search"], 318 | input[type="tel"], 319 | input[type="color"], 320 | .uneditable-input, textarea, .hero-unit, .progress { 321 | -webkit-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 322 | -moz-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 323 | box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 324 | background: #202020; 325 | background-color: rgba(0, 0, 0, 0.3); 326 | border: 0; 327 | } 328 | 329 | .breadcrumb { 330 | border: 0; 331 | } 332 | .breadcrumb li { 333 | text-shadow: 0 1px 0 black; 334 | } 335 | 336 | .page-header { 337 | -webkit-box-shadow: rgba(255, 255, 255, 0.07) 0 1px 0; 338 | -moz-box-shadow: rgba(255, 255, 255, 0.07) 0 1px 0; 339 | box-shadow: rgba(255, 255, 255, 0.07) 0 1px 0; 340 | border-bottom: 1px solid #121212; 341 | } 342 | 343 | h1, h2, h3, h4, h5, h6 { 344 | color: white; 345 | } 346 | 347 | h6 { 348 | color: #999; 349 | } 350 | 351 | blockquote { 352 | border-left-color: #111; 353 | } 354 | blockquote.pull-right { 355 | border-right-color: #111; 356 | } 357 | 358 | hr { 359 | -webkit-box-shadow: rgba(255, 255, 255, 0.07) 0 1px 0; 360 | -moz-box-shadow: rgba(255, 255, 255, 0.07) 0 1px 0; 361 | box-shadow: rgba(255, 255, 255, 0.07) 0 1px 0; 362 | border-bottom: 1px solid #121212; 363 | border-top: none; 364 | } 365 | 366 | code { 367 | border: none; 368 | padding: 2px 4px; 369 | } 370 | 371 | pre { 372 | border: none; 373 | color: #c6c6c6; 374 | padding: 8px; 375 | } 376 | 377 | legend { 378 | -webkit-box-shadow: rgba(255, 255, 255, 0.07) 0 1px 0; 379 | -moz-box-shadow: rgba(255, 255, 255, 0.07) 0 1px 0; 380 | box-shadow: rgba(255, 255, 255, 0.07) 0 1px 0; 381 | border-bottom: 1px solid #121212; 382 | color: #fff; 383 | } 384 | 385 | select, 386 | input[type="text"], 387 | input[type="password"], 388 | input[type="datetime"], 389 | input[type="datetime-local"], 390 | input[type="date"], 391 | input[type="month"], 392 | input[type="time"], 393 | input[type="week"], 394 | input[type="number"], 395 | input[type="email"], 396 | input[type="url"], 397 | input[type="search"], 398 | input[type="tel"], 399 | input[type="color"], 400 | .uneditable-input { 401 | color: white; 402 | height: 21px; 403 | } 404 | select:-moz-placeholder, 405 | input[type="text"]:-moz-placeholder, 406 | input[type="password"]:-moz-placeholder, 407 | input[type="datetime"]:-moz-placeholder, 408 | input[type="datetime-local"]:-moz-placeholder, 409 | input[type="date"]:-moz-placeholder, 410 | input[type="month"]:-moz-placeholder, 411 | input[type="time"]:-moz-placeholder, 412 | input[type="week"]:-moz-placeholder, 413 | input[type="number"]:-moz-placeholder, 414 | input[type="email"]:-moz-placeholder, 415 | input[type="url"]:-moz-placeholder, 416 | input[type="search"]:-moz-placeholder, 417 | input[type="tel"]:-moz-placeholder, 418 | input[type="color"]:-moz-placeholder, 419 | .uneditable-input:-moz-placeholder { 420 | color: #666666; 421 | } 422 | select:-ms-input-placeholder, 423 | input[type="text"]:-ms-input-placeholder, 424 | input[type="password"]:-ms-input-placeholder, 425 | input[type="datetime"]:-ms-input-placeholder, 426 | input[type="datetime-local"]:-ms-input-placeholder, 427 | input[type="date"]:-ms-input-placeholder, 428 | input[type="month"]:-ms-input-placeholder, 429 | input[type="time"]:-ms-input-placeholder, 430 | input[type="week"]:-ms-input-placeholder, 431 | input[type="number"]:-ms-input-placeholder, 432 | input[type="email"]:-ms-input-placeholder, 433 | input[type="url"]:-ms-input-placeholder, 434 | input[type="search"]:-ms-input-placeholder, 435 | input[type="tel"]:-ms-input-placeholder, 436 | input[type="color"]:-ms-input-placeholder, 437 | .uneditable-input:-ms-input-placeholder { 438 | color: #666666; 439 | } 440 | select::-webkit-input-placeholder, 441 | input[type="text"]::-webkit-input-placeholder, 442 | input[type="password"]::-webkit-input-placeholder, 443 | input[type="datetime"]::-webkit-input-placeholder, 444 | input[type="datetime-local"]::-webkit-input-placeholder, 445 | input[type="date"]::-webkit-input-placeholder, 446 | input[type="month"]::-webkit-input-placeholder, 447 | input[type="time"]::-webkit-input-placeholder, 448 | input[type="week"]::-webkit-input-placeholder, 449 | input[type="number"]::-webkit-input-placeholder, 450 | input[type="email"]::-webkit-input-placeholder, 451 | input[type="url"]::-webkit-input-placeholder, 452 | input[type="search"]::-webkit-input-placeholder, 453 | input[type="tel"]::-webkit-input-placeholder, 454 | input[type="color"]::-webkit-input-placeholder, 455 | .uneditable-input::-webkit-input-placeholder { 456 | color: #666666; 457 | } 458 | 459 | textarea { 460 | color: white; 461 | } 462 | textarea:-moz-placeholder { 463 | color: #666666; 464 | } 465 | textarea:-ms-input-placeholder { 466 | color: #666666; 467 | } 468 | textarea::-webkit-input-placeholder { 469 | color: #666666; 470 | } 471 | 472 | select { 473 | height: 29px; 474 | } 475 | 476 | .input-prepend .add-on, 477 | .input-append .add-on { 478 | background: #444; 479 | color: #c6c6c6; 480 | border-color: #111; 481 | text-shadow: 0 1px 0 black; 482 | } 483 | 484 | .form-actions { 485 | border-top-color: #222; 486 | } 487 | 488 | .well .form-actions { 489 | border-top-color: #000; 490 | background-color: rgba(0, 0, 0, 0.3); 491 | margin-left: -17px; 492 | margin-right: -17px; 493 | margin-bottom: -17px; 494 | } 495 | 496 | .help-inline, 497 | .help-block { 498 | color: #999; 499 | } 500 | 501 | .control-group.warning input, .control-group.warning select, .control-group.warning textarea { 502 | color: #faa732; 503 | border-color: #faa732; 504 | -webkit-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 505 | -moz-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 506 | box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 507 | background: #202020; 508 | background-color: rgba(0, 0, 0, 0.3); 509 | } 510 | .control-group.warning input:focus, 511 | .control-group.warning select:focus, 512 | .control-group.warning textarea:focus { 513 | border-color: #faa732; 514 | -webkit-box-shadow: 0 0 6px #faa732; 515 | -moz-box-shadow: 0 0 6px #faa732; 516 | box-shadow: 0 0 6px #faa732; 517 | } 518 | .control-group.warning .control-label, 519 | .control-group.warning .help-block, 520 | .control-group.warning .help-inline { 521 | color: #faa732; 522 | } 523 | .control-group.success input, .control-group.success select, .control-group.success textarea { 524 | color: #5bb75b; 525 | border-color: #5bb75b; 526 | -webkit-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 527 | -moz-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 528 | box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 529 | background: #202020; 530 | background-color: rgba(0, 0, 0, 0.3); 531 | } 532 | .control-group.success input:focus, 533 | .control-group.success select:focus, 534 | .control-group.success textarea:focus { 535 | border-color: #5bb75b; 536 | -webkit-box-shadow: 0 0 6px #5bb75b; 537 | -moz-box-shadow: 0 0 6px #5bb75b; 538 | box-shadow: 0 0 6px #5bb75b; 539 | } 540 | .control-group.success .control-label, 541 | .control-group.success .help-block, 542 | .control-group.success .help-inline { 543 | color: #5bb75b; 544 | } 545 | .control-group.error input, .control-group.error select, .control-group.error textarea { 546 | color: #fc5b5e; 547 | border-color: #fc5b5e; 548 | -webkit-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 549 | -moz-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 550 | box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 551 | background: #202020; 552 | background-color: rgba(0, 0, 0, 0.3); 553 | } 554 | .control-group.error input:focus, 555 | .control-group.error select:focus, 556 | .control-group.error textarea:focus { 557 | border-color: #fc5b5e; 558 | -webkit-box-shadow: 0 0 6px #fc5b5e; 559 | -moz-box-shadow: 0 0 6px #fc5b5e; 560 | box-shadow: 0 0 6px #fc5b5e; 561 | } 562 | .control-group.error .control-label, 563 | .control-group.error .help-block, 564 | .control-group.error .help-inline { 565 | color: #fc5b5e; 566 | } 567 | .control-group.info input, .control-group.info select, .control-group.info textarea { 568 | color: #3a87ad; 569 | border-color: #3a87ad; 570 | -webkit-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 571 | -moz-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 572 | box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 7px 0px inset; 573 | background: #202020; 574 | background-color: rgba(0, 0, 0, 0.3); 575 | } 576 | .control-group.info input:focus, 577 | .control-group.info select:focus, 578 | .control-group.info textarea:focus { 579 | border-color: #3a87ad; 580 | -webkit-box-shadow: 0 0 6px #3a87ad; 581 | -moz-box-shadow: 0 0 6px #3a87ad; 582 | box-shadow: 0 0 6px #3a87ad; 583 | } 584 | .control-group.info .control-label, 585 | .control-group.info .help-block, 586 | .control-group.info .help-inline { 587 | color: #3a87ad; 588 | } 589 | 590 | input:focus:invalid, 591 | textarea:focus:invalid, 592 | select:focus:invalid { 593 | border-color: #fc5b5e; 594 | } 595 | 596 | input:focus:invalid:focus, 597 | textarea:focus:invalid:focus, 598 | select:focus:invalid:focus { 599 | border-color: #fc5b5e; 600 | box-shadow: 0 0 6px #fc5b5e; 601 | } 602 | 603 | .btn-link { 604 | text-shadow: none; 605 | } 606 | 607 | .img-polaroid { 608 | background-color: #111; 609 | background-color: rgba(0, 0, 0, 0.3); 610 | } 611 | 612 | .nav-tabs .open .dropdown-toggle, 613 | .nav-pills .open .dropdown-toggle, 614 | .nav > .open.active > a:hover { 615 | background-color: rgba(0, 0, 0, 0.25); 616 | border-color: transparent transparent #666666 transparent; 617 | } 618 | 619 | .nav > .dropdown.active > a:hover { 620 | color: #fff; 621 | } 622 | 623 | .nav-tabs .active .dropdown-toggle .caret, 624 | .nav-pills .active .dropdown-toggle .caret { 625 | border-top-color: #fff; 626 | } 627 | 628 | .nav-tabs { 629 | border-bottom: 1px solid #666666; 630 | } 631 | .nav-tabs > .active > a, .nav-tabs > .active > a:hover { 632 | background-color: #2f2f2f; 633 | color: #fff; 634 | border-color: #666666 #666666 transparent #666666; 635 | } 636 | .nav-tabs > li > a:hover { 637 | border-color: #2f2f2f #2f2f2f #666666 #2f2f2f; 638 | background-color: rgba(0, 0, 0, 0.25); 639 | color: #00aaff; 640 | } 641 | .nav-tabs.nav-stacked > li > a, .nav-tabs.nav-stacked > li > a:hover { 642 | border-color: #666; 643 | } 644 | 645 | .well > .nav-tabs > .active > a, .well > .nav-tabs > .active > a:hover { 646 | background-color: #202020; 647 | } 648 | 649 | .nav-pills > li > a:hover { 650 | background-color: rgba(0, 0, 0, 0.25); 651 | color: #00aaff; 652 | } 653 | 654 | .nav-list > li > a, 655 | .nav-list .nav-header { 656 | text-shadow: 0 1px 0 black; 657 | } 658 | 659 | .nav-list > li > a:hover { 660 | background-color: rgba(0, 0, 0, 0.25); 661 | color: #00aaff; 662 | } 663 | 664 | .nav-list .active > a:hover { 665 | background-color: #0088cc; 666 | color: white; 667 | } 668 | 669 | .tabs-below .nav-tabs { 670 | border-top: 1px solid #666666; 671 | } 672 | 673 | .tabs-left .nav-tabs { 674 | border-right: 1px solid #666666; 675 | } 676 | 677 | .tabs-right .nav-tabs { 678 | border-left: 1px solid #666666; 679 | } 680 | 681 | .tabs-below .nav-tabs > li > a:hover { 682 | border-top: 1px solid #666666; 683 | } 684 | 685 | .tabs-left .nav-tabs > li > a:hover { 686 | border-color: transparent #666666 transparent transparent; 687 | } 688 | 689 | .tabs-right .nav-tabs > li > a:hover { 690 | border-color: transparent transparent transparent #666666; 691 | } 692 | 693 | .tabs-below .nav-tabs .active > a, 694 | .tabs-below .nav-tabs .active > a:hover { 695 | border-color: transparent #666666 #666666 #666666; 696 | } 697 | 698 | .tabs-left .nav-tabs .active > a, 699 | .tabs-left .nav-tabs .active > a:hover { 700 | border-color: #666666 transparent #666666 #666666; 701 | } 702 | 703 | .tabs-right .nav-tabs .active > a, 704 | .tabs-right .nav-tabs .active > a:hover { 705 | border-color: #666666 #666666 #666666 transparent; 706 | } 707 | 708 | .nav-list > li > a, 709 | .nav-list .nav-header { 710 | text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5); 711 | } 712 | 713 | .nav-tabs > li > a:hover { 714 | border-color: transparent transparent #666666 transparent; 715 | } 716 | 717 | .nav > .disabled > a:hover { 718 | color: #999; 719 | } 720 | 721 | .nav-list .divider { 722 | background-color: transparent; 723 | -webkit-box-shadow: rgba(255, 255, 255, 0.07) 0 1px 0; 724 | -moz-box-shadow: rgba(255, 255, 255, 0.07) 0 1px 0; 725 | box-shadow: rgba(255, 255, 255, 0.07) 0 1px 0; 726 | border-bottom: 1px solid #121212; 727 | } 728 | 729 | .navbar .brand { 730 | text-shadow: 0 1px 0 black; 731 | } 732 | 733 | .navbar .divider-vertical { 734 | border: transparent; 735 | -webkit-box-shadow: rgba(255, 255, 255, 0.07) 1px 0 0; 736 | -moz-box-shadow: rgba(255, 255, 255, 0.07) 1px 0 0; 737 | box-shadow: rgba(255, 255, 255, 0.07) 1px 0 0; 738 | border-right: 1px solid #121212; 739 | } 740 | 741 | .navbar-inverse .brand { 742 | color: #555; 743 | text-shadow: 0 1px 0 white; 744 | } 745 | .navbar-inverse .brand:hover { 746 | color: #555; 747 | } 748 | .navbar-inverse .navbar-inner { 749 | background: #fafafa; 750 | border: 1px solid #030303; 751 | box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5); 752 | background: -moz-linear-gradient(top, white 0%, #999999 100%); 753 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #999999)); 754 | background: -webkit-linear-gradient(top, white 0%, #999999 100%); 755 | background: -o-linear-gradient(top, white 0%, #999999 100%); 756 | background: -ms-linear-gradient(top, white 0%, #999999 100%); 757 | background: linear-gradient(to bottom, #ffffff 0%, #999999 100%); 758 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#999999',GradientType=0 ); 759 | } 760 | .navbar-inverse .nav > li > a { 761 | color: #555; 762 | } 763 | .navbar-inverse .nav > li > a:hover { 764 | color: #333; 765 | } 766 | .navbar-inverse .nav > .active > a, 767 | .navbar-inverse .nav > .active > a:hover { 768 | background-color: #e5e5e5; 769 | box-shadow: 0 3px 8px rgba(0, 0, 0, 0.125) inset; 770 | color: #555555; 771 | } 772 | .navbar-inverse .nav li.dropdown.open > .dropdown-toggle, 773 | .navbar-inverse .nav li.dropdown.active > .dropdown-toggle, 774 | .navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { 775 | background-color: #e5e5e5; 776 | color: #555; 777 | } 778 | .navbar-inverse .nav li.dropdown > a:hover .caret { 779 | border-top-color: #555; 780 | color: #555; 781 | } 782 | .navbar-inverse .nav > li > a:focus, 783 | .navbar-inverse .nav > li > a:hover { 784 | background-color: transparent; 785 | color: #333; 786 | } 787 | .navbar-inverse .nav li.dropdown.open > .dropdown-toggle, 788 | .navbar-inverse .nav li.dropdown.active > .dropdown-toggle, 789 | .navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { 790 | background-color: #e5e5e5; 791 | color: #555; 792 | } 793 | .navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, 794 | .navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret, 795 | .navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret { 796 | border-bottom-color: #555; 797 | border-top-color: #555; 798 | color: #555; 799 | } 800 | .navbar-inverse .navbar-search .search-query { 801 | box-shadow: 0 3px 8px rgba(0, 0, 0, 0.6) inset; 802 | background-color: white; 803 | color: #333; 804 | } 805 | .navbar-inverse .navbar-search input.search-query:focus { 806 | box-shadow: 0 3px 8px rgba(0, 0, 0, 0.6) inset, 0 0 8px rgba(82, 168, 236, 0.6); 807 | box-shadow: 0 3px 8px rgba(0, 0, 0, 0.6) inset, 0 0 8px rgba(82, 168, 236, 0.9); 808 | padding: 4px 14px; 809 | outline: 0 none; 810 | } 811 | .navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { 812 | border-bottom-color: #555; 813 | border-top-color: #555; 814 | } 815 | .navbar-inverse .nav li.dropdown > a:hover .caret { 816 | border-bottom-color: #333; 817 | border-top-color: #333; 818 | } 819 | .navbar-inverse .navbar-search .search-query:-moz-placeholder { 820 | color: #999; 821 | } 822 | 823 | .pagination ul > li > a, 824 | .pagination ul > li > span { 825 | background: transparent; 826 | border-color: #666; 827 | } 828 | 829 | .pagination ul > li > a:hover, 830 | .pagination ul > .active > a, 831 | .pagination ul > .active > span { 832 | background-color: rgba(0, 0, 0, 0.25); 833 | } 834 | 835 | .pager li > a, .pager li > span { 836 | background-color: transparent; 837 | border-color: #666; 838 | } 839 | 840 | .pager li > a:hover { 841 | background-color: rgba(0, 0, 0, 0.25); 842 | } 843 | 844 | .pager .disabled > a, 845 | .pager .disabled > a:hover, 846 | .pager .disabled > span { 847 | background-color: transparent; 848 | } 849 | 850 | .label, 851 | .badge { 852 | text-shadow: 1px 1px 0 black; 853 | box-shadow: 1px 1px 0 black; 854 | } 855 | 856 | .label-inverse, 857 | .badge-inverse { 858 | background-color: #111; 859 | } 860 | 861 | .hero-unit { 862 | background: #111; 863 | color: #ccc; 864 | } 865 | 866 | .thumbnail { 867 | border-color: #666; 868 | box-shadow: 0 1px 3px black; 869 | } 870 | .thumbnail .caption { 871 | color: #999; 872 | } 873 | 874 | .alert { 875 | color: white; 876 | border-color: #a86404; 877 | text-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); 878 | } 879 | .alert h1, .alert h2, .alert h3, .alert h4, .alert h5, .alert h6 { 880 | color: #c17305; 881 | } 882 | 883 | .alert-error { 884 | border-color: #d40408; 885 | } 886 | .alert-error h1, .alert-error h2, .alert-error h3, .alert-error h4, .alert-error h5, .alert-error h6 { 887 | color: #ed0409; 888 | } 889 | 890 | .alert-success { 891 | border-color: #2d662d; 892 | } 893 | .alert-success h1, .alert-success h2, .alert-success h3, .alert-success h4, .alert-success h5, .alert-success h6 { 894 | color: #347834; 895 | } 896 | 897 | .alert-info { 898 | border-color: #1a3c4e; 899 | } 900 | .alert-info h1, .alert-info h2, .alert-info h3, .alert-info h4, .alert-info h5, .alert-info h6 { 901 | color: #204B61; 902 | } 903 | 904 | select::-webkit-scrollbar { 905 | -webkit-appearance: none; 906 | width: 11px; 907 | } 908 | select::-webkit-scrollbar-thumb { 909 | border-radius: 8px; 910 | border: 2px solid #202020; 911 | background-color: rgba(0, 0, 0, 0.5); 912 | } 913 | 914 | .modal { 915 | background-color: #444; 916 | } 917 | 918 | .modal-header { 919 | border-bottom: 1px solid #222222; 920 | } 921 | 922 | .modal-body p { 923 | color: #c6c6c6; 924 | } 925 | 926 | .modal-footer { 927 | background-color: #373737; 928 | border-top: 1px solid #222222; 929 | -moz-box-shadow: 0 1px 0 #333333 inset; 930 | -webkit-box-shadow: 0 1px 0 #333333 inset; 931 | -o-box-shadow: 0 1px 0 #333333 inset; 932 | box-shadow: 0 1px 0 #333333 inset; 933 | } 934 | 935 | .popover { 936 | background: #444; 937 | border: 1px solid rgba(0, 0, 0, 0.5); 938 | border: 1px solid black; 939 | } 940 | 941 | .popover-title { 942 | background: #373737; 943 | border-bottom-color: #222; 944 | } 945 | 946 | .popover.top .arrow:after { 947 | border-top-color: #444; 948 | } 949 | 950 | .popover.right .arrow:after { 951 | border-right-color: #444; 952 | } 953 | 954 | .popover.bottom .arrow:after { 955 | border-bottom-color: #444; 956 | } 957 | 958 | .popover.left .arrow:after { 959 | border-left-color: #444; 960 | } 961 | -------------------------------------------------------------------------------- /docs/gen/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Menlo, Monaco, Consolas, monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /docs/gen/styles/sunlight.dark.css: -------------------------------------------------------------------------------- 1 | /* global styles */ 2 | .sunlight-container { 3 | clear: both !important; 4 | position: relative !important; 5 | margin: 10px 0 !important; 6 | } 7 | .sunlight-code-container { 8 | clear: both !important; 9 | position: relative !important; 10 | border: none; 11 | border-color: #626262 !important; 12 | background-color: #262626 !important; 13 | } 14 | .sunlight-highlighted, .sunlight-container, .sunlight-container textarea { 15 | font-family: Consolas, Inconsolata, Monaco, "Courier New" !important; 16 | font-size: 12px !important; 17 | line-height: 15px !important; 18 | } 19 | .sunlight-highlighted, .sunlight-container textarea { 20 | color: #FFFFFF !important; 21 | margin: 0 !important; 22 | } 23 | .sunlight-container textarea { 24 | padding-left: 0 !important; 25 | margin-left: 0 !important; 26 | margin-right: 0 !important; 27 | padding-right: 0 !important; 28 | } 29 | .sunlight-code-container > .sunlight-highlighted { 30 | white-space: pre; 31 | overflow-x: auto; 32 | overflow-y: hidden; /* ie requires this wtf? */ 33 | } 34 | .sunlight-highlighted { 35 | z-index: 1; 36 | position: relative; 37 | } 38 | .sunlight-highlighted * { 39 | background: transparent; 40 | } 41 | .sunlight-line-number-margin { 42 | float: left !important; 43 | margin-right: 5px !important; 44 | margin-top: 0 !important; 45 | margin-bottom: 0 !important; 46 | padding: 0 !important; 47 | padding-right: 4px !important; 48 | padding-left: 4px !important; 49 | border-right: 1px solid #9A9A9A !important; 50 | background-color: #3E3E3E !important; 51 | color: #9A9A9A !important; 52 | text-align: right !important; 53 | position: relative; 54 | z-index: 3; 55 | } 56 | .sunlight-highlighted a, .sunlight-line-number-margin a { 57 | border: none !important; 58 | text-decoration: none !important; 59 | font-style: normal !important; 60 | padding: 0 !important; 61 | } 62 | .sunlight-line-number-margin a { 63 | color: inherit !important; 64 | } 65 | .sunlight-line-highlight-overlay { 66 | position: absolute; 67 | top: 0; 68 | left: 0; 69 | width: 100%; 70 | z-index: 0; 71 | } 72 | .sunlight-line-highlight-overlay div { 73 | height: 15px; 74 | width: 100%; 75 | } 76 | .sunlight-line-highlight-overlay .sunlight-line-highlight-active { 77 | background-color: #4B4B4B; 78 | } 79 | 80 | /* menu */ 81 | .sunlight-menu { 82 | background-color: #FFFFCC; 83 | color: #000000; 84 | } 85 | .sunlight-menu ul { 86 | margin: 0 !important; 87 | padding: 0 !important; 88 | list-style-type: none !important; 89 | } 90 | .sunlight-menu li { 91 | float: right !important; 92 | margin-left: 5px !important; 93 | } 94 | .sunlight-menu a, .sunlight-menu img { 95 | color: #000099 !important; 96 | text-decoration: none !important; 97 | border: none !important; 98 | } 99 | 100 | 101 | 102 | 103 | .sunlight-string, 104 | .sunlight-char, 105 | .sunlight-heredoc, 106 | .sunlight-heredocDeclaration, 107 | .sunlight-nowdoc, 108 | .sunlight-longString, 109 | .sunlight-rawString, 110 | .sunlight-binaryString, 111 | .sunlight-verbatimString, 112 | .sunlight-rawLongString, 113 | .sunlight-binaryLongString, 114 | .sunlight-diff .sunlight-added { 115 | color: #55EB54 !important; 116 | } 117 | .sunlight-operator, 118 | .sunlight-punctuation, 119 | .sunlight-delimiter { 120 | color: #B1EDEC !important; 121 | } 122 | .sunlight-ident, 123 | .sunlight-diff .sunlight-unchanged { 124 | color: #E0E0E0 !important; 125 | font-weight: bold !important; 126 | } 127 | .sunlight-comment, 128 | .sunlight-xmlDocCommentContent, 129 | .sunlight-nginx .sunlight-ssiCommand, 130 | .sunlight-sln .sunlight-formatDeclaration, 131 | .sunlight-diff .sunlight-mergeHeader, 132 | .sunlight-diff .sunlight-noNewLine { 133 | color: #787D31 !important; 134 | } 135 | .sunlight-number, 136 | .sunlight-cdata, 137 | .sunlight-guid, 138 | .sunlight-diff .sunlight-modified { 139 | color: #F7BA7E !important; 140 | font-weight: bold !important; 141 | } 142 | .sunlight-named-ident, 143 | .sunlight-xml .sunlight-attribute, 144 | .sunlight-constant, 145 | .sunlight-javascript .sunlight-globalVariable, 146 | .sunlight-globalObject, 147 | .sunlight-css .sunlight-id, 148 | .sunlight-python .sunlight-attribute, 149 | .sunlight-nginx .sunlight-context, 150 | .sunlight-httpd .sunlight-context, 151 | .sunlight-lisp .sunlight-declarationSpecifier, 152 | .sunlight-erlang .sunlight-userDefinedFunction, 153 | .sunlight-diff .sunlight-removed { 154 | color: #FBBDEE !important; 155 | font-weight: bold !important; 156 | } 157 | .sunlight-keyword, 158 | .sunlight-languageConstruct, 159 | .sunlight-specialOperator, 160 | .sunlight-xml .sunlight-tagName, 161 | .sunlight-xml .sunlight-operator, 162 | .sunlight-bash .sunlight-command, 163 | .sunlight-erlang .sunlight-moduleAttribute { 164 | color: #A3CCF7 !important; 165 | font-weight: bold !important; 166 | } 167 | .sunlight-shortOpenTag, 168 | .sunlight-openTag, 169 | .sunlight-closeTag, 170 | .sunlight-xmlOpenTag, 171 | .sunlight-xmlCloseTag, 172 | .sunlight-aspOpenTag, 173 | .sunlight-aspCloseTag, 174 | .sunlight-label, 175 | .sunlight-css .sunlight-importantFlag { 176 | background-color: #7373C1 !important; 177 | } 178 | .sunlight-content { 179 | color: #FFFFFF !important; 180 | font-weight: bold !important; 181 | } 182 | .sunlight-function, 183 | .sunlight-globalFunction, 184 | .sunlight-objective-c .sunlight-messageDestination, 185 | .sunlight-ruby .sunlight-specialFunction, 186 | .sunlight-6502asm .sunlight-illegalOpcode, 187 | .sunlight-powershell .sunlight-switch, 188 | .sunlight-lisp .sunlight-macro, 189 | .sunlight-lisp .sunlight-specialForm, 190 | .sunlight-lisp .sunlight-type, 191 | .sunlight-sln .sunlight-sectionName, 192 | .sunlight-diff .sunlight-header { 193 | color: #C8BBF1 !important; 194 | font-weight: bold !important; 195 | } 196 | .sunlight-variable, 197 | .sunlight-environmentVariable, 198 | .sunlight-specialVariable, 199 | .sunlight-objective-c .sunlight-messageArgumentName, 200 | .sunlight-lisp .sunlight-globalVariable, 201 | .sunlight-ruby .sunlight-globalVariable, 202 | .sunlight-ruby .sunlight-instanceVariable { 203 | color: #F5E5B0 !important; 204 | font-weight: bold !important; 205 | } 206 | .sunlight-regexLiteral, 207 | .sunlight-lisp .sunlight-operator, 208 | .sunlight-6502asm .sunlight-pseudoOp, 209 | .sunlight-erlang .sunlight-macro, 210 | .sunlight-diff .sunlight-rangeInfo { 211 | color: #E0F16A !important; 212 | } 213 | .sunlight-specialVariable { 214 | font-style: italic !important; 215 | font-weight: bold !important; 216 | } 217 | .sunlight-csharp .sunlight-pragma, 218 | .sunlight-preprocessorDirective, 219 | .sunlight-vb .sunlight-compilerDirective { 220 | color: #666363 !important; 221 | font-style: italic !important; 222 | } 223 | .sunlight-xmlDocCommentMeta, 224 | .sunlight-java .sunlight-annotation, 225 | .sunlight-scala .sunlight-annotation, 226 | .sunlight-docComment { 227 | color: #666363 !important; 228 | } 229 | .sunlight-quotedIdent, 230 | .sunlight-ruby .sunlight-subshellCommand, 231 | .sunlight-lisp .sunlight-keywordArgument, 232 | .sunlight-haskell .sunlight-infixOperator, 233 | .sunlight-erlang .sunlight-quotedAtom { 234 | color: #F8CA16 !important; 235 | } 236 | 237 | 238 | 239 | 240 | /* html/xml */ 241 | .sunlight-xml .sunlight-tagName, 242 | .sunlight-xml .sunlight-operator, 243 | .sunlight-xml .sunlight-attribute { 244 | font-weight: normal !important; 245 | } 246 | .sunlight-doctype { 247 | color: #DEB9B2 !important; 248 | font-style: italic !important; 249 | } 250 | .sunlight-xml .sunlight-entity { 251 | background-color: #E6E585 !important; 252 | color: #000000 !important; 253 | } 254 | 255 | /* javascript */ 256 | .sunlight-javascript .sunlight-reservedWord { 257 | font-style: italic !important; 258 | } 259 | 260 | /* css */ 261 | .sunlight-css .sunlight-element { 262 | color: #E9EE97 !important; 263 | } 264 | .sunlight-css .sunlight-microsoftFilterPrefix { 265 | color: #C9FF9F !important; 266 | } 267 | .sunlight-css .sunlight-rule { 268 | color: #0099FF !important; 269 | } 270 | .sunlight-css .sunlight-class { 271 | color: #E78282 !important; 272 | } 273 | .sunlight-css .sunlight-pseudoClass, .sunlight-css .sunlight-pseudoElement { 274 | color: #73D693 !important; 275 | } 276 | 277 | /* bash */ 278 | .sunlight-bash .sunlight-hashBang { 279 | color: #FFFF00 !important; 280 | } 281 | 282 | .sunlight-bash .sunlight-verbatimCommand { 283 | color: #BBA4EE !important; 284 | } 285 | .sunlight-bash .sunlight-variable, 286 | .sunlight-bash .sunlight-specialVariable { 287 | color: #ED8585 !important; 288 | } 289 | 290 | /* python */ 291 | .sunlight-python .sunlight-specialMethod { 292 | font-weight: bold !important; 293 | color: #B0A3C2; 294 | } 295 | 296 | /* ruby */ 297 | .sunlight-ruby .sunlight-symbol { 298 | font-weight: bold !important; 299 | color: #90EEA2 !important; 300 | } 301 | 302 | /* brainfuck */ 303 | .sunlight-brainfuck { 304 | font-weight: bold !important; 305 | color: #000000 !important; 306 | } 307 | .sunlight-brainfuck .sunlight-increment { 308 | background-color: #FF9900 !important; 309 | } 310 | .sunlight-brainfuck .sunlight-decrement { 311 | background-color: #FF99FF !important; 312 | } 313 | .sunlight-brainfuck .sunlight-incrementPointer { 314 | background-color: #FFFF99 !important; 315 | } 316 | .sunlight-brainfuck .sunlight-decrementPointer { 317 | background-color: #66CCFF !important; 318 | } 319 | .sunlight-brainfuck .sunlight-read { 320 | background-color: #FFFFFF !important; 321 | } 322 | .sunlight-brainfuck .sunlight-write { 323 | background-color: #99FF99 !important; 324 | } 325 | .sunlight-brainfuck .sunlight-openLoop, .sunlight-brainfuck .sunlight-closeLoop { 326 | background-color: #FFFFFF !important; 327 | } 328 | 329 | /* 6502 asm */ 330 | .sunlight-6502asm .sunlight-label { 331 | background: none !important; 332 | color: #FFFFFF !important; 333 | text-decoration: underline !important; 334 | } 335 | 336 | /* lisp */ 337 | .sunlight-lisp .sunlight-macro { 338 | font-style: italic !important; 339 | } 340 | 341 | /* erlang */ 342 | .sunlight-erlang .sunlight-atom { 343 | color: #FFFFFF !important; 344 | font-weight: bold !important; 345 | } -------------------------------------------------------------------------------- /docs/gen/styles/sunlight.default.css: -------------------------------------------------------------------------------- 1 | /* global styles */ 2 | .sunlight-container { 3 | clear: both !important; 4 | position: relative !important; 5 | margin: 10px 0 !important; 6 | } 7 | .sunlight-code-container { 8 | clear: both !important; 9 | position: relative !important; 10 | border: none; 11 | border-color: #969696 !important; 12 | background-color: #FFFFFF !important; 13 | } 14 | .sunlight-highlighted, .sunlight-container, .sunlight-container textarea { 15 | font-family: Consolas, Inconsolata, Monaco, "Courier New" !important; 16 | font-size: 12px !important; 17 | line-height: 15px !important; 18 | } 19 | .sunlight-highlighted, .sunlight-container textarea { 20 | color: #000000 !important; 21 | margin: 0 !important; 22 | } 23 | .sunlight-container textarea { 24 | padding-left: 0 !important; 25 | margin-left: 0 !important; 26 | margin-right: 0 !important; 27 | padding-right: 0 !important; 28 | } 29 | .sunlight-code-container > .sunlight-highlighted { 30 | white-space: pre; 31 | overflow-x: auto; 32 | overflow-y: hidden; /* ie requires this wtf? */ 33 | } 34 | .sunlight-highlighted { 35 | z-index: 1; 36 | position: relative; 37 | } 38 | .sunlight-highlighted * { 39 | background: transparent; 40 | } 41 | .sunlight-line-number-margin { 42 | float: left !important; 43 | margin-right: 5px !important; 44 | margin-top: 0 !important; 45 | margin-bottom: 0 !important; 46 | padding: 0 !important; 47 | padding-right: 4px !important; 48 | padding-left: 4px !important; 49 | border-right: 1px solid #CCCCCC !important; 50 | background-color: #EEEEEE !important; 51 | color: #848484 !important; 52 | text-align: right !important; 53 | position: relative; 54 | z-index: 3; 55 | } 56 | .sunlight-highlighted a, .sunlight-line-number-margin a { 57 | border: none !important; 58 | text-decoration: none !important; 59 | font-weight: normal !important; 60 | font-style: normal !important; 61 | padding: 0 !important; 62 | } 63 | .sunlight-line-number-margin a { 64 | color: inherit !important; 65 | } 66 | .sunlight-line-highlight-overlay { 67 | position: absolute; 68 | top: 0; 69 | left: 0; 70 | width: 100%; 71 | z-index: 0; 72 | } 73 | .sunlight-line-highlight-overlay div { 74 | height: 15px; 75 | width: 100%; 76 | } 77 | .sunlight-line-highlight-overlay .sunlight-line-highlight-active { 78 | background-color: #E7FCFA; 79 | } 80 | 81 | /* menu */ 82 | .sunlight-menu { 83 | background-color: #FFFFCC; 84 | color: #000000; 85 | } 86 | .sunlight-menu ul { 87 | margin: 0 !important; 88 | padding: 0 !important; 89 | list-style-type: none !important; 90 | } 91 | .sunlight-menu li { 92 | float: right !important; 93 | margin-left: 5px !important; 94 | } 95 | .sunlight-menu a, .sunlight-menu img { 96 | color: #000099 !important; 97 | text-decoration: none !important; 98 | border: none !important; 99 | } 100 | 101 | 102 | 103 | 104 | .sunlight-string, 105 | .sunlight-char, 106 | .sunlight-heredoc, 107 | .sunlight-heredocDeclaration, 108 | .sunlight-nowdoc, 109 | .sunlight-longString, 110 | .sunlight-rawString, 111 | .sunlight-binaryString, 112 | .sunlight-rawLongString, 113 | .sunlight-binaryLongString, 114 | .sunlight-verbatimString, 115 | .sunlight-diff .sunlight-removed { 116 | color: #990000 !important; 117 | } 118 | 119 | .sunlight-ident, 120 | .sunlight-operator, 121 | .sunlight-punctuation, 122 | .sunlight-delimiter, 123 | .sunlight-diff .sunlight-unchanged { 124 | color: #000000 !important; 125 | } 126 | 127 | .sunlight-comment, 128 | .sunlight-xmlDocCommentContent, 129 | .sunlight-nginx .sunlight-ssiCommand, 130 | .sunlight-sln .sunlight-formatDeclaration, 131 | .sunlight-diff .sunlight-added { 132 | color: #009900 !important; 133 | } 134 | .sunlight-number, 135 | .sunlight-guid, 136 | .sunlight-cdata { 137 | color: #CC6600 !important; 138 | } 139 | 140 | .sunlight-named-ident, 141 | .sunlight-constant, 142 | .sunlight-javascript .sunlight-globalVariable, 143 | .sunlight-globalObject, 144 | .sunlight-python .sunlight-attribute, 145 | .sunlight-nginx .sunlight-context, 146 | .sunlight-httpd .sunlight-context, 147 | .sunlight-haskell .sunlight-class, 148 | .sunlight-haskell .sunlight-type, 149 | .sunlight-lisp .sunlight-declarationSpecifier, 150 | .sunlight-erlang .sunlight-userDefinedFunction, 151 | .sunlight-diff .sunlight-header { 152 | color: #2B91AF !important; 153 | } 154 | .sunlight-keyword, 155 | .sunlight-languageConstruct, 156 | .sunlight-css 157 | .sunlight-element, 158 | .sunlight-bash .sunlight-command, 159 | .sunlight-specialOperator, 160 | .sunlight-erlang .sunlight-moduleAttribute, 161 | .sunlight-xml .sunlight-tagName, 162 | .sunlight-xml .sunlight-operator, 163 | .sunlight-diff .sunlight-modified { 164 | color: #0000FF !important; 165 | } 166 | .sunlight-shortOpenTag, 167 | .sunlight-openTag, 168 | .sunlight-closeTag, 169 | .sunlight-xmlOpenTag, 170 | .sunlight-xmlCloseTag, 171 | .sunlight-aspOpenTag, 172 | .sunlight-aspCloseTag, 173 | .sunlight-label, 174 | .sunlight-css .sunlight-importantFlag { 175 | background-color: #FFFF99 !important; 176 | color: #000000 !important; 177 | } 178 | .sunlight-function, 179 | .sunlight-globalFunction, 180 | .sunlight-ruby .sunlight-specialFunction, 181 | .sunlight-objective-c .sunlight-messageDestination, 182 | .sunlight-6502asm .sunlight-illegalOpcode, 183 | .sunlight-powershell .sunlight-switch, 184 | .sunlight-lisp .sunlight-macro, 185 | .sunlight-lisp .sunlight-specialForm, 186 | .sunlight-lisp .sunlight-type, 187 | .sunlight-sln .sunlight-sectionName, 188 | .sunlight-diff .sunlight-rangeInfo { 189 | color: #B069AF !important; 190 | } 191 | 192 | .sunlight-variable, 193 | .sunlight-specialVariable, 194 | .sunlight-environmentVariable, 195 | .sunlight-objective-c .sunlight-messageArgumentName, 196 | .sunlight-lisp .sunlight-globalVariable, 197 | .sunlight-ruby .sunlight-globalVariable, 198 | .sunlight-ruby .sunlight-instanceVariable, 199 | .sunlight-sln .sunlight-operator { 200 | color: #325484 !important; 201 | } 202 | .sunlight-regexLiteral, 203 | .sunlight-lisp .sunlight-operator, 204 | .sunlight-6502asm .sunlight-pseudoOp, 205 | .sunlight-erlang .sunlight-macro { 206 | color: #FF00B2 !important; 207 | } 208 | .sunlight-specialVariable { 209 | font-style: italic !important; 210 | font-weight: bold !important; 211 | } 212 | .sunlight-csharp .sunlight-pragma, 213 | .sunlight-preprocessorDirective, 214 | .sunlight-vb .sunlight-compilerDirective, 215 | .sunlight-diff .sunlight-mergeHeader, 216 | .sunlight-diff .sunlight-noNewLine { 217 | color: #999999 !important; 218 | font-style: italic !important; 219 | } 220 | .sunlight-xmlDocCommentMeta, 221 | .sunlight-java .sunlight-annotation, 222 | .sunlight-scala .sunlight-annotation, 223 | .sunlight-docComment { 224 | color: #808080 !important; 225 | } 226 | .sunlight-quotedIdent, 227 | .sunlight-ruby .sunlight-subshellCommand, 228 | .sunlight-lisp .sunlight-keywordArgument, 229 | .sunlight-haskell .sunlight-infixOperator, 230 | .sunlight-erlang .sunlight-quotedAtom { 231 | color: #999900 !important; 232 | } 233 | 234 | 235 | 236 | /* xml */ 237 | .sunlight-xml .sunlight-string { 238 | color: #990099 !important; 239 | } 240 | .sunlight-xml .sunlight-attribute { 241 | color: #FF0000 !important; 242 | } 243 | .sunlight-xml .sunlight-entity { 244 | background-color: #EEEEEE !important; 245 | color: #000000 !important; 246 | border: 1px solid #000000 !important; 247 | } 248 | .sunlight-xml .sunlight-doctype { 249 | color: #2B91AF !important; 250 | } 251 | 252 | /* javascript */ 253 | .sunlight-javascript .sunlight-reservedWord { 254 | font-style: italic !important; 255 | } 256 | 257 | /* css */ 258 | .sunlight-css .sunlight-microsoftFilterPrefix { 259 | color: #FF00FF !important; 260 | } 261 | .sunlight-css .sunlight-rule { 262 | color: #0099FF !important; 263 | } 264 | .sunlight-css .sunlight-keyword { 265 | color: #4E65B8 !important; 266 | } 267 | .sunlight-css .sunlight-class { 268 | color: #FF0000 !important; 269 | } 270 | .sunlight-css .sunlight-id { 271 | color: #8A8E13 !important; 272 | } 273 | .sunlight-css .sunlight-pseudoClass, 274 | .sunlight-css .sunlight-pseudoElement { 275 | color: #368B87 !important; 276 | } 277 | 278 | /* bash */ 279 | .sunlight-bash .sunlight-hashBang { 280 | color: #3D97F5 !important; 281 | } 282 | .sunlight-bash .sunlight-verbatimCommand { 283 | color: #999900 !important; 284 | } 285 | .sunlight-bash .sunlight-variable, 286 | .sunlight-bash .sunlight-specialVariable { 287 | color: #FF0000 !important; 288 | } 289 | 290 | /* python */ 291 | .sunlight-python .sunlight-specialMethod { 292 | font-weight: bold !important; 293 | color: #A07DD3; 294 | } 295 | 296 | /* ruby */ 297 | .sunlight-ruby .sunlight-symbol { 298 | font-weight: bold !important; 299 | color: #ED7272 !important; 300 | } 301 | 302 | /* brainfuck */ 303 | .sunlight-brainfuck { 304 | font-weight: bold !important; 305 | color: #000000 !important; 306 | } 307 | .sunlight-brainfuck .sunlight-increment { 308 | background-color: #FF9900 !important; 309 | } 310 | .sunlight-brainfuck .sunlight-decrement { 311 | background-color: #FF99FF !important; 312 | } 313 | .sunlight-brainfuck .sunlight-incrementPointer { 314 | background-color: #FFFF99 !important; 315 | } 316 | .sunlight-brainfuck .sunlight-decrementPointer { 317 | background-color: #66CCFF !important; 318 | } 319 | .sunlight-brainfuck .sunlight-read { 320 | background-color: #FFFFFF !important; 321 | } 322 | .sunlight-brainfuck .sunlight-write { 323 | background-color: #99FF99 !important; 324 | } 325 | .sunlight-brainfuck .sunlight-openLoop, .sunlight-brainfuck .sunlight-closeLoop { 326 | background-color: #FFFFFF !important; 327 | } 328 | 329 | /* 6502 asm */ 330 | .sunlight-6502asm .sunlight-label { 331 | font-weight: bold !important; 332 | color: #000000 !important; 333 | background: none !important; 334 | } 335 | 336 | /* lisp */ 337 | .sunlight-lisp .sunlight-macro { 338 | font-style: italic !important; 339 | } 340 | 341 | /* erlang */ 342 | .sunlight-erlang .sunlight-atom { 343 | font-weight: bold !important; 344 | } -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require("gulp"); 2 | var exec = require("child_process").exec; 3 | var jsdoc = require("gulp-jsdoc3"); 4 | 5 | gulp.task("webpack", function (callback) { 6 | exec("webpack", function (err) { 7 | if (err != null) { 8 | callback(err); 9 | return; 10 | } 11 | callback(); 12 | }); 13 | }); 14 | 15 | gulp.task("jsdoc", ["webpack"], function (callback) { 16 | gulp.src(["./README.md", "./library/**/*.js"], { read: false }).pipe(jsdoc(callback)); 17 | }); 18 | 19 | gulp.task("default", ["webpack", "jsdoc"]); -------------------------------------------------------------------------------- /library/ListView.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | 3 | const DEFAULT_ON_END_REACHED_THRESHOLD = 2000; 4 | 5 | /** Infinite List View */ 6 | class ListView extends Component { 7 | constructor(props) { 8 | super(props); 9 | 10 | this.state = { 11 | firstBatchIndex: 0, 12 | lastBatchIndex: 0, 13 | isLoading: true 14 | }; 15 | 16 | this._onEndReachedThreshold = props.onEndReachedThreshold || DEFAULT_ON_END_REACHED_THRESHOLD; 17 | this._childrenHeightCache = []; 18 | this._cachedScrollContainerRect = null; 19 | 20 | this._onScroll = this._onScroll.bind(this); 21 | } 22 | 23 | _setRenderableBatches() { 24 | var children = Array.from(this.batchedComponentsContainer.children); 25 | var first = null; 26 | var last = 0; 27 | 28 | this._cachedScrollContainerRect = this.scrollableContainer.getBoundingClientRect(); 29 | 30 | children.forEach((child, index) => { 31 | if (this._isElementInViewport(child, index)) { 32 | if (first == null) { 33 | first = index; 34 | } 35 | 36 | last = index; 37 | } else { 38 | child.style.height = this._childrenHeightCache[index] + "px"; 39 | } 40 | }); 41 | 42 | first = first == null ? 0 : first; 43 | 44 | this.setState(prevState => { 45 | if (prevState.firstBatchIndex !== first || prevState.lastBatchIndex !== last) { 46 | return { 47 | firstBatchIndex: first, 48 | lastBatchIndex: last 49 | }; 50 | } 51 | }); 52 | } 53 | 54 | _getRenderableBatches() { 55 | let { firstBatchIndex, lastBatchIndex } = this.state; 56 | let { dataSource, renderRow } = this.props; 57 | let numberOfBatches = dataSource.getBatchCount(); 58 | let batches = []; 59 | 60 | for (let i = 0; i < numberOfBatches; i++) { 61 | if (i >= firstBatchIndex && i <= lastBatchIndex) { 62 | let batchIndex = i; 63 | let batch = dataSource.getBatchData(batchIndex); 64 | let batchContainerElement = ( 65 |
(this["batchContainer" + batchIndex] = div)} key={batchIndex}> 66 | {batch.map((item, itemIndex) => { 67 | return renderRow(item, batchIndex + "_" + itemIndex); 68 | })} 69 |
70 | ); 71 | 72 | batches.push(batchContainerElement); 73 | } else { 74 | let emptyBatchContainer = this["batchContainer" + i] || null; 75 | 76 | if (emptyBatchContainer) { 77 | let emptyContainerHeight = this["batchContainer" + i].style.height; 78 | let emptyBatchContainerElement = ( 79 |
(this["batchContainer" + i] = div)} key={i} /> 80 | ); 81 | 82 | batches.push(emptyBatchContainerElement); 83 | } 84 | } 85 | } 86 | 87 | return batches; 88 | } 89 | 90 | _isElementInViewport(element, index) { 91 | var elementRect = element.getBoundingClientRect(); 92 | this._childrenHeightCache[index] = elementRect.height; 93 | 94 | var scrollContainerRect = this._cachedScrollContainerRect; 95 | 96 | var scrollTop = scrollContainerRect.top - this._onEndReachedThreshold; 97 | var scrollBottom = scrollContainerRect.bottom + this._onEndReachedThreshold; 98 | 99 | var top = Math.max(elementRect.top, scrollTop); 100 | var bottom = Math.min(elementRect.bottom, scrollBottom); 101 | 102 | return top < bottom; 103 | } 104 | 105 | _isWithinOnEndReachedThreshold() { 106 | var scrollContainerRect = this.scrollableContainer.getBoundingClientRect(); 107 | var bottom = scrollContainerRect.height + this.scrollableContainer.scrollTop; 108 | 109 | return this.scrollableContainer.scrollHeight - bottom <= this._onEndReachedThreshold; 110 | } 111 | 112 | _checkForDig() { 113 | if (this._isWithinOnEndReachedThreshold()) { 114 | let batchCount = this.props.dataSource.getBatchCount(); 115 | 116 | if (batchCount - 1 > this.state.lastBatchIndex) { 117 | this.setState((prevState, props) => { 118 | return { lastBatchIndex: prevState.lastBatchIndex + 1 }; 119 | }); 120 | } else { 121 | this.digBatches(); 122 | } 123 | } 124 | } 125 | _onScroll() { 126 | this.update(); 127 | } 128 | 129 | /** 130 | * Manually dig batches from the props.onEndReached function. 131 | */ 132 | digBatches() { 133 | if (this.props.onEndReached) { 134 | this.props.onEndReached(this.state.lastBatchIndex); 135 | 136 | let batchCount = this.props.dataSource.getBatchCount(); 137 | 138 | this.setState((prevState, props) => { 139 | if (batchCount !== 0) { 140 | return { 141 | lastBatchIndex: batchCount - 1, 142 | isLoading: true 143 | }; 144 | } 145 | }); 146 | } 147 | } 148 | 149 | /** 150 | * Checks if content inside of scrollbar is long enough to have an active scrollbar. 151 | */ 152 | isScrollbarActive() { 153 | return this.scrollableContainer.clientHeight === this.scrollableContainer.scrollHeight ? false : true; 154 | } 155 | 156 | /** 157 | * Changes the scrollTop to the topPosition provided. 158 | * @param {number} topPosition - The desired scroll top position. 159 | */ 160 | scrollTo(topPosition) { 161 | this.scrollableContainer.scrollTop = topPosition; 162 | } 163 | 164 | update() { 165 | this._setRenderableBatches(); 166 | this._checkForDig(); 167 | } 168 | 169 | componentDidMount() { 170 | this._setRenderableBatches(); 171 | } 172 | 173 | componentWillReceiveProps(nextProps) { 174 | if (this.props.dataSource.getBatchCount() !== nextProps.dataSource.getBatchCount()) { 175 | this.setState({ 176 | isLoading: false 177 | }); 178 | } 179 | } 180 | 181 | render() { 182 | let batchedComponents = this._getRenderableBatches(); 183 | let loadingComponent = this.state.isLoading && this.props.loadingComponent ? this.props.loadingComponent() : null; 184 | 185 | return ( 186 |
(this.scrollableContainer = this.props.scrollableContainer || div)} 189 | onScroll={this._onScroll}> 190 |
(this.batchedComponentsContainer = div)}>{batchedComponents}
191 | {loadingComponent} 192 |
193 | ); 194 | } 195 | } 196 | 197 | export default ListView; 198 | -------------------------------------------------------------------------------- /library/ListViewDataSource.js: -------------------------------------------------------------------------------- 1 | const DEFAULT_BATCH_SIZE = 20; 2 | 3 | class ListViewDataSource { 4 | constructor(batchSize, dataBlob) { 5 | this._dataBlob = dataBlob || []; 6 | this._batchedData = []; 7 | this._batchSize = batchSize || DEFAULT_BATCH_SIZE; 8 | this._createBatchedData(); 9 | } 10 | 11 | _createBatchedData() { 12 | this._batchedData = this._dataBlob.reduce((acc, currentItem, currentIndex) => { 13 | if (!(currentIndex % this._batchSize)) { 14 | acc.push(this._dataBlob.slice(currentIndex, currentIndex + this._batchSize)) 15 | } 16 | return acc; 17 | }, []); 18 | } 19 | 20 | appendRows(dataBlob) { 21 | return this.cloneWithRows(dataBlob); 22 | } 23 | 24 | prependRows(dataBlob) { 25 | this._dataBlob.unshift(dataBlob); 26 | 27 | let newDataSource = new ListViewDataSource(this._batchSize, this._dataBlob); 28 | return newDataSource; 29 | } 30 | 31 | cloneWithRows(dataBlob) { 32 | let newDataSource = new ListViewDataSource(this._batchSize, this._dataBlob.concat(dataBlob)); 33 | return newDataSource; 34 | } 35 | 36 | getBatchCount() { 37 | return this._batchedData.length; 38 | } 39 | 40 | getBatchData(batchIndex) { 41 | return this._batchedData[batchIndex]; 42 | } 43 | }; 44 | 45 | export default ListViewDataSource; -------------------------------------------------------------------------------- /library/main.js: -------------------------------------------------------------------------------- 1 | import ListView from "./ListView"; 2 | import ListViewDataSource from "./ListViewDataSource"; 3 | 4 | export { 5 | ListView, 6 | ListViewDataSource 7 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "clarity-react-infinite-list", 3 | "version": "1.0.7", 4 | "description": "A browser efficient infinite list for React apps that allows loading of items with differing heights and sizes.", 5 | "main": "dist/main.js", 6 | "license": "MIT", 7 | "keywords": [ 8 | "react", 9 | "reactjs", 10 | "react-component", 11 | "list", 12 | "scrolling", 13 | "infinite", 14 | "react-list", 15 | "scroll", 16 | "dynamic", 17 | "height", 18 | "lazy", 19 | "virtual", 20 | "vertical" 21 | ], 22 | "repository": { 23 | "type": "git", 24 | "url": "SourceDecoded/clarity-react-infinite-list" 25 | }, 26 | "private": false, 27 | "devDependencies": { 28 | "babel-core": "^6.22.1", 29 | "babel-loader": "^6.2.10", 30 | "babel-preset-es2015": "^6.22.0", 31 | "babel-preset-react": "^6.22.0", 32 | "gulp": "^3.9.1", 33 | "gulp-jsdoc3": "^1.0.1", 34 | "react-scripts": "0.8.5", 35 | "webpack": "^2.2.1" 36 | }, 37 | "dependencies": { 38 | "react": "^15.4.2", 39 | "react-dom": "^15.4.2" 40 | }, 41 | "scripts": { 42 | "start": "react-scripts start", 43 | "build": "react-scripts build", 44 | "test": "react-scripts test --env=jsdom", 45 | "eject": "react-scripts eject" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | 3 | var distribution = { 4 | entry: [ 5 | "./library/main.js" 6 | ], 7 | output: { 8 | filename: 'main.js', 9 | library: "clarity-react-infinite-list", 10 | libraryTarget: "umd", 11 | path: './dist' 12 | }, 13 | module: { 14 | loaders: [ 15 | { 16 | test: /.jsx?$/, 17 | loader: 'babel-loader', 18 | exclude: /node_modules/, 19 | query: { 20 | presets: ['es2015', 'react'] 21 | } 22 | } 23 | ] 24 | } 25 | }; 26 | 27 | module.exports = [ 28 | distribution 29 | ] --------------------------------------------------------------------------------