",
42 | "license": "ISC",
43 | "bugs": {
44 | "url": "https://github.com/linchpinstudios/yii2-filemanager/issues"
45 | },
46 | "homepage": "https://github.com/linchpinstudios/yii2-filemanager#readme"
47 | }
48 |
--------------------------------------------------------------------------------
/src/js/components/Button.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 |
3 | export default class Button extends Component {
4 | render() {
5 | return
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/js/components/Close.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 | import Thumbnail from '../components/Thumbnail'
3 | import Dragula from 'react-dragula'
4 |
5 | export default class Selected extends Component {
6 |
7 | constructor() {
8 | super()
9 | this.state.images = []
10 | this.state.clickHandler = () => {}
11 | }
12 |
13 | render(props = { images: [] }, state) {
14 | if (props.clickHandler) state.clickHandler = props.clickHandler
15 | return state.clickHandler(props.image)}>
16 | X
17 |
18 | }
19 | }
20 |
21 | const styles = {
22 | close: {
23 | position: 'absolute',
24 | top: '5px',
25 | right: '5px',
26 | color: '#ff0000',
27 | cursor: 'pointer',
28 | opacity: 0,
29 | 'font-weight': 'bold',
30 | 'text-decoration': 'none',
31 | transition: '500ms opacity'
32 | },
33 | hover: {
34 | opacity: 1
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/js/components/Pagination.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 |
3 | export default class Pagination extends Component {
4 |
5 | constructor() {
6 | super()
7 | this.clickHandler = e => false
8 | }
9 |
10 | getFirstButton(page = 1) {
11 | if (page <= 1) {
12 | return «
13 | }
14 | return this.clickHandler(page-1)}>«
15 | }
16 |
17 | getLastButton(count, page = 1) {
18 | if (page + 1 >= count) {
19 | return »
20 | }
21 | return this.clickHandler(page+1)}>»
22 | }
23 |
24 | getOffset(page, count, limit) {
25 | let offset = page - Math.floor((limit-1) / 2)
26 | return offset >= 1 ? offset : 1
27 | }
28 |
29 | getNumbers(count, page = 1, limit = 11) {
30 | let nums = []
31 | let offset = this.getOffset(page, count, limit)
32 | let top = (offset + limit) > count ? count : offset + limit
33 | for (let i = offset; i <= top; i++) {
34 | nums.push( this.clickHandler(i)}>{i})
35 | }
36 | return nums
37 | }
38 |
39 | render(props) {
40 | if (props.clickHandler) this.clickHandler = props.clickHandler
41 | return
42 |
47 |
48 | }
49 | }
50 |
51 | const styles = {
52 | button: {
53 | textAlign: 'center',
54 | minWidth: '40px',
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/js/components/Search.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 |
3 | export default class Search extends Component {
4 |
5 | constructor() {
6 | super()
7 | this.clickHandler = e => {
8 | return false
9 | }
10 | this.state.term = ''
11 | }
12 |
13 | handleChange(e) {
14 | this.state.term = e.target.value
15 | console.log('update state', this.state.term)
16 | }
17 |
18 | handleKeyInput(e) {
19 | if (e.charCode == 13 || e.keyCode == 13) {
20 | e.preventDefault();
21 | this.state.term = e.target.value
22 | this.state.clickHandler(this.state.term)
23 | return false
24 | }
25 | }
26 |
27 | render(props = {term:''}, state) {
28 | state.term = props.term
29 |
30 | if (props.clickHandler) state.clickHandler = props.clickHandler
31 |
32 | return
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/js/components/Selected.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 | import Thumbnail from '../components/Thumbnail'
3 | import Dragula from 'react-dragula'
4 |
5 | export default class Selected extends Component {
6 |
7 | constructor() {
8 | super()
9 | this.state.images = []
10 | this.state.clickHandler = false
11 | this.state.orderHandler = () => {}
12 | this.state.removeHandle = false
13 | this.dragulaDecorator = this.dragulaDecorator.bind(this);
14 | this.thumbnails = this.thumbnails.bind(this)
15 | }
16 |
17 | dragulaDecorator(componentBackingInstance) {
18 | if (componentBackingInstance) {
19 | let options = {
20 | drop: (el) => {
21 | console.log('dropped', el)
22 | }
23 | }
24 | let drake = Dragula([componentBackingInstance], options);
25 | drake.on('drop', (el, target, source, sibling) => {
26 | let order = []
27 |
28 | for (let i = 0; i < source.children.length; i++) {
29 | order.push(source.children[i].dataset.id)
30 | }
31 |
32 | this.state.orderHandler(order)
33 | })
34 | }
35 | }
36 |
37 | thumbnails(images) {
38 | let components = []
39 | images.forEach((image, key) => {
40 | components.push()
41 | })
42 | return components
43 | }
44 |
45 | render(props = { images: [] }, state) {
46 | if (props.clickHandler) state.clickHandler = props.clickHandler
47 | if (props.removeHandle) state.removeHandle = props.removeHandle
48 | if (props.orderHandler) state.orderHandler = props.orderHandler
49 | state.images = props.images
50 | return
51 | {this.thumbnails(state.images)}
52 |
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/js/components/Thumbnail.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 | import Close from '../components/Close'
3 |
4 | export default class Thumbnail extends Component {
5 | constructor() {
6 | super()
7 | this.state.clickHandler = () => {}
8 | this.state.removeHandle = false
9 | this.state.hover = false
10 | this.state.image
11 | }
12 |
13 | hoverOn() {
14 | this.setState({
15 | hover: true,
16 | })
17 | }
18 |
19 | hoverOff() {
20 | this.setState({
21 | hover: false,
22 | })
23 | }
24 |
25 | closeButton() {
26 | return this.state.removeHandle ? :
27 | }
28 |
29 | render(props, state) {
30 | if (props.clickHandler) state.clickHandler = props.clickHandler
31 | if (props.removeHandle) state.removeHandle = props.removeHandle
32 |
33 | state.image = props.image
34 |
35 | return
41 | }
42 | }
43 |
44 | const styles = {
45 | wrapper: {
46 | position: 'relative',
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/js/components/Uploader.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 | import Axios from 'axios';
3 |
4 | export default class Uploader extends Component {
5 | constructor() {
6 | super()
7 | this.state.uploadCallback = () => { }
8 | this.state.csrfToken = document.querySelector('[name="csrf-token"]').content
9 | this.refs = {}
10 | }
11 |
12 | handleFiles(e) {
13 | let files = e.target.files
14 | console.log(files)
15 | Array.from(files)
16 | .forEach(file => this.upload(file)
17 | .then(response => response.data)
18 | .then(data => {
19 | this.state.uploadCallback(data)
20 | this.refs.fileInput.value = null
21 | })
22 | .catch(error => console.log(error)))
23 | }
24 |
25 | upload(file) {
26 | let formData = new FormData;
27 | formData.append('Files[file_name]', file)
28 | return Axios.post('/filemanager/files/uploadpicker', formData, {
29 | headers: {
30 | 'Content-Type': 'multipart/form-data',
31 | 'X-CSRF-Token': this.state.csrfToken,
32 | Accept: 'application/json',
33 | }
34 | })
35 | }
36 |
37 | render(props, state) {
38 | if (props.uploadCallback) state.uploadCallback = props.uploadCallback
39 | return ()
43 | }
44 | }
45 |
46 |
47 | const styles = {
48 | input: {
49 | display: 'none'
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/js/index.js:
--------------------------------------------------------------------------------
1 | import { h, render } from 'preact'
2 | import FilePicker from './views/FilePicker'
3 | import { Store, Actions} from './store/FilePickerStore'
4 | import { Provider, connect } from 'unistore/preact'
5 | import 'react-dragula/dist/dragula.min.css';
6 |
7 | var elements = document.querySelectorAll('*[data-filemanager]')
8 |
9 | if (elements) {
10 | elements.forEach(function(element) {
11 | var view = element.getAttribute('data-filemanager')
12 | var target = element.getAttribute('data-target')
13 | var selected = element.getAttribute('data-selected')
14 | var limit = element.getAttribute('data-limit')
15 | switch (view) {
16 | case 'FilePicker':
17 | render(
18 |
19 | , element);
20 | break;
21 | }
22 | })
23 | }
24 |
--------------------------------------------------------------------------------
/src/js/store/FilePickerStore.js:
--------------------------------------------------------------------------------
1 | import createStore from 'unistore'
2 | import Axios from 'axios'
3 |
4 | export const Store = createStore({
5 | images: [],
6 | selected: [],
7 | selectedIds: [],
8 | page: 1,
9 | term: '',
10 | pageCount: 10,
11 | showSelector: false,
12 | })
13 |
14 | export const Actions = store => ({
15 |
16 | /**
17 | * @param {State} state
18 | * @param {Page} page
19 | */
20 | async getPage(state, page = 1) {
21 | let params = { page }
22 | if (state.term !== '') params["FilesSearch[title]"] = state.term
23 |
24 | let response = await Axios.get('/filemanager/files/index', {
25 | params,
26 | headers: {
27 | Accept: 'application/json'
28 | }
29 | })
30 | let data = await response.data
31 | return {
32 | images: state.images.push(data.images),
33 | page: page,
34 | pageCount: data.pageCount
35 | }
36 | }
37 |
38 |
39 | })
40 |
--------------------------------------------------------------------------------
/src/js/views/FilePicker.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 | import Search from '../components/Search'
3 | import Thumbnail from '../components/Thumbnail'
4 | import Pagination from '../components/Pagination';
5 | import Selected from '../components/Selected';
6 | import Axios from 'axios';
7 | import Uploader from '../components/Uploader';
8 |
9 | export default class FilePicker extends Component {
10 | constructor(props) {
11 | super(props);
12 | // set initial time:
13 | this.props = props
14 | this.state = this.setDefaultState(props)
15 |
16 | this.thumbnails = this.thumbnails.bind(this)
17 | this.addToSelected = this.addToSelected.bind(this)
18 | }
19 |
20 | setDefaultState(props) {
21 | return {
22 | images: [],
23 | selected: [],
24 | selectedIds: props.selected ? JSON.parse(props.selected) : [],
25 | limit: parseInt(props.limit),
26 | page: 1,
27 | term: '',
28 | pageCount: 10,
29 | showSelector: false,
30 | }
31 | }
32 |
33 | componentDidMount() {
34 | this.getSelected()
35 | this.getPage()
36 | }
37 |
38 | getSelected() {
39 | this.state.selectedIds.forEach(id => this.getById(id).then(image => this.state.selected.push(image)).then(() => {this.orderSelected(this.state.selectedIds)}).catch(error => console.log(error)))
40 | }
41 |
42 | orderSelected(order) {
43 | let selected = order.map((index) => {
44 | return this.state.selected.find(image => index == image.id)
45 | }).filter((item) => item)
46 | this.setState({
47 | selected: selected,
48 | selectedIds: order,
49 | })
50 | }
51 |
52 | getById(id) {
53 | return new Promise((resolve, reject) => {
54 | Axios.get('/filemanager/files/view', {
55 | params: { id: id },
56 | headers: {
57 | Accept: 'application/json'
58 | }
59 | }).then(response => response.data).then(data => {
60 | resolve(data)
61 | }).catch(error => console.log('getById', reject(error)))
62 | })
63 | }
64 |
65 | handleUploaded(image) {
66 | this.addToSelected(image)
67 | this.getPage()
68 | }
69 |
70 | addToSelected(image) {
71 | let match = this.state.selected.find(img => image === img)
72 | if (match) return
73 | if (this.state.limit > 0 && this.state.selected.length >= this.state.limit) {
74 | this.state.selected.pop()
75 | this.state.selectedIds.pop()
76 | }
77 | this.state.selected.push(image)
78 | this.state.selectedIds.push(image.id)
79 | this.setState({ selected: this.state.selected })
80 | }
81 |
82 | removeFromSelected(image) {
83 | let selected = this.state.selected.filter(img => image !== img)
84 | let selectedIds = this.state.selectedIds.filter(img => image.id !== img)
85 | this.setState({
86 | selected: selected,
87 | selectedIds: selectedIds,
88 | })
89 | }
90 |
91 | clickHandler(page) {
92 | this.getPage(page <= 0 ? 1 : page)
93 | return false
94 | }
95 |
96 | searchHandler(term = '') {
97 | this.setState({term: term})
98 | this.getPage()
99 | return false
100 | }
101 |
102 | getPage(page = 1) {
103 | let params = { page }
104 |
105 | if (this.state.term !== '') params["FilesSearch[title]"] = this.state.term
106 |
107 | this.clearThumbnails()
108 |
109 | Axios.get('/filemanager/files/index', {
110 | params,
111 | headers: {
112 | Accept: 'application/json'
113 | }
114 | }).then(response => response.data).then(data => {
115 | this.setState({
116 | page: page,
117 | images: data.images,
118 | pageCount: data.pageCount,
119 | })
120 | }).catch(error => console.log('getPage', error))
121 | }
122 |
123 | clearThumbnails () {
124 | this.setState({images: []})
125 | }
126 |
127 | thumbnails(images) {
128 | let components = []
129 | images.forEach((image) => {
130 | components.push()
131 | })
132 | return components
133 | }
134 |
135 | toggleSelector() {
136 | let show = !this.state.showSelector
137 | this.setState({showSelector: show})
138 | }
139 |
140 | selector() {
141 | if (!this.state.showSelector) {
142 | return ''
143 | }
144 | return (
145 |
146 |
147 |
148 |
149 |
150 |
151 | this.handleUploaded(image)}>
152 |
153 |
154 |
155 |
156 |
157 | { this.thumbnails(this.state.images) }
158 |
159 |
160 |
163 |
)
164 | }
165 |
166 | inputs() {
167 | let inputs = []
168 | if (this.state.limit == 1) {
169 | this.state.selectedIds.forEach((id, key) => inputs.push())
170 | } else {
171 | this.state.selectedIds.forEach((id, key) => inputs.push())
172 | }
173 | return inputs
174 | }
175 |
176 | render(props, state) {
177 | return (
178 | {this.inputs()}
179 |
180 |
181 |
182 |
183 |
184 |
189 |
190 |
191 | { this.selector() }
192 |
)
193 | }
194 | }
195 |
196 | const styles = {
197 | selected: {
198 | backgroundColor: '#eeeff2',
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/tests/functional/TestCase.php:
--------------------------------------------------------------------------------
1 | mockWebApplication(
18 | [
19 | 'components' => [
20 | 'request' => [
21 | 'class' => 'yii\web\Request',
22 | 'url' => '/test',
23 | 'enableCsrfValidation' => false,
24 | ],
25 | 'response' => [
26 | 'class' => 'yii\web\Response',
27 | ],
28 | ],
29 | ]
30 | );
31 | }
32 | /**
33 | * Clean up after test.
34 | * By default the application created with [[mockApplication]] will be destroyed.
35 | */
36 | protected function tearDown()
37 | {
38 | parent::tearDown();
39 | $this->destroyApplication();
40 | }
41 | protected function mockApplication($config = [], $appClass = '\yii\console\Application')
42 | {
43 | new $appClass(
44 | ArrayHelper::merge(
45 | [
46 | 'id' => 'testapp',
47 | 'basePath' => __DIR__,
48 | 'vendorPath' => $this->getVendorPath(),
49 | ],
50 | $config
51 | )
52 | );
53 | }
54 | protected function mockWebApplication($config = [], $appClass = '\yii\web\Application')
55 | {
56 | new $appClass(
57 | ArrayHelper::merge(
58 | [
59 | 'id' => 'testapp',
60 | 'basePath' => __DIR__,
61 | 'vendorPath' => $this->getVendorPath(),
62 | 'components' => [
63 | 'request' => [
64 | 'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq',
65 | 'scriptFile' => __DIR__ . '/index.php',
66 | 'scriptUrl' => '/index.php',
67 | ],
68 | 'assetManager' => [
69 | 'basePath' => '@tests/data/assets',
70 | 'baseUrl' => '/',
71 | ]
72 | ]
73 | ],
74 | $config
75 | )
76 | );
77 | }
78 | protected function getVendorPath()
79 | {
80 | return dirname(dirname(__DIR__)) . '/vendor';
81 | }
82 | /**
83 | * Destroys application in Yii::$app by setting it to null.
84 | */
85 | protected function destroyApplication()
86 | {
87 | \Yii::$app = null;
88 | }
89 | /**
90 | * Creates a view for testing purposes
91 | *
92 | * @return View
93 | */
94 | protected function getView()
95 | {
96 | $view = new View();
97 | $view->setAssetManager(
98 | new AssetManager(
99 | [
100 | 'basePath' => '@tests/data/assets',
101 | 'baseUrl' => '/',
102 | ]
103 | )
104 | );
105 | return $view;
106 | }
107 | /**
108 | * Asserting two strings equality ignoring line endings
109 | *
110 | * @param string $expected
111 | * @param string $actual
112 | */
113 | public function assertEqualsWithoutLE($expected, $actual)
114 | {
115 | $expected = str_replace("\r\n", "\n", $expected);
116 | $actual = str_replace("\r\n", "\n", $actual);
117 | $this->assertEquals($expected, $actual);
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/tests/functional/bootstrap.php:
--------------------------------------------------------------------------------
1 |
7 | * @link http://linchpinstudios.com/
8 | */
9 | error_reporting(-1);
10 | define('YII_ENABLE_ERROR_HANDLER', false);
11 | define('YII_DEBUG', true);
12 | $_SERVER['SCRIPT_NAME'] = '/' . __DIR__;
13 | $_SERVER['SCRIPT_FILENAME'] = __FILE__;
14 | require_once(__DIR__ . '/../../vendor/autoload.php');
15 | require_once(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');
16 | Yii::setAlias('@tests', __DIR__);
17 | require_once(__DIR__ . '/TestCase.php');
18 |
--------------------------------------------------------------------------------
/views/default/index.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | = Html::a(Html::tag('i','',['class' => 'glyphicon glyphicon-cloud-upload']),['filemanager/files/filemodal'],['class' => 'btn btn-default navbar-btn', 'data-toggle' => 'modal', 'data-target' => '#filemanagerUpload']); ?>
12 |
13 |
19 |
20 |
21 |
22 |
23 |
28 |
33 |
38 |
43 |
48 |
53 |
58 |
63 |
68 |
73 |
78 |
83 |
84 |
85 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
107 |
108 |
109 |
110 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/views/file-tag/_form.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
26 |
--------------------------------------------------------------------------------
/views/file-tag/_search.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 | ['index'],
15 | 'method' => 'get',
16 | ]); ?>
17 |
18 | = $form->field($model, 'id') ?>
19 |
20 | = $form->field($model, 'name') ?>
21 |
22 | = $form->field($model, 'slug') ?>
23 |
24 |
25 | = Html::submitButton(Yii::t('app', 'Search'), ['class' => 'btn btn-primary']) ?>
26 | = Html::resetButton(Yii::t('app', 'Reset'), ['class' => 'btn btn-default']) ?>
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/views/file-tag/create.php:
--------------------------------------------------------------------------------
1 | title = Yii::t('app', 'Create File Tag');
10 | $this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'File Tags'), 'url' => ['index']];
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 |
17 | = $this->render('_form', [
18 | 'model' => $model,
19 | ]) ?>
20 |
21 |
22 |
--------------------------------------------------------------------------------
/views/file-tag/index.php:
--------------------------------------------------------------------------------
1 | title = Yii::t('app', 'File Tags');
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 | render('_search', ['model' => $searchModel]); ?>
17 |
18 |
19 | = Html::a(Yii::t('app', 'Create File Tag'), ['create'], ['class' => 'btn btn-success']) ?>
20 |
21 |
22 | = GridView::widget([
23 | 'dataProvider' => $dataProvider,
24 | 'filterModel' => $searchModel,
25 | 'columns' => [
26 | ['class' => 'yii\grid\SerialColumn'],
27 |
28 | 'id',
29 | 'name',
30 | 'slug',
31 |
32 | ['class' => 'yii\grid\ActionColumn'],
33 | ],
34 | ]); ?>
35 |
36 |
37 |
--------------------------------------------------------------------------------
/views/file-tag/update.php:
--------------------------------------------------------------------------------
1 | title = Yii::t('app', 'Update {modelClass}: ', [
9 | 'modelClass' => 'File Tag',
10 | ]) . ' ' . $model->name;
11 | $this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'File Tags'), 'url' => ['index']];
12 | $this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]];
13 | $this->params['breadcrumbs'][] = Yii::t('app', 'Update');
14 | ?>
15 |
16 |
17 |
= Html::encode($this->title) ?>
18 |
19 | = $this->render('_form', [
20 | 'model' => $model,
21 | ]) ?>
22 |
23 |
24 |
--------------------------------------------------------------------------------
/views/file-tag/view.php:
--------------------------------------------------------------------------------
1 | title = $model->name;
10 | $this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'File Tags'), 'url' => ['index']];
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 |
17 |
18 | = Html::a(Yii::t('app', 'Update'), ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>
19 | = Html::a(Yii::t('app', 'Delete'), ['delete', 'id' => $model->id], [
20 | 'class' => 'btn btn-danger',
21 | 'data' => [
22 | 'confirm' => Yii::t('app', 'Are you sure you want to delete this item?'),
23 | 'method' => 'post',
24 | ],
25 | ]) ?>
26 |
27 |
28 | = DetailView::widget([
29 | 'model' => $model,
30 | 'attributes' => [
31 | 'id',
32 | 'name',
33 | 'slug',
34 | ],
35 | ]) ?>
36 |
37 |
38 |
--------------------------------------------------------------------------------
/views/files/_form.php:
--------------------------------------------------------------------------------
1 |
11 |
12 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
123 | ['//filemanager/file-tag/createtag'],
126 | 'enableAjaxValidation' => false,
127 | 'enableClientValidation' => true,
128 | 'id' => 'create_tag',
129 | ]);
130 | ?>
131 |
132 | = $formTag->field($newTag, 'name')->textInput(['maxlength' => 255]) ?>
133 |
134 |
138 |
139 |
140 |
141 |
142 |
--------------------------------------------------------------------------------
/views/files/_properties.php:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/views/files/_search.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 | ['index'],
15 | 'method' => 'get',
16 | ]); ?>
17 |
18 | = $form->field($model, 'id') ?>
19 |
20 | = $form->field($model, 'user_id') ?>
21 |
22 | = $form->field($model, 'url') ?>
23 |
24 | = $form->field($model, 'thumbnail_url') ?>
25 |
26 | = $form->field($model, 'file_name') ?>
27 |
28 | field($model, 'type') ?>
29 |
30 | field($model, 'title') ?>
31 |
32 | field($model, 'size') ?>
33 |
34 | field($model, 'width') ?>
35 |
36 | field($model, 'height') ?>
37 |
38 | field($model, 'date') ?>
39 |
40 | field($model, 'date_gmt') ?>
41 |
42 | field($model, 'update') ?>
43 |
44 | field($model, 'update_gmt') ?>
45 |
46 |
47 | = Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
48 | = Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/views/files/create.php:
--------------------------------------------------------------------------------
1 | title = 'Create Files';
10 | $this->params['breadcrumbs'][] = ['label' => 'Files', 'url' => ['index']];
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 |
17 | = $this->render('_form', [
18 | 'model' => $model,
19 | 'tags' => $tags,
20 | 'newTag' => $newTag,
21 | ]) ?>
22 |
23 |
24 |
--------------------------------------------------------------------------------
/views/files/fileModal.php:
--------------------------------------------------------------------------------
1 | title = 'File Upload';
7 | ?>
8 |
9 |
10 | = FileUploadUI::widget([
11 | 'model' => $model,
12 | 'attribute' => 'file_name',
13 | 'url' => ['files/upload'], // your url, this is just for demo purposes,
14 | 'options' => ['accept' => 'image/*'],
15 | 'clientOptions' => [
16 | 'maxFileSize' => 2000000
17 | ]
18 | ]);?>
19 |
--------------------------------------------------------------------------------
/views/files/index.php:
--------------------------------------------------------------------------------
1 | title = 'Files';
16 | $this->params['breadcrumbs'][] = $this->title;
17 |
18 | $awsConfig = $this->context->module->aws;
19 |
20 | if($awsConfig['enable']){
21 | $path = $this->context->module->url;
22 | }else{
23 | $path = '/';
24 | }
25 |
26 | ?>
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | = Html::a(Html::tag('i','',['class' => 'glyphicon glyphicon-th-large']), '#', ['class' => 'btn btn-primary navbar-btn disabled', 'id' => 'fileGridBtn']); ?>
37 | = Html::a(Html::tag('i','',['class' => 'glyphicon glyphicon-cloud-upload']), '#', ['class' => 'btn btn-success navbar-btn', 'id' => 'fileUploadBtn']); ?>
38 |
39 |
40 | 'file-search-form',
43 | 'method' => 'get',
44 | 'options' => ['class' => 'navbar-form navbar-right'],
45 | ]);
46 |
47 | echo Html::beginTag('div',['class' => 'form-group']);
48 | echo $form->field($searchModel, 'title')->textInput(['class' => 'form-control', 'placeholder' => 'Search']);
49 | echo Html::endTag('div');
50 | echo Html::submitButton('
', ['class' => 'btn btn-primary']);
51 | ActiveForm::end();
52 | ?>
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | getModels();
63 |
64 | foreach($models as $m){
65 |
66 | echo '
';
67 | echo Html::a( '

', ['view', 'id' => $m->id],['class'=>'thumbnail', 'data-id' => $m->id]);
68 | echo '
';
69 |
70 | }
71 | ?>
72 |
73 |
74 |
75 | = FileUploadUI::widget([
76 | 'model' => $model,
77 | 'attribute' => 'file_name',
78 | 'url' => ['files/upload'], // your url, this is just for demo purposes,
79 | 'options' => [
80 | 'accept' => 'image/*',
81 | 'done' => 'filemanager',
82 | ],
83 | 'clientOptions' => [
84 | 'maxFileSize' => 2000000,
85 | 'debug' => true,
86 | ],
87 | 'clientEvents' => [
88 | 'fileuploaddone' => 'function(e, data) {
89 | console.log(data);
90 | $.each(data.result.files, function( index, value ){
91 | console.log(value);
92 | $("#fileGridManager .row").prepend(\'
\');
93 | $(\'#filemanagerUpload\').hide();
94 | $(\'#fileGridManager,#fileGridFooter\').show();
95 | });
96 | }',
97 | 'fileuploadfail' => 'function(e, data) {
98 | console.log(e);
99 | console.log(data);
100 | }',
101 | ],
102 | ]);?>
103 |
104 |
105 |
106 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/views/files/update.php:
--------------------------------------------------------------------------------
1 | title = 'Update Files: ' . ' ' . $model->title;
9 | $this->params['breadcrumbs'][] = ['label' => 'Files', 'url' => ['index']];
10 | $this->params['breadcrumbs'][] = ['label' => $model->title, 'url' => ['view', 'id' => $model->id]];
11 | $this->params['breadcrumbs'][] = 'Update';
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 |
17 | = $this->render('_form', [
18 | 'model' => $model,
19 | 'tags' => $tags,
20 | 'newTag' => $newTag,
21 | ]) ?>
22 |
23 |
24 |
--------------------------------------------------------------------------------
/views/files/view.php:
--------------------------------------------------------------------------------
1 | title = $model->title;
10 | $this->params['breadcrumbs'][] = ['label' => 'Files', 'url' => ['index']];
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
14 |
15 |
= Html::encode($this->title) ?>
16 |
17 |
18 | = Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>
19 | = Html::a('Delete', ['delete', 'id' => $model->id], [
20 | 'class' => 'btn btn-danger',
21 | 'data' => [
22 | 'confirm' => 'Are you sure you want to delete this item?',
23 | 'method' => 'post',
24 | ],
25 | ]) ?>
26 |
27 |
28 | = DetailView::widget([
29 | 'model' => $model,
30 | 'attributes' => [
31 | 'id',
32 | 'user_id',
33 | 'url:url',
34 | 'thumbnail_url:url',
35 | 'file_name',
36 | 'type',
37 | 'title',
38 | 'size',
39 | 'width',
40 | 'height',
41 | 'date',
42 | 'date_gmt',
43 | 'update',
44 | 'update_gmt',
45 | ],
46 | ]) ?>
47 |
48 |
49 |
--------------------------------------------------------------------------------
/views/layouts/modal.php:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | = $content ?>
7 |
8 |
--------------------------------------------------------------------------------
/views/layouts/tinymce.php:
--------------------------------------------------------------------------------
1 |
14 | beginPage() ?>
15 |
16 |
17 |
18 |
19 |
20 | = Html::encode($this->title) ?>
21 | head() ?>
22 | = Html::csrfMetaTags() ?>
23 |
24 |
25 | beginBody() ?>
26 | = $content ?>
27 | endBody() ?>
28 |
29 |
30 | endPage() ?>
31 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | mode: 'development',
5 | entry: ['./src/js/index.js'],
6 | output: {
7 | path: path.resolve(__dirname, 'js'),
8 | filename: 'bundle.js'
9 | },
10 | module: {
11 | rules: [{
12 | test: /\.js$/,
13 | exclude: /node_modules/,
14 | use: {
15 | loader: "babel-loader"
16 | }
17 | },
18 | {
19 | test: /\.css$/,
20 | use: ['style-loader', 'css-loader'],
21 | }]
22 | },
23 | resolve: {
24 | alias: {
25 | react: "preact-compat",
26 | "react-dom": "preact-compat"
27 | }
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/widgets/FilePicker.php:
--------------------------------------------------------------------------------
1 |
20 | * @since 0.1
21 | */
22 |
23 | class FilePicker extends InputWidget
24 | {
25 | /**
26 | * @var array the options for the DateTime JS plugin.
27 | * Please refer to the DateTime JS plugin Web page for possible options.
28 | * @see http://xdsoft.net/jqplugins/datetimepicker/
29 | */
30 | public $clientOptions = [
31 | 'limit'
32 | ];
33 |
34 |
35 | /**
36 | * run function.
37 | *
38 | * @access public
39 | * @return void
40 | */
41 | public function run()
42 | {
43 | \Yii::$app->assetManager->forceCopy = true;
44 | $view = $this->getView();
45 | FilemanagerPreactAssets::register( $view );
46 |
47 | if ( isset($this->clientOptions['fileTypes']) && !in_array('*', $this->clientOptions['fileTypes']) ) {
48 | $where = ['type'=>$this->clientOptions['fileTypes']];
49 | } else {
50 | $where = [];
51 | }
52 |
53 | if ($this->hasModel()) {
54 | $selected = [];
55 | if (is_array($this->model[$this->attribute])) {
56 | foreach ($this->model[$this->attribute] as $file) {
57 | $selected[] = $file->id;
58 | }
59 | } else if (!empty($this->model[$this->attribute])) {
60 | $selected[] = $this->model[$this->attribute];
61 | }
62 | } else {
63 | $selected = $this->value;
64 | }
65 |
66 | if ($this->model) {
67 | $this->name = $this->model->formName() . '[' . $this->attribute .']';
68 | }
69 |
70 | echo Html::beginTag('div', [
71 | 'data-filemanager' => 'FilePicker',
72 | 'data-target' => $this->name,
73 | 'data-selected' => $selected,
74 | 'data-limit' => isset($this->options['limit']) ? $this->options['limit'] : 0,
75 | ]);
76 | echo Html::endTag('div');
77 |
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/widgets/FileSelect.php:
--------------------------------------------------------------------------------
1 |
19 | * @since 0.1
20 | */
21 |
22 | class FileSelect extends InputWidget
23 | {
24 | /**
25 | * @var array the options for the DateTime JS plugin.
26 | * Please refer to the DateTime JS plugin Web page for possible options.
27 | * @see http://xdsoft.net/jqplugins/datetimepicker/
28 | */
29 | public $clientOptions = [];
30 |
31 |
32 |
33 |
34 | /**
35 | * run function.
36 | *
37 | * @access public
38 | * @return void
39 | */
40 | public function run()
41 | {
42 |
43 | $randomId = uniqid();
44 |
45 | if ( isset($this->clientOptions['fileTypes']) && !in_array('*', $this->clientOptions['fileTypes']) ) {
46 | $where = ['type'=>$this->clientOptions['fileTypes']];
47 | } else {
48 | $where = [];
49 | }
50 |
51 | $imageArray = ArrayHelper::map(Files::find()->select(['id', 'title'])->where( $where )->orderBy('title')->all(), 'id', 'title');
52 |
53 | $selectOptions = ArrayHelper::merge(['' => 'Select a Thumbnail'], $imageArray);
54 |
55 | if ($this->hasModel()) {
56 | echo Html::activeDropDownList($this->model, $this->attribute, $selectOptions, $this->options);
57 | } else {
58 | echo Html::dropDownList($this->name, $this->value, $selectOptions, $this->options);
59 | }
60 |
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/widgets/FileTagSelect.php:
--------------------------------------------------------------------------------
1 |
21 | * @since 0.1
22 | */
23 |
24 | class FileTagSelect extends InputWidget
25 | {
26 | /**
27 | * @var array the options for the DateTime JS plugin.
28 | * Please refer to the DateTime JS plugin Web page for possible options.
29 | * @see http://xdsoft.net/jqplugins/datetimepicker/
30 | */
31 | public $clientOptions = [];
32 |
33 |
34 |
35 |
36 | /**
37 | * run function.
38 | *
39 | * @access public
40 | * @return void
41 | */
42 | public function run()
43 | {
44 |
45 | $randomId = uniqid();
46 |
47 | $tagsArray = ArrayHelper::map( FileTag::find()->select(['id', 'name'])->orderBy('name')->all(), 'id', 'name' );
48 |
49 | $selectOptions = ArrayHelper::merge(['' => 'Select a File Tag'], $tagsArray);
50 |
51 | if ($this->hasModel()) {
52 | echo Html::activeDropDownList($this->model, $this->attribute, $selectOptions, $this->options);
53 | } else {
54 | echo Html::dropDownList($this->name, $this->value, $selectOptions, $this->options);
55 | }
56 |
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/widgets/Fileupload.php:
--------------------------------------------------------------------------------
1 | field($model, 'body')->widget(DateTime::className(), [
24 | * 'options' => ['rows' => 10],
25 | * 'clientOptions' => [
26 | * 'datepicker' => false,
27 | * 'format' => 'H:i',
28 | * ]
29 | * ]);
30 | * ```
31 | * @see http://xdsoft.net/jqplugins/datetimepicker/
32 | * @author Josh Hagel
33 | * @since 0.1
34 | */
35 |
36 | class Fileupload extends InputWidget
37 | {
38 | /**
39 | * @var array the options for the DateTime JS plugin.
40 | * Please refer to the DateTime JS plugin Web page for possible options.
41 | * @see http://xdsoft.net/jqplugins/datetimepicker/
42 | */
43 | public $clientOptions = [];
44 |
45 |
46 |
47 |
48 | /**
49 | * run function.
50 | *
51 | * @access public
52 | * @return void
53 | */
54 | public function run()
55 | {
56 |
57 | $randomId = uniqid();
58 |
59 | if ($this->hasModel()) {
60 | echo Html::activeHiddenInput($this->model, $this->attribute, $this->options);
61 | } else {
62 | echo Html::hiddenInput($this->name, $this->value, $this->options);
63 | }
64 | echo Html::tag('div', Html::a('Select Image',['/filemanager/files/filemodal'],['class' => 'btn btn-success','data-toggle' => 'modal','data-target' => '#filePickModal_'.$randomId]));
65 |
66 | echo $this->generateModal($randomId);
67 |
68 | $this->registerClientScript();
69 | }
70 |
71 |
72 | /**
73 | * Registers CSS and Scripts
74 | */
75 | protected function registerClientScript()
76 | {
77 |
78 | $view = $this->getView();
79 |
80 | FileUploadAssets::register( $view );
81 |
82 | /*$view = $this->getView();
83 |
84 | DateTimePickerAssets::register($view);
85 |
86 | $id = $this->options['id'];
87 |
88 | $options = Json::encode($this->clientOptions);
89 |
90 | $view->registerJs("jQuery('#$id').datetimepicker($options);");*/
91 | }
92 |
93 |
94 |
95 | /**
96 | * [generateModal description]
97 | * @param [type] $id [description]
98 | */
99 | protected function generateModal($id)
100 | {
101 | $html = '';
108 |
109 | return $html;
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------