}} to get pure name
109 | $paramName = str_replace(array('{', '}', ' ', ':'), '', $properties['yearParam']);
110 | $url = CmsPage::url($page->getBaseFileName(), [$paramName => $year]);
111 |
112 | return $url;
113 | }
114 |
115 |
116 | /**
117 | *
118 | * Returns menu type info for all-photo-albums menu item
119 | *
120 | * @return array
121 | */
122 | protected static function getAllAlbumsInfo() {
123 | $result = ['dynamicItems' => TRUE,];
124 | $result['cmsPages'] = self::getCmsPages('photoAlbum');
125 | return $result;
126 | }
127 |
128 |
129 | /**
130 | *
131 | * Returns menu type info for all-photo-albums menu item
132 | *
133 | * @return array
134 | */
135 | protected static function getSingleAlbumInfo() {
136 | $result = [
137 | 'dynamicItems' => FALSE,
138 | 'nesting' => FALSE,
139 | ];
140 | $result['cmsPages'] = self::getCmsPages('photoAlbum');
141 |
142 | $references = [];
143 | $albums = Album::all();
144 | foreach ($albums as $album) {
145 | $references[$album->id] = $album->title;
146 | }
147 | $result['references'] = $references;
148 |
149 | return $result;
150 | }
151 |
152 |
153 | /**
154 | *
155 | * Returns menu type info for all-photos menu item
156 | *
157 | * @return array
158 | */
159 | protected static function getAllPhotosInfo() {
160 | $result = ['dynamicItems' => true,];
161 | $result['cmsPages'] = self::getCmsPages('singlePhoto');
162 | return $result;
163 | }
164 |
165 |
166 | /**
167 | *
168 | * Return array of Cms pages having $component attached
169 | *
170 | * @param string $component
171 | * @return array
172 | */
173 | protected static function getCmsPages($component) {
174 | $theme = Theme::getActiveTheme();
175 |
176 | $pages = CmsPage::listInTheme($theme, true);
177 | $cmsPages = [];
178 |
179 | foreach ($pages as $page) {
180 | if (!$page->hasComponent($component)) {
181 | continue;
182 | }
183 |
184 | $cmsPages[] = $page;
185 | }
186 |
187 | return $cmsPages;
188 | }
189 |
190 |
191 | /**
192 | *
193 | * Resolves All Albums menu item
194 | *
195 | * @param MenuItem $item
196 | * @param string $url
197 | * @param Theme $theme
198 | * @return array
199 | */
200 | protected static function resolveAllAlbumsItem($item, $url, $theme) {
201 | $result = [
202 | 'items' => [],
203 | ];
204 |
205 | $albums = Album::all();
206 | foreach ($albums as $album) {
207 | $albumItem = [
208 | 'title' => $album->title,
209 | 'url' => self::getAlbumUrl($album, $item->cmsPage, $theme),
210 | 'mtime' => $album->updated_at,
211 | ];
212 | $albumItem['isActive'] = ($albumItem['url'] == $url);
213 | $result['items'][] = $albumItem;
214 | }
215 |
216 | return $result;
217 | }
218 |
219 |
220 | /**
221 | *
222 | * Resolves single Album menu item
223 | *
224 | * @param MenuItem $item
225 | * @param string $url
226 | * @param Theme $theme
227 | * @return array
228 | */
229 | protected static function resolveSingleAlbumItem($item, $url, $theme) {
230 | $result = [];
231 |
232 | if (!$item->reference || !$item->cmsPage) {
233 | return [];
234 | }
235 |
236 | $album = Album::find($item->reference);
237 | if (!$album) {
238 | return [];
239 | }
240 |
241 | $pageUrl = self::getAlbumUrl($album, $item->cmsPage, $theme);
242 | if (!$pageUrl) {
243 | return [];
244 | }
245 | $pageUrl = Url::to($pageUrl);
246 |
247 | $result['url'] = $pageUrl;
248 | $result['isActive'] = ($pageUrl == $url);
249 | $result['mtime'] = $album->updated_at;
250 |
251 | return $result;
252 | }
253 |
254 |
255 | /**
256 | *
257 | * Resolves All Photos menu item
258 | *
259 | * @param MenuItem $item
260 | * @param string $url
261 | * @param Theme $theme
262 | * @return array
263 | */
264 | protected static function resolveAllPhotosItem($item, $url, $theme) {
265 | $result = [
266 | 'items' => [],
267 | ];
268 |
269 | $photos = Photo::all();
270 | foreach ($photos as $photo) {
271 | $photoItem = [
272 | 'title' => $photo->title,
273 | 'url' => self::getPhotoUrl($photo, $item->cmsPage, $theme),
274 | 'mtime' => $photo->updated_at,
275 | ];
276 | $photoItem['isActive'] = ($photoItem['url'] == $url);
277 | $result['items'][] = $photoItem;
278 | }
279 |
280 | return $result;
281 | }
282 |
283 |
284 | /**
285 | *
286 | * Generates url for album
287 | *
288 | * @param Album $album
289 | * @param string $pageCode
290 | * @param Theme $theme
291 | * @return string
292 | */
293 | protected static function getAlbumUrl($album, $pageCode, $theme) {
294 | $page = CmsPage::loadCached($theme, $pageCode);
295 | if (!$page) return '';
296 |
297 | $properties = $page->getComponentProperties('photoAlbum');
298 | if (!isset($properties['slug'])) {
299 | return '';
300 | }
301 |
302 | if (!preg_match('/^\{\{([^\}]+)\}\}$/', $properties['slug'], $matches)) {
303 | return '';
304 | }
305 |
306 | $paramName = substr(trim($matches[1]), 1);
307 | $params = [
308 | $paramName => $album->slug,
309 | 'id' => $album->id,
310 | ];
311 | $url = CmsPage::url($page->getBaseFileName(), $params);
312 |
313 | return $url;
314 | }
315 |
316 |
317 | /**
318 | *
319 | * Generates url for photo
320 | *
321 | * @param Photo $photo
322 | * @param string $pageCode
323 | * @param Theme $theme
324 | * @return string
325 | */
326 | protected static function getPhotoUrl($photo, $pageCode, $theme) {
327 | $page = CmsPage::loadCached($theme, $pageCode);
328 | if (!$page) return '';
329 |
330 | $properties = $page->getComponentProperties('singlePhoto');
331 | if (!isset($properties['id'])) {
332 | return '';
333 | }
334 |
335 | if (!preg_match('/^\{\{([^\}]+)\}\}$/', $properties['id'], $matches)) {
336 | return '';
337 | }
338 |
339 | $paramName = substr(trim($matches[1]), 1);
340 | $params = [
341 | $paramName => $photo->id,
342 | 'album_slug' => $photo->album->slug,
343 | ];
344 | $url = CmsPage::url($page->getBaseFileName(), $params);
345 |
346 | return $url;
347 | }
348 |
349 | }
350 |
--------------------------------------------------------------------------------
/components/Album.php:
--------------------------------------------------------------------------------
1 | 'graker.photoalbums::lang.plugin.album',
33 | 'description' => 'graker.photoalbums::lang.components.album_description'
34 | ];
35 | }
36 |
37 | /**
38 | * @return array of component properties
39 | */
40 | public function defineProperties()
41 | {
42 | return [
43 | 'slug' => [
44 | 'title' => 'graker.photoalbums::lang.plugin.slug_label',
45 | 'description' => 'graker.photoalbums::lang.plugin.slug_description',
46 | 'default' => '{{ :slug }}',
47 | 'type' => 'string'
48 | ],
49 | 'photoPage' => [
50 | 'title' => 'graker.photoalbums::lang.components.photo_page_label',
51 | 'description' => 'graker.photoalbums::lang.components.photo_page_description',
52 | 'type' => 'dropdown',
53 | 'default' => 'photoalbums/album/photo',
54 | ],
55 | 'thumbMode' => [
56 | 'title' => 'graker.photoalbums::lang.components.thumb_mode_label',
57 | 'description' => 'graker.photoalbums::lang.components.thumb_mode_description',
58 | 'type' => 'dropdown',
59 | 'default' => 'auto',
60 | ],
61 | 'thumbWidth' => [
62 | 'title' => 'graker.photoalbums::lang.components.thumb_width_label',
63 | 'description' => 'graker.photoalbums::lang.components.thumb_width_description',
64 | 'default' => 640,
65 | 'type' => 'string',
66 | 'validationMessage' => 'graker.photoalbums::lang.errors.thumb_width_error',
67 | 'validationPattern' => '^[0-9]+$',
68 | 'required' => FALSE,
69 | ],
70 | 'thumbHeight' => [
71 | 'title' => 'graker.photoalbums::lang.components.thumb_height_label',
72 | 'description' => 'graker.photoalbums::lang.components.thumb_height_description',
73 | 'default' => 480,
74 | 'type' => 'string',
75 | 'validationMessage' => 'graker.photoalbums::lang.errors.thumbs_height_error',
76 | 'validationPattern' => '^[0-9]+$',
77 | 'required' => FALSE,
78 | ],
79 | 'photosOnPage' => [
80 | 'title' => 'graker.photoalbums::lang.components.photos_on_page_label',
81 | 'description' => 'graker.photoalbums::lang.components.photos_on_page_description',
82 | 'default' => 12,
83 | 'type' => 'string',
84 | 'validationMessage' => 'graker.photoalbums::lang.errors.photos_on_page_error',
85 | 'validationPattern' => '^[0-9]+$',
86 | 'required' => FALSE,
87 | ],
88 | ];
89 | }
90 |
91 | /**
92 | *
93 | * Returns pages list for album page select box setting
94 | *
95 | * @return mixed
96 | */
97 | public function getPhotoPageOptions() {
98 | return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
99 | }
100 |
101 |
102 | /**
103 | *
104 | * Returns thumb resize mode options for thumb mode select box setting
105 | *
106 | * @return array
107 | */
108 | public function getThumbModeOptions() {
109 | return [
110 | 'auto' => 'Auto',
111 | 'exact' => 'Exact',
112 | 'portrait' => 'Portrait',
113 | 'landscape' => 'Landscape',
114 | 'crop' => 'Crop',
115 | ];
116 | }
117 |
118 |
119 | /**
120 | * Get photo page number from query
121 | */
122 | protected function setCurrentPage() {
123 | if (isset($_GET['page'])) {
124 | if (ctype_digit($_GET['page']) && ($_GET['page'] > 0)) {
125 | $this->currentPage = $_GET['page'];
126 | } else {
127 | return FALSE;
128 | }
129 | } else {
130 | $this->currentPage = 1;
131 | }
132 | return TRUE;
133 | }
134 |
135 |
136 | /**
137 | * Loads album on onRun event
138 | */
139 | public function onRun() {
140 | if (!$this->setCurrentPage()) {
141 | // if page parameter is invalid, redirect to the first page
142 | return Redirect::to($this->currentPageUrl() . '?page=1');
143 | }
144 | $this->album = $this->page->album = $this->loadAlbum();
145 | // if current page is greater than number of pages, redirect to the last page
146 | // check for > 1 to avoid infinite redirect when there are no photos
147 | if (($this->currentPage > 1) && ($this->currentPage > $this->lastPage)) {
148 | return Redirect::to($this->currentPageUrl() . '?page=' . $this->lastPage);
149 | }
150 | }
151 |
152 |
153 | /**
154 | *
155 | * Loads album model with it's photos
156 | *
157 | * @return AlbumModel
158 | */
159 | protected function loadAlbum() {
160 | $slug = $this->property('slug');
161 | $album = AlbumModel::where('slug', $slug)
162 | ->with(['photos' => function ($query) {
163 | $query->orderBy('created_at', 'desc');
164 | $query->with('image');
165 | $query->paginate($this->property('photosOnPage'), $this->currentPage);
166 | }])
167 | ->first();
168 |
169 | if ($album) {
170 | //prepare photo urls and thumbs
171 | foreach ($album->photos as $photo) {
172 | $photo->url = $photo->setUrl($this->property('photoPage'), $this->controller);
173 | $photo->thumb = $photo->image->getThumb(
174 | $this->property('thumbWidth'),
175 | $this->property('thumbHeight'),
176 | ['mode' => $this->property('thumbMode')]
177 | );
178 | }
179 | //setup page numbers
180 | $this->lastPage = ceil($album->photosCount / $this->property('photosOnPage'));
181 | }
182 |
183 | return $album;
184 | }
185 |
186 | }
187 |
--------------------------------------------------------------------------------
/components/AlbumList.php:
--------------------------------------------------------------------------------
1 | 'graker.photoalbums::lang.components.albums_list',
37 | 'description' => 'graker.photoalbums::lang.components.albums_list_description'
38 | ];
39 | }
40 |
41 | /**
42 | *
43 | * Define properties
44 | *
45 | * @return array of component properties
46 | */
47 | public function defineProperties()
48 | {
49 | return [
50 | 'albumPage' => [
51 | 'title' => 'graker.photoalbums::lang.components.album_page_label',
52 | 'description' => 'graker.photoalbums::lang.components.album_page_description',
53 | 'type' => 'dropdown',
54 | 'default' => 'photoalbums/album',
55 | ],
56 | 'thumbMode' => [
57 | 'title' => 'graker.photoalbums::lang.components.thumb_mode_label',
58 | 'description' => 'graker.photoalbums::lang.components.thumb_mode_description',
59 | 'type' => 'dropdown',
60 | 'default' => 'auto',
61 | ],
62 | 'thumbWidth' => [
63 | 'title' => 'graker.photoalbums::lang.components.thumb_width_label',
64 | 'description' => 'graker.photoalbums::lang.components.thumb_width_description',
65 | 'default' => 640,
66 | 'type' => 'string',
67 | 'validationMessage' => 'graker.photoalbums::lang.errors.thumb_width_error',
68 | 'validationPattern' => '^[0-9]+$',
69 | 'required' => FALSE,
70 | ],
71 | 'thumbHeight' => [
72 | 'title' => 'graker.photoalbums::lang.components.thumb_height_label',
73 | 'description' => 'graker.photoalbums::lang.components.thumb_height_description',
74 | 'default' => 480,
75 | 'type' => 'string',
76 | 'validationMessage' => 'graker.photoalbums::lang.errors.thumb_height_error',
77 | 'validationPattern' => '^[0-9]+$',
78 | 'required' => FALSE,
79 | ],
80 | 'albumsOnPage' => [
81 | 'title' => 'graker.photoalbums::lang.components.albums_on_page_label',
82 | 'description' => 'graker.photoalbums::lang.components.albums_on_page_description',
83 | 'default' => 12,
84 | 'type' => 'string',
85 | 'validationMessage' => 'graker.photoalbums::lang.errors.albums_on_page_error',
86 | 'validationPattern' => '^[0-9]+$',
87 | 'required' => FALSE,
88 | ],
89 | ];
90 | }
91 |
92 |
93 | /**
94 | *
95 | * Returns pages list for album page select box setting
96 | *
97 | * @return mixed
98 | */
99 | public function getAlbumPageOptions() {
100 | return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
101 | }
102 |
103 |
104 | /**
105 | *
106 | * Returns thumb resize mode options for thumb mode select box setting
107 | *
108 | * @return array
109 | */
110 | public function getThumbModeOptions() {
111 | return [
112 | 'auto' => 'Auto',
113 | 'exact' => 'Exact',
114 | 'portrait' => 'Portrait',
115 | 'landscape' => 'Landscape',
116 | 'crop' => 'Crop',
117 | ];
118 | }
119 |
120 |
121 | /**
122 | * Get photo page number from query
123 | */
124 | protected function setCurrentPage() {
125 | if (isset($_GET['page'])) {
126 | if (ctype_digit($_GET['page']) && ($_GET['page'] > 0)) {
127 | $this->currentPage = $_GET['page'];
128 | } else {
129 | return FALSE;
130 | }
131 | } else {
132 | $this->currentPage = 1;
133 | }
134 | return TRUE;
135 | }
136 |
137 |
138 | /**
139 | * OnRun implementation
140 | * Setup pager
141 | * Load albums
142 | */
143 | public function onRun() {
144 | if (!$this->setCurrentPage()) {
145 | return Redirect::to($this->currentPageUrl() . '?page=1');
146 | }
147 | $this->albums = $this->loadAlbums();
148 | $this->prepareAlbums();
149 |
150 | $this->lastPage = $this->albums->lastPage();
151 | // if current page is greater than number of pages, redirect to the last page
152 | // only if lastPage > 0 to avoid redirect loop when there are no elements
153 | if ($this->lastPage && ($this->currentPage > $this->lastPage)) {
154 | return Redirect::to($this->currentPageUrl() . '?page=' . $this->lastPage);
155 | }
156 | }
157 |
158 |
159 | /**
160 | *
161 | * Returns array of site's albums to be used in component
162 | * Albums are sorted by created date desc, each one loaded with one latest photo (or photo set to be front)
163 | * Empty albums won't be displayed
164 | *
165 | * @return array
166 | */
167 | protected function loadAlbums() {
168 | $albums = AlbumModel::orderBy('created_at', 'desc')
169 | ->has('photos')
170 | ->with(['latestPhoto' => function ($query) {
171 | $query->with('image');
172 | }])
173 | ->with(['front' => function ($query) {
174 | $query->with('image');
175 | }])
176 | ->with('photosCount')
177 | ->paginate($this->property('albumsOnPage'), $this->currentPage);
178 |
179 | return $albums;
180 | }
181 |
182 |
183 | /**
184 | *
185 | * Prepares array of album models to be displayed:
186 | * - set up album urls
187 | * - set up photo counts
188 | * - set up album thumb
189 | */
190 | protected function prepareAlbums() {
191 | //set up photo count and url
192 | foreach ($this->albums as $album) {
193 | $album->photo_count = $album->photosCount;
194 | $album->url = $album->setUrl($this->property('albumPage'), $this->controller);
195 |
196 | // prepare thumb from $album->front if it is set or from latestPhoto otherwise
197 | $image = ($album->front) ? $album->front->image : $album->latestPhoto->image;
198 | $album->latestPhoto->thumb = $image->getThumb(
199 | $this->property('thumbWidth'),
200 | $this->property('thumbHeight'),
201 | ['mode' => $this->property('thumbMode')]
202 | );
203 | }
204 | }
205 |
206 | }
207 |
--------------------------------------------------------------------------------
/components/Photo.php:
--------------------------------------------------------------------------------
1 | 'graker.photoalbums::lang.plugin.photo',
16 | 'description' => 'graker.photoalbums::lang.components.photo_description'
17 | ];
18 | }
19 |
20 | /**
21 | *
22 | * Properties of component
23 | *
24 | * @return array
25 | */
26 | public function defineProperties()
27 | {
28 | return [
29 | 'id' => [
30 | 'title' => 'graker.photoalbums::lang.components.id_label',
31 | 'description' => 'graker.photoalbums::lang.components.id_description',
32 | 'default' => '{{ :id }}',
33 | 'type' => 'string'
34 | ],
35 | 'albumPage' => [
36 | 'title' => 'graker.photoalbums::lang.components.album_page_label',
37 | 'description' => 'graker.photoalbums::lang.components.album_page_description',
38 | 'type' => 'dropdown',
39 | 'default' => 'photoalbums/album',
40 | ],
41 | 'photoPage' => [
42 | 'title' => 'graker.photoalbums::lang.components.photo_page_label',
43 | 'description' => 'graker.photoalbums::lang.components.photo_page_description',
44 | 'type' => 'dropdown',
45 | 'default' => 'photoalbums/album/photo',
46 | ],
47 | ];
48 | }
49 |
50 |
51 | /**
52 | *
53 | * Returns pages list for album page select box setting
54 | *
55 | * @return mixed
56 | */
57 | public function getAlbumPageOptions() {
58 | return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
59 | }
60 |
61 |
62 | /**
63 | *
64 | * Returns pages list for photo page select box setting
65 | *
66 | * @return mixed
67 | */
68 | public function getPhotoPageOptions() {
69 | return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
70 | }
71 |
72 |
73 | /**
74 | * Loads photo on onRun event
75 | */
76 | public function onRun() {
77 | $this->photo = $this->page->photo = $this->loadPhoto();
78 | }
79 |
80 |
81 | /**
82 | *
83 | * Loads photo to be displayed in this component
84 | *
85 | * @return PhotoModel
86 | */
87 | protected function loadPhoto() {
88 | $id = $this->property('id');
89 | $photo = PhotoModel::where('id', $id)
90 | ->with('image')
91 | ->with('album')
92 | ->first();
93 |
94 | if ($photo) {
95 | // set url so we can have back link to the parent album
96 | $photo->album->url = $photo->album->setUrl($this->property('albumPage'), $this->controller);
97 |
98 | //set next and previous photos
99 | $photo->next = $photo->nextPhoto();
100 | if ($photo->next) {
101 | $photo->next->url = $photo->next->setUrl($this->property('photoPage'), $this->controller);
102 | }
103 | $photo->previous = $photo->previousPhoto();
104 | if ($photo->previous) {
105 | $photo->previous->url = $photo->previous->setUrl($this->property('photoPage'), $this->controller);
106 | }
107 | }
108 |
109 | return $photo;
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/components/RandomPhotos.php:
--------------------------------------------------------------------------------
1 | 'graker.photoalbums::lang.components.random_photos',
17 | 'description' => 'graker.photoalbums::lang.components.random_photos_description',
18 | ];
19 | }
20 |
21 | public function defineProperties()
22 | {
23 | return [
24 | 'photosCount' => [
25 | 'title' => 'graker.photoalbums::lang.components.photos_count_label',
26 | 'description' => 'graker.photoalbums::lang.components.photos_count_description',
27 | 'default' => 5,
28 | 'type' => 'string',
29 | 'validationMessage' => 'graker.photoalbums::lang.errors.photos_count_error',
30 | 'validationPattern' => '^[0-9]+$',
31 | 'required' => FALSE,
32 | ],
33 | 'cacheLifetime' => [
34 | 'title' => 'graker.photoalbums::lang.components.cache_lifetime_label',
35 | 'description' => 'graker.photoalbums::lang.components.cache_lifetime_description',
36 | 'default' => 0,
37 | 'type' => 'string',
38 | 'validationMessage' => 'graker.photoalbums::lang.errors.cache_lifetime_error',
39 | 'validationPattern' => '^[0-9]+$',
40 | 'required' => FALSE,
41 | ],
42 | 'thumbMode' => [
43 | 'title' => 'graker.photoalbums::lang.components.thumb_mode_label',
44 | 'description' => 'graker.photoalbums::lang.components.thumb_mode_description',
45 | 'type' => 'dropdown',
46 | 'default' => 'auto',
47 | ],
48 | 'thumbWidth' => [
49 | 'title' => 'graker.photoalbums::lang.components.thumb_width_label',
50 | 'description' => 'graker.photoalbums::lang.components.thumb_width_description',
51 | 'default' => 640,
52 | 'type' => 'string',
53 | 'validationMessage' => 'graker.photoalbums::lang.errors.thumb_width_error',
54 | 'validationPattern' => '^[0-9]+$',
55 | 'required' => FALSE,
56 | ],
57 | 'thumbHeight' => [
58 | 'title' => 'graker.photoalbums::lang.components.thumb_height_label',
59 | 'description' => 'graker.photoalbums::lang.components.thumb_height_description',
60 | 'default' => 480,
61 | 'type' => 'string',
62 | 'validationMessage' => 'graker.photoalbums::lang.errors.thumb_height_error',
63 | 'validationPattern' => '^[0-9]+$',
64 | 'required' => FALSE,
65 | ],
66 | 'photoPage' => [
67 | 'title' => 'graker.photoalbums::lang.components.photo_page_label',
68 | 'description' => 'graker.photoalbums::lang.components.photo_page_description',
69 | 'type' => 'dropdown',
70 | 'default' => 'blog/post',
71 | ],
72 | ];
73 | }
74 |
75 |
76 | /**
77 | *
78 | * Returns pages list for album page select box setting
79 | *
80 | * @return mixed
81 | */
82 | public function getPhotoPageOptions() {
83 | return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
84 | }
85 |
86 |
87 | /**
88 | *
89 | * Returns thumb resize mode options for thumb mode select box setting
90 | *
91 | * @return array
92 | */
93 | public function getThumbModeOptions() {
94 | return [
95 | 'auto' => 'Auto',
96 | 'exact' => 'Exact',
97 | 'portrait' => 'Portrait',
98 | 'landscape' => 'Landscape',
99 | 'crop' => 'Crop',
100 | ];
101 | }
102 |
103 |
104 | /**
105 | *
106 | * Returns an array of photosCount random photos
107 | * Array is returned if from Cache, Collection otherwise
108 | *
109 | * @return array|Collection
110 | */
111 | public function photos() {
112 | $photos = [];
113 | if ($this->property('cacheLifetime')) {
114 | $photos = Cache::get('photoalbums_random_photos');
115 | }
116 |
117 | if (empty($photos)) {
118 | $photos = $this->getPhotos();
119 | }
120 |
121 | return $photos;
122 | }
123 |
124 |
125 | /**
126 | *
127 | * Returns a collection of random photos
128 | * Works for MySQL and Sqlite, for other drivers returns non-random selection
129 | *
130 | * @return Collection
131 | */
132 | protected function getPhotos() {
133 | $count = $this->property('photosCount');
134 | if (DB::connection()->getDriverName() == 'mysql') {
135 | $photos = PhotoModel::orderBy(DB::raw('RAND()'));
136 | } else if (DB::connection()->getDriverName() == 'sqlite') {
137 | $photos = PhotoModel::orderBy(DB::raw('RANDOM()'));
138 | } else {
139 | $photos = PhotoModel::orderBy('id');
140 | }
141 | $photos = $photos->with('image')->take($count)->get();
142 |
143 | foreach ($photos as $photo) {
144 | $photo->url = $photo->setUrl($this->property('photoPage'), $this->controller);
145 | $photo->thumb = $photo->image->getThumb(
146 | $this->property('thumbWidth'),
147 | $this->property('thumbHeight'),
148 | ['mode' => $this->property('thumbMode')]
149 | );
150 | }
151 |
152 | $this->cachePhotos($photos);
153 |
154 | return $photos;
155 | }
156 |
157 |
158 | /**
159 | *
160 | * Cache photos if caching is enabled
161 | *
162 | * @param Collection $photos
163 | */
164 | protected function cachePhotos($photos) {
165 | $cache = $this->property('cacheLifetime');
166 | if ($cache) {
167 | Cache::put('photoalbums_random_photos', $photos->toArray(), $cache);
168 | }
169 | }
170 |
171 | }
172 |
--------------------------------------------------------------------------------
/components/album/default.htm:
--------------------------------------------------------------------------------
1 | {% set album = __SELF__.album %}
2 |
3 | {{ album.title }}
4 |
5 | {% if album.description %}
6 |
7 |
8 | {{ album.description|raw }}
9 |
10 |
11 | {% endif %}
12 |
13 |
14 | {% for photo in album.photos %}
15 |
25 | {% else %}
26 |
Album doesn't have any photos yet
27 | {% endfor %}
28 |
29 |
30 | {% if __SELF__.lastPage > 1 %}
31 |
46 | {% endif %}
47 |
--------------------------------------------------------------------------------
/components/albumlist/default.htm:
--------------------------------------------------------------------------------
1 |
2 | {% for album in __SELF__.albums %}
3 |
4 |
5 |
6 |
10 |
11 | Created on {{ album.created_at|date('M d, Y') }}
12 | {{ album.photo_count }} images
13 |
14 | {% else %}
15 |
You have not created any albums yet
16 | {% endfor %}
17 |
18 |
19 | {% if __SELF__.lastPage > 1 %}
20 |
35 | {% endif %}
36 |
--------------------------------------------------------------------------------
/components/photo/default.htm:
--------------------------------------------------------------------------------
1 | {% set photo = __SELF__.photo %}
2 |
3 | {% if photo.title %}
4 | {{ photo.title }}
5 | {% endif %}
6 |
7 |
8 |

14 |
15 |
16 |
17 |
18 | {{ photo.created_at|date('Y/m/d') }}
19 |
{{ photo.album.title }}
20 | {% if photo.description %}
21 | {{ photo.description | raw }}
22 | {% endif %}
23 |
24 |
25 | {% if photo.previous %}
26 |
Previous photo
27 | {% else %}
28 |
Previous photo
29 | {% endif %}
30 | {% if photo.next %}
31 |
Next photo
32 | {% else %}
33 |
Next photo
34 | {% endif %}
35 |
36 |
37 |
--------------------------------------------------------------------------------
/components/randomphotos/default.htm:
--------------------------------------------------------------------------------
1 |
2 | {% for photo in __SELF__.photos() %}
3 |
9 | {% else %}
10 | You have not created any photos
11 | {% endfor %}
12 |
13 |
--------------------------------------------------------------------------------
/controllers/Albums.php:
--------------------------------------------------------------------------------
1 | album_id != $album->id) {
64 | // attempt to use other album's photo
65 | throw new ApplicationException(Lang::get('graker.photoalbums::lang.errors.not_this_album'));
66 | }
67 | } catch (Exception $e) {
68 | return Response::json($e->getMessage(), 400);
69 | }
70 |
71 | // set front id
72 | $album->front_id = $photo->id;
73 | $album->save();
74 |
75 | $this->initRelation($album, 'photos');
76 | return $this->relationRefresh('photos');
77 | }
78 |
79 |
80 | /**
81 | *
82 | * Returns path to reorder current album
83 | *
84 | * @return string
85 | */
86 | protected function getReorderPath() {
87 | if (!isset($this->vars['formModel']->id)) {
88 | return '';
89 | }
90 |
91 | $uri = \Backend::url('graker/photoalbums/reorder/album/' . $this->vars['formModel']->id);
92 | return $uri;
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/controllers/Photos.php:
--------------------------------------------------------------------------------
1 | model = $album;
38 | $this->addJs('/modules/backend/behaviors/reordercontroller/assets/js/october.reorder.js', 'core');
39 |
40 | $this->pageTitle = Lang::get('graker.photoalbums::lang.plugin.reorder_title', ['name' => $album->title]);
41 |
42 | return $this->makePartial('reorder', ['reorderRecords' => $this->model->photos,]);
43 | }
44 |
45 |
46 | /**
47 | * Callback to save reorder information
48 | * Calls function from Sortable trait on the model
49 | */
50 | public function onReorder() {
51 | if (!$ids = post('record_ids')) return;
52 | if (!$orders = post('sort_orders')) return;
53 |
54 | $model = new Photo();
55 | $model->setSortableOrder($ids, $orders);
56 | }
57 |
58 |
59 | /**
60 | * Reorder constructor
61 | */
62 | public function __construct()
63 | {
64 | parent::__construct();
65 |
66 | BackendMenu::setContext('Graker.PhotoAlbums', 'photoalbums', 'albums');
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/controllers/Upload.php:
--------------------------------------------------------------------------------
1 | pageTitle = Lang::get('graker.photoalbums::lang.plugin.upload_photos');
30 | $this->addJs('/modules/backend/assets/vendor/dropzone/dropzone.js');
31 | $this->addJs('/plugins/graker/photoalbums/assets/js/upload.js');
32 | $this->addCss('/plugins/graker/photoalbums/assets/css/dropzone.css');
33 | return $this->makePartial('form');
34 | }
35 |
36 |
37 | /**
38 | * File upload controller
39 | */
40 | public function post_files() {
41 | try {
42 | if (!Input::hasFile('file')) {
43 | throw new ApplicationException(Lang::get('graker.photoalbums::lang.errors.no_file'));
44 | }
45 |
46 | $upload = Input::file('file');
47 |
48 | $validationRules = ['max:' . File::getMaxFilesize()];
49 |
50 | $validation = Validator::make(
51 | ['file' => $upload],
52 | ['file' => $validationRules]
53 | );
54 | if ($validation->fails()) {
55 | throw new ValidationException($validation);
56 | }
57 | if (!$upload->isValid()) {
58 | throw new ApplicationException(Lang::get('graker.photoalbums::lang.errors.invalid_file', ['name' => $upload->getClientOriginalName()]));
59 | }
60 |
61 | $file = new File;
62 | $file->data = $upload;
63 | $file->is_public = true;
64 | $file->save();
65 | return Response::json(['id' => $file->id], 200);
66 | } catch (Exception $e) {
67 | return Response::json($e->getMessage(), 400);
68 | }
69 | }
70 |
71 |
72 | /**
73 | * Form save callback
74 | */
75 | public function onSave() {
76 | $input = Input::all();
77 |
78 | $album = AlbumModel::find($input['album']);
79 | if ($album && !empty($input['file-id'])) {
80 | $this->savePhotos($album, $input['file-id'], $input['file-title']);
81 | Flash::success(Lang::get('graker.photoalbums::lang.messages.photos_saved'));
82 | return Redirect::to(Backend::url('graker/photoalbums/albums/update/' . $album->id));
83 | }
84 |
85 | Flash::error(Lang::get('graker.photoalbums::lang.errors.album_not_found'));
86 | return Redirect::to(Backend::url('graker/photoalbums/albums'));
87 | }
88 |
89 |
90 | /**
91 | * File remove callback
92 | */
93 | public function onFileRemove() {
94 | if (Input::has('file_id')) {
95 | $file_id = Input::get('file_id');
96 | $file = File::find($file_id);
97 | if ($file) {
98 | $file->delete();
99 | }
100 | }
101 | }
102 |
103 |
104 | /**
105 | *
106 | * Saves photos with files attached from $file_ids and attaches them to album
107 | *
108 | * @param AlbumModel $album
109 | * @param array $file_ids
110 | * @param string[] $file_titles arrray of titles
111 | */
112 | protected function savePhotos($album, $file_ids, $file_titles) {
113 | $files = File::whereIn('id', $file_ids)->get();
114 | $photos = array();
115 | foreach ($files as $file) {
116 | $photo = new PhotoModel();
117 | $photo->title = isset($file_titles[$file->id]) ? $file_titles[$file->id] : '';
118 | $photo->save();
119 | $photo->image()->save($file);
120 | $photos[] = $photo;
121 | }
122 | $album->photos()->saveMany($photos);
123 | }
124 |
125 |
126 | /**
127 | * @return array of [album id => album title] to use in select list
128 | */
129 | protected function getAlbumsList() {
130 | $albums = AlbumModel::orderBy('created_at', 'desc')->get();
131 | $options = [];
132 |
133 | foreach ($albums as $album) {
134 | $options[$album->id] = $album->title;
135 | }
136 |
137 | return $options;
138 | }
139 |
140 |
141 | public function __construct()
142 | {
143 | parent::__construct();
144 |
145 | BackendMenu::setContext('Graker.PhotoAlbums', 'photoalbums', 'upload');
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/controllers/albums/_list_toolbar.htm:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/controllers/albums/_relation_toolbar.htm:
--------------------------------------------------------------------------------
1 |
54 |
--------------------------------------------------------------------------------
/controllers/albums/config_form.yaml:
--------------------------------------------------------------------------------
1 | # ===================================
2 | # Form Behavior Config
3 | # ===================================
4 |
5 | # Record name
6 | name: graker.photoalbums::lang.plugin.album
7 |
8 | # Model Form Field configuration
9 | form: $/graker/photoalbums/models/album/fields.yaml
10 |
11 | # Model Class name
12 | modelClass: Graker\Photoalbums\Models\Album
13 |
14 | # Default redirect location
15 | defaultRedirect: graker/photoalbums/albums
16 |
17 | # Create page
18 | create:
19 | title: graker.photoalbums::lang.plugin.create_album
20 | redirect: graker/photoalbums/albums/update/:id
21 | redirectClose: graker/photoalbums/albums
22 |
23 | # Update page
24 | update:
25 | title: graker.photoalbums::lang.plugin.edit_album
26 | redirect: graker/photoalbums/albums
27 | redirectClose: graker/photoalbums/albums
28 |
29 | # Preview page
30 | preview:
31 | title: graker.photoalbums::lang.plugin.preview_album
--------------------------------------------------------------------------------
/controllers/albums/config_list.yaml:
--------------------------------------------------------------------------------
1 | # ===================================
2 | # List Behavior Config
3 | # ===================================
4 |
5 | # Model List Column configuration
6 | list: $/graker/photoalbums/models/album/columns.yaml
7 |
8 | # Model Class name
9 | modelClass: Graker\Photoalbums\Models\Album
10 |
11 | # List Title
12 | title: graker.photoalbums::lang.plugin.list_title
13 |
14 | # Link URL for each record
15 | recordUrl: graker/photoalbums/albums/update/:id
16 |
17 | # Message to display if the list is empty
18 | noRecordsMessage: backend::lang.list.no_records
19 |
20 | # Records to display per page
21 | recordsPerPage: 20
22 |
23 | # Displays the list column set up button
24 | showSetup: true
25 |
26 | # Displays the sorting link on each column
27 | showSorting: true
28 |
29 | # Default sorting column
30 | # defaultSort:
31 | # column: created_at
32 | # direction: desc
33 |
34 | # Display checkboxes next to each record
35 | # showCheckboxes: true
36 |
37 | # Toolbar widget configuration
38 | toolbar:
39 | # Partial for toolbar buttons
40 | buttons: list_toolbar
41 |
42 | # Search widget configuration
43 | search:
44 | prompt: backend::lang.list.search_prompt
45 |
--------------------------------------------------------------------------------
/controllers/albums/config_relation.yaml:
--------------------------------------------------------------------------------
1 | # ===================================
2 | # Relation Behavior Config
3 | # ===================================
4 |
5 | photos:
6 | label: graker.photoalbums::lang.plugin.photo
7 | manage:
8 | form: $/graker/photoalbums/models/photo/fields.yaml
9 | list: $/graker/photoalbums/models/photo/columns.yaml
10 | view:
11 | list: $/graker/photoalbums/models/photo/columns.yaml
12 | toolbarPartial: relation_toolbar
13 |
--------------------------------------------------------------------------------
/controllers/albums/create.htm:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | fatalError): ?>
9 |
10 | = Form::open(['class' => 'layout']) ?>
11 |
12 |
13 | = $this->formRender() ?>
14 |
15 |
16 |
17 | = $this->relationRender('photos') ?>
18 |
19 |
20 |
44 |
45 | = Form::close() ?>
46 |
47 |
48 |
49 | = e($this->fatalError) ?>
50 | = e(trans('graker.photoalbums::lang.errors.return_to_albums')) ?>
51 |
52 |
--------------------------------------------------------------------------------
/controllers/albums/index.htm:
--------------------------------------------------------------------------------
1 |
2 | = $this->listRender() ?>
3 |
--------------------------------------------------------------------------------
/controllers/albums/preview.htm:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | fatalError): ?>
9 |
10 |
11 | = $this->formRenderPreview() ?>
12 |
13 |
14 |
15 |
16 | = e($this->fatalError) ?>
17 | = e(trans('graker.photoalbums::lang.errors.return_to_albums')) ?>
18 |
19 |
--------------------------------------------------------------------------------
/controllers/albums/update.htm:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | fatalError): ?>
9 |
10 | = Form::open(['class' => 'layout']) ?>
11 |
12 |
13 | = $this->formRender() ?>
14 |
15 |
16 |
17 | = $this->relationRender('photos') ?>
18 |
19 |
20 |
52 |
53 | = Form::close() ?>
54 |
55 |
56 |
57 | = e($this->fatalError) ?>
58 | = e(trans('backend::lang.errors.return_to_albums')) ?>
59 |
60 |
--------------------------------------------------------------------------------
/controllers/photos/_list_toolbar.htm:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/controllers/photos/config_form.yaml:
--------------------------------------------------------------------------------
1 | # ===================================
2 | # Form Behavior Config
3 | # ===================================
4 |
5 | # Record name
6 | name: graker.photoalbums::lang.plugin.photo
7 |
8 | # Model Form Field configuration
9 | form: $/graker/photoalbums/models/photo/fields.yaml
10 |
11 | # Model Class name
12 | modelClass: Graker\PhotoAlbums\Models\Photo
13 |
14 | # Default redirect location
15 | defaultRedirect: graker/photoalbums/photos
16 |
17 | # Create page
18 | create:
19 | title: graker.photoalbums::lang.plugin.create_photo
20 | redirect: graker/photoalbums/photos/update/:id
21 | redirectClose: graker/photoalbums/photos
22 |
23 | # Update page
24 | update:
25 | title: graker.photoalbums::lang.plugin.edit_photo
26 | redirect: graker/photoalbums/photos
27 | redirectClose: graker/photoalbums/photos
28 |
29 | # Preview page
30 | preview:
31 | title: graker.photoalbums::lang.plugin.preview_photo
--------------------------------------------------------------------------------
/controllers/photos/config_list.yaml:
--------------------------------------------------------------------------------
1 | # ===================================
2 | # List Behavior Config
3 | # ===================================
4 |
5 | # Model List Column configuration
6 | list: $/graker/photoalbums/models/photo/columns.yaml
7 |
8 | # Model Class name
9 | modelClass: Graker\PhotoAlbums\Models\Photo
10 |
11 | # List Title
12 | title: graker.photoalbums::lang.plugin.manage_photos
13 |
14 | # Link URL for each record
15 | recordUrl: graker/photoalbums/photos/update/:id
16 |
17 | # Message to display if the list is empty
18 | noRecordsMessage: backend::lang.list.no_records
19 |
20 | # Records to display per page
21 | recordsPerPage: 20
22 |
23 | # Displays the list column set up button
24 | showSetup: true
25 |
26 | # Displays the sorting link on each column
27 | showSorting: true
28 |
29 | # Toolbar widget configuration
30 | toolbar:
31 | # Partial for toolbar buttons
32 | buttons: list_toolbar
33 |
34 | # Search widget configuration
35 | search:
36 | prompt: backend::lang.list.search_prompt
37 |
--------------------------------------------------------------------------------
/controllers/photos/create.htm:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | fatalError): ?>
9 |
10 | = Form::open(['class' => 'layout']) ?>
11 |
12 |
13 | = $this->formRender() ?>
14 |
15 |
16 |
40 |
41 | = Form::close() ?>
42 |
43 |
44 |
45 | = e($this->fatalError) ?>
46 | = e(trans('backend::lang.errors.return_to_photos')) ?>
47 |
48 |
--------------------------------------------------------------------------------
/controllers/photos/index.htm:
--------------------------------------------------------------------------------
1 |
2 | = $this->listRender() ?>
3 |
--------------------------------------------------------------------------------
/controllers/photos/preview.htm:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | fatalError): ?>
9 |
10 |
11 | = $this->formRenderPreview() ?>
12 |
13 |
14 |
15 |
16 | = e($this->fatalError) ?>
17 | = e(trans('backend::lang.errors.return_to_photos')) ?>
18 |
19 |
--------------------------------------------------------------------------------
/controllers/photos/update.htm:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | fatalError): ?>
9 |
10 | = Form::open(['class' => 'layout']) ?>
11 |
12 |
13 | = $this->formRender() ?>
14 |
15 |
16 |
48 |
49 | = Form::close() ?>
50 |
51 |
52 |
53 | = e($this->fatalError) ?>
54 | = e(trans('graker.photoalbums::lang.errors.return_to_photos')) ?>
55 |
56 |
--------------------------------------------------------------------------------
/controllers/reorder/_records.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
; ?>)
6 |
= $record->title ?>
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/controllers/reorder/_reorder.htm:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | fatalError): ?>
10 |
11 | = Form::open() ?>
12 |
19 |
20 |
21 | = $this->makePartial('records', ['records' => $reorderRecords]) ?>
22 |
23 |
24 |
= Lang::get('backend::lang.reorder.no_records') ?>
25 |
26 |
27 | = Form::close() ?>
28 |
29 |
32 |
33 |
34 | = e($this->fatalError) ?>
35 | = e(trans('graker.photoalbums::lang.errors.return_to_albums')) ?>
36 |
--------------------------------------------------------------------------------
/controllers/upload/_form.htm:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | fatalError): ?>
9 | = Form::open(['file' => TRUE, 'class' => 'layout',]) ?>
10 |
11 |
12 | = Form::label('album', e(trans('graker.photoalbums::lang.plugin.album_to_upload')) ) ?>
13 | = Form::select('album', $this->getAlbumsList()) ?>
14 |
15 |
22 |
26 |
27 |
28 |
43 |
44 | = Form::close() ?>
45 |
46 |
47 |
48 | = e($this->fatalError) ?>
49 | = e(trans('graker.photoalbums::lang.errors.return_to_albums')) ?>
50 |
51 |
52 |
--------------------------------------------------------------------------------
/lang/en/lang.php:
--------------------------------------------------------------------------------
1 | [
5 | 'name' => 'Photo Albums',
6 | 'description' => 'Create, display and manage galleries of photos arranged in albums.',
7 | 'settings_description' => 'Photo Albums plugin settings',
8 | 'tab' => 'Photo Albums',
9 | 'manage_albums' => 'Manage photo albums',
10 | 'access_permission' => 'Access Settings',
11 | 'upload_photos' => 'Upload photos',
12 | 'new_album' => 'New album',
13 | 'create_album' => 'Create album',
14 | 'edit_album' => 'Edit album',
15 | 'preview_album' => 'Preview album',
16 | 'creating_album' => 'Creating album...',
17 | 'saving_album' => 'Saving album...',
18 | 'deleting_album' => 'Deleting album...',
19 | 'list_title' => 'Manage albums',
20 | 'album' => 'Album',
21 | 'albums' => 'Albums',
22 | 'manage_photos' => 'Manage photos',
23 | 'new_photo' => 'New photo',
24 | 'create_photo' => 'Create photo',
25 | 'edit_photo' => 'Edit photo',
26 | 'preview_photo' => 'Preview photo',
27 | 'creating_photo' => 'Creating photo...',
28 | 'saving_photo' => 'Saving photo...',
29 | 'deleting_photo' => 'Deleting photo...',
30 | 'photo' => 'Photo',
31 | 'photos' => 'Photos',
32 | 'photo_description' => 'Description',
33 | 'set_front_button' => 'Set as front',
34 | 'reorder_button' => 'Reorder photos',
35 | 'bool_positive' => 'Yes',
36 | 'reorder_title' => 'Reorder album :name',
37 | 'reorder' => 'Reorder',
38 | 'saving_upload' => 'Saving upload...',
39 | 'upload_photos_title' => 'Upload multiple photos',
40 | 'album_to_upload' => 'Album to upload to',
41 | 'save_upload' => 'Save upload',
42 | 'title_label' => 'Title',
43 | 'title_placeholder_album' => 'Album title',
44 | 'title_placeholder_photo' => 'Photo title',
45 | 'created_label' => 'Created',
46 | 'updated_label' => 'Updated',
47 | 'slug_label' => 'Slug',
48 | 'slug_description' => 'URL slug parameter',
49 | 'slug_placeholder_album' => 'album-title',
50 | 'description_label' => 'Description',
51 | 'front_label' => 'Front',
52 | 'code_label' => 'Code',
53 | 'code_description' => 'Type in default markdown to use for photo insert. There are two placeholders: %id% and %title%, they will be replaced with photo id and photo title automatically.',
54 | 'selecting_photo' => 'Selecting photo',
55 | 'insert' => 'Insert',
56 | 'not_selected' => 'Not selected',
57 | 'back_to_albums' => 'Back to albums',
58 | 'all_photo_albums' => 'All Photo Albums',
59 | 'all_photos' => 'All Photos',
60 | ],
61 | 'errors' => [
62 | 'album_not_found' => 'Album not found!',
63 | 'cant_find_selected' => 'Can\'t find selected photo!',
64 | 'not_this_album' => 'Selected photo doesn\'t belong to this album!',
65 | 'return_to_albums' => 'Return to albums list',
66 | 'return_to_photos' => 'Return to photos list',
67 | 'no_file' => 'No file in request',
68 | 'invalid_file' => 'File :name is not valid.',
69 | 'thumb_width_error' => 'Thumb width must be a number',
70 | 'thumb_height_error' => 'Thumb height must be a number',
71 | 'photos_on_page_error' => 'Photos on page value must be a number',
72 | 'albums_on_page_error' => 'Albums on page value must be a number',
73 | 'photos_count_error' => 'Photos count must be a number',
74 | 'cache_lifetime_error' => 'Cache lifetime must be a number',
75 | 'no_albums' => 'You don\'t have any albums yet.',
76 | ],
77 | 'messages' => [
78 | 'set_front' => 'Are you sure to set this photo as front for the album?',
79 | 'delete' => 'Do you really want to delete this album?',
80 | 'delete_photo' => 'Do you really want to delete this photo?',
81 | 'photos_saved' => 'Photos are saved!',
82 | ],
83 | 'components' => [
84 | 'photo_description' => 'Single photo component',
85 | 'album_description' => 'Component to output one photo album with all its photos.',
86 | 'photo_page_label' => 'Photo page',
87 | 'photo_page_description' => 'Page used to display a single photo',
88 | 'thumb_mode_label' => 'Thumb mode',
89 | 'thumb_mode_description' => 'Mode of thumb generation',
90 | 'thumb_width_label' => 'Thumb width',
91 | 'thumb_width_description' => 'Width of the thumb to be generated',
92 | 'thumb_height_label' => 'Thumb height',
93 | 'thumb_height_description' => 'Height of the thumb to be generated',
94 | 'photos_on_page_label' => 'Photos on page',
95 | 'photos_on_page_description' => 'Amount of photos on one page (to use in pagination)',
96 | 'albums_on_page_label' => 'Albums on page',
97 | 'albums_on_page_description' => 'Amount of albums on one page (to use in pagination)',
98 | 'albums_list' => 'Albums list',
99 | 'albums_list_description' => 'Lists all photo albums on site',
100 | 'album_page_label' => 'Album page',
101 | 'album_page_description' => 'Page used to display photo albums',
102 | 'id_label' => 'ID',
103 | 'id_description' => 'Photo id parameter',
104 | 'random_photos' => 'Random Photos',
105 | 'random_photos_description' => 'Output predefined number of random photos',
106 | 'photos_count_label' => 'Photos to output',
107 | 'photos_count_description' => 'Amount of random photos to output',
108 | 'cache_lifetime_label' => 'Cache lifetime',
109 | 'cache_lifetime_description' => 'Number of minutes selected photos are stored in cache. 0 for no caching.',
110 | ],
111 | ];
112 |
--------------------------------------------------------------------------------
/lang/es/lang.php:
--------------------------------------------------------------------------------
1 | [
10 | 'name' => 'Photo Albums',
11 | 'description' => 'Crear, mostrar y gestionar galerías de fotos ordenadas en álbumes.',
12 | 'settings_description' => 'Ajustes del plugin Photo Albums',
13 | 'tab' => 'Álbumes de fotos',
14 | 'manage_albums' => 'Gestionar álbumes de fotos',
15 | 'access_permission' => 'Ajustes de permisos de acceso',
16 | 'upload_photos' => 'Subir fotos',
17 | 'new_album' => 'Nuevo álbum',
18 | 'create_album' => 'Crear álbum',
19 | 'edit_album' => 'Editar álbum',
20 | 'preview_album' => 'Previsualizar álbum',
21 | 'creating_album' => 'Creando álbum...',
22 | 'saving_album' => 'Guardando álbum...',
23 | 'deleting_album' => 'Eliminando álbum...',
24 | 'list_title' => 'Gestionar álbumes',
25 | 'album' => 'Álbum',
26 | 'albums' => 'Álbumes',
27 | 'manage_photos' => 'Gestionar fotos',
28 | 'new_photo' => 'Nueva foto',
29 | 'create_photo' => 'Crear foto',
30 | 'edit_photo' => 'Editar foto',
31 | 'preview_photo' => 'Previsualizar foto',
32 | 'creating_photo' => 'Creando foto...',
33 | 'saving_photo' => 'Guardando photo...',
34 | 'deleting_photo' => 'Eliminando foto...',
35 | 'photo' => 'Foto',
36 | 'photos' => 'Fotos',
37 | 'photo_description' => 'Descripción',
38 | 'set_front_button' => 'Poner como portada',
39 | 'reorder_button' => 'Reordenar fotos',
40 | 'bool_positive' => 'Sí',
41 | 'reorder_title' => 'Reordenar álbum :name',
42 | 'reorder' => 'Reordenar',
43 | 'saving_upload' => 'Guardando subida...',
44 | 'upload_photos_title' => 'Subir múltiples fotos',
45 | 'album_to_upload' => 'Álbum al que subir',
46 | 'save_upload' => 'Guardar subida',
47 | 'title_label' => 'Título',
48 | 'title_placeholder_album' => 'Título del Álbum',
49 | 'title_placeholder_photo' => 'Título de la Foto',
50 | 'created_label' => 'Creación',
51 | 'updated_label' => 'Actualización',
52 | 'slug_label' => 'Identificador',
53 | 'slug_description' => 'Parámetro identificador para la URL (dirección)',
54 | 'slug_placeholder_album' => 'titulo-del-album',
55 | 'description_label' => 'Descripción',
56 | 'front_label' => 'Portada',
57 | 'code_label' => 'Código',
58 | 'code_description' => 'Pon el código markdown para usar para las inserciones de fotos. Hay dos variables: %id% y %title%, serán reemplazadas con la id y el título de la foto automáticamente.',
59 | 'selecting_photo' => 'Seleccionando foto',
60 | 'insert' => 'Insertar',
61 | 'not_selected' => 'Sin seleccionar',
62 | 'back_to_albums' => 'Volver a álbumes',
63 | 'all_photo_albums' => 'Todos los álbumes de fotos',
64 | 'all_photos' => 'Todas las fotos',
65 | ],
66 | 'errors' => [
67 | 'album_not_found' => '¡Álbum encontrado!',
68 | 'cant_find_selected' => '¡No se encuentra la foto seleccionada!',
69 | 'not_this_album' => '¡La foto seleccionada no pertenece a éste álbum!',
70 | 'return_to_albums' => 'Volver a la lista de álbumes',
71 | 'return_to_photos' => 'Volver a la lista de fotos',
72 | 'no_file' => 'No hay archivo en la petición',
73 | 'invalid_file' => 'El archivo :name no es válido.',
74 | 'thumb_width_error' => 'El ancho de miniatura debe ser un número',
75 | 'thumb_height_error' => 'La altura de la miniatura debe ser un número',
76 | 'photos_on_page_error' => 'El valor de fotos por página debe ser un número',
77 | 'albums_on_page_error' => 'El valor de álbumes por página debe ser un número',
78 | 'photos_count_error' => 'La cantidad de fotos debe ser un número',
79 | 'cache_lifetime_error' => 'La vida de la caché debe ser un número',
80 | 'no_albums' => 'No tienes álbumes aún.',
81 | ],
82 | 'messages' => [
83 | 'set_front' => '¿Seguro de quieres poner ésta foto como la portada del álbum?',
84 | 'delete' => '¿Seguro que quieres eliminar éste álbum?Do you really want to delete this álbum?',
85 | 'delete_photo' => '¿Seguro que quieres eliminar ésta foto?',
86 | 'photos_saved' => '¡Fotos guardadas!',
87 | ],
88 | 'components' => [
89 | 'photo_description' => 'Componente de foto suelta',
90 | 'album_description' => 'Componente para obtener un álbum de fotos junto con todas sus fotos.',
91 | 'photo_page_label' => 'Página de foto',
92 | 'photo_page_description' => 'Página usada para mostrar una foto suelta',
93 | 'thumb_mode_label' => 'Modo dce miniaturas',
94 | 'thumb_mode_description' => 'Modo de generación de las miniaturas',
95 | 'thumb_width_label' => 'Ancho de miniatura',
96 | 'thumb_width_description' => 'Ancho de las miniaturas que se generarán',
97 | 'thumb_height_label' => 'Alto de Miniatura',
98 | 'thumb_height_description' => 'Altura de las miniaturas que se generarán',
99 | 'photos_on_page_label' => 'Fotos por página',
100 | 'photos_on_page_description' => 'Cantidad de fotos a mostrar en una página (para usar en la paginación)',
101 | 'albums_on_page_label' => 'Álbumes por página',
102 | 'albums_on_page_description' => 'Cantidad de álbumes a mostrar en una página (para usar en la paginación)',
103 | 'albums_list' => 'Lista de álbumes',
104 | 'albums_list_description' => 'Lista todos los álbumes de fotos en el sitio',
105 | 'album_page_label' => 'Página de álbum',
106 | 'album_page_description' => 'Página usada para mostrar los álbumes de fotos',
107 | 'id_label' => 'ID',
108 | 'id_description' => 'Parámetro de identifiación de la foto',
109 | 'random_photos' => 'Fotos aleatorias',
110 | 'random_photos_description' => 'Muestra un número de fotos aleatorias prefefinido',
111 | 'photos_count_label' => 'Fotos a mostrar',
112 | 'photos_count_description' => 'Cantidad de fotos aleatorias para mostrar',
113 | 'cache_lifetime_label' => 'Vida de la caché',
114 | 'cache_lifetime_description' => 'Número de minutos en que las fotos seleccionadas se guardan en caché. 0 para desactivar.',
115 | ],
116 | ];
117 |
--------------------------------------------------------------------------------
/models/Album.php:
--------------------------------------------------------------------------------
1 | 'required',
22 | 'slug' => ['required', 'regex:/^[a-z0-9\/\:_\-\*\[\]\+\?\|]*$/i', 'unique:graker_photoalbums_albums'],
23 | ];
24 |
25 | /**
26 | * @var array Relations
27 | */
28 | public $hasMany = [
29 | 'photos' => [
30 | 'Graker\PhotoAlbums\Models\Photo',
31 | 'order' => 'sort_order desc',
32 | ]
33 | ];
34 | public $belongsTo = [
35 | 'user' => ['Backend\Models\User'],
36 | 'front' => ['Graker\PhotoAlbums\Models\Photo'],
37 | ];
38 |
39 |
40 | /**
41 | *
42 | * This relation allows us to eager-load 1 latest photo per album
43 | *
44 | * @return mixed
45 | */
46 | public function latestPhoto() {
47 | return $this->hasOne('Graker\PhotoAlbums\Models\Photo')->latest();
48 | }
49 |
50 |
51 | /**
52 | *
53 | * This relation allows us to count photos
54 | *
55 | * @return mixed
56 | */
57 | public function photosCount() {
58 | return $this->hasOne('Graker\PhotoAlbums\Models\Photo')
59 | ->selectRaw('album_id, count(*) as aggregate')
60 | ->orderBy('album_id')
61 | ->groupBy('album_id');
62 | }
63 |
64 |
65 | /**
66 | *
67 | * Getter for photos count
68 | *
69 | * @return int
70 | */
71 | public function getPhotosCountAttribute() {
72 | // if relation is not loaded already, let's do it first
73 | if (!array_key_exists('photosCount', $this->relations)) {
74 | $this->load('photosCount');
75 | }
76 | $related = $this->getRelation('photosCount');
77 |
78 | return ($related) ? (int) $related->aggregate : 0;
79 | }
80 |
81 |
82 | /**
83 | *
84 | * Returns image file of photo set as album front or image in the latest photo of the album
85 | *
86 | * @return File
87 | */
88 | public function getImage() {
89 | if ($this->front) {
90 | return $this->front->image;
91 | }
92 |
93 | if ($this->latestPhoto) {
94 | return $this->latestPhoto->image;
95 | }
96 |
97 | return NULL;
98 | }
99 |
100 |
101 | /**
102 | *
103 | * Sets and returns url for this model using provided page name and controller
104 | * For now we expose just id and slug for URL parameters
105 | *
106 | * @param string $pageName
107 | * @param CMS\Classes\Controller $controller
108 | * @return string
109 | */
110 | public function setUrl($pageName, $controller) {
111 | $params = [
112 | 'id' => $this->id,
113 | 'slug' => $this->slug,
114 | ];
115 |
116 | return $this->url = $controller->pageUrl($pageName, $params);
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/models/Photo.php:
--------------------------------------------------------------------------------
1 | 'required',
25 | ];
26 |
27 | /**
28 | * @var array of fillable fields to use in mass assignment
29 | */
30 | protected $fillable = [
31 | 'title', 'description',
32 | ];
33 |
34 | /**
35 | * @var array Relations
36 | */
37 | public $belongsTo = [
38 | 'user' => ['Backend\Models\User'],
39 | 'album' => ['Graker\PhotoAlbums\Models\Album'],
40 | ];
41 | public $attachOne = [
42 | 'image' => ['System\Models\File'],
43 | ];
44 |
45 |
46 | /**
47 | *
48 | * Returns next photo or NULL if this is the last in the album
49 | *
50 | * @return Photo
51 | */
52 | public function nextPhoto() {
53 | $next = NULL;
54 | $current_found = FALSE;
55 |
56 | foreach ($this->album->photos as $photo) {
57 | if ($current_found) {
58 | // previous iteration was current photo, so we found the next one
59 | $next = $photo;
60 | break;
61 | }
62 | if ($photo->id == $this->id) {
63 | $current_found = TRUE;
64 | }
65 | }
66 |
67 | return $next;
68 | }
69 |
70 |
71 | /**
72 | *
73 | * Returns previous photo or NULL if this is the first in the album
74 | *
75 | * @return Photo
76 | */
77 | public function previousPhoto() {
78 | $previous = NULL;
79 |
80 | foreach ($this->album->photos as $photo) {
81 | if ($photo->id == $this->id) {
82 | // found current photo
83 | break;
84 | } else {
85 | $previous = $photo;
86 | }
87 | }
88 |
89 | return $previous;
90 | }
91 |
92 |
93 | /**
94 | *
95 | * Sets and returns url for this model using provided page name and controller
96 | * For now we expose photo id and album's slug
97 | *
98 | * @param string $pageName
99 | * @param CMS\Classes\Controller $controller
100 | * @return string
101 | */
102 | public function setUrl($pageName, $controller) {
103 | $params = [
104 | 'id' => $this->id,
105 | 'album_slug' => $this->album->slug,
106 | ];
107 |
108 | return $this->url = $controller->pageUrl($pageName, $params);
109 | }
110 |
111 |
112 | /**
113 | * beforeDelete() event
114 | * Using it to delete attached
115 | */
116 | public function beforeDelete() {
117 | if ($this->image) {
118 | $this->image->delete();
119 | }
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/models/Settings.php:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | ./tests
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/RandomPhotosTest.php:
--------------------------------------------------------------------------------
1 | createAlbum();
26 | $photos[] = $this->createPhoto($album);
27 | $photos[] = $this->createPhoto($album);
28 | $photos[] = $this->createPhoto($album);
29 | $photos[] = $this->createPhoto($album);
30 | $photos[] = $this->createPhoto($album);
31 | $photos[] = $this->createPhoto($album);
32 | $photos[] = $this->createPhoto($album);
33 |
34 | // get random photos
35 | $component = $this->createRandomPhotosComponent();
36 | $random_photos = $component->photos();
37 |
38 | // assert all photos are from generated array
39 | self::assertEquals(5, count($random_photos), 'There are 5 random photos');
40 | $found_all = TRUE;
41 | foreach ($random_photos as $random_photo) {
42 | $found = FALSE;
43 | foreach ($photos as $photo) {
44 | if ($photo->id == $random_photo->id) {
45 | $found = TRUE;
46 | break;
47 | }
48 | }
49 | if (!$found) {
50 | $found_all = FALSE;
51 | break;
52 | }
53 | }
54 | self::assertTrue($found_all, 'All photos exist in original array');
55 | }
56 |
57 |
58 | /**
59 | *
60 | * Creates album model
61 | *
62 | * @return \Graker\PhotoAlbums\Models\Album
63 | */
64 | protected function createAlbum() {
65 | $faker = Faker\Factory::create();
66 | $album = new Album();
67 | $album->title = $faker->sentence(3);
68 | $album->slug = str_slug($album->title);
69 | $album->description = $faker->text();
70 | $album->save();
71 | return $album;
72 | }
73 |
74 |
75 | /**
76 | *
77 | * Creates photo model and put it into album
78 | *
79 | * @param \Graker\PhotoAlbums\Models\Album $album
80 | * @return \Graker\PhotoAlbums\Models\Photo
81 | */
82 | protected function createPhoto(Album $album) {
83 | $faker = Faker\Factory::create();
84 | $photo = new Photo();
85 | $photo->title = $faker->sentence(3);
86 | $photo->description = $faker->text();
87 | $photo->image = $faker->image();
88 | $photo->album = $album;
89 | $photo->save();
90 | return $photo;
91 | }
92 |
93 |
94 | /**
95 | *
96 | * Creates randomPhotos component to test
97 | *
98 | * @return \Graker\PhotoAlbums\Components\RandomPhotos
99 | */
100 | protected function createRandomPhotosComponent() {
101 | // Spoof all the objects we need to make a page object
102 | $theme = Theme::load('test');
103 | $page = Page::load($theme, 'index.htm');
104 | $layout = Layout::load($theme, 'content.htm');
105 | $controller = new Controller($theme);
106 | $parser = new CodeParser($page);
107 | $pageObj = $parser->source($page, $layout, $controller);
108 | $manager = ComponentManager::instance();
109 | $object = $manager->makeComponent('randomPhotos', $pageObj);
110 | return $object;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/updates/add_album_front.php:
--------------------------------------------------------------------------------
1 | integer('front_id')->unsigned()->nullable();
14 | });
15 | }
16 |
17 | public function down()
18 | {
19 | Schema::table('graker_photoalbums_albums', function($table)
20 | {
21 | $table->dropColumn('front_id');
22 | });
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/updates/add_sort_order_field.php:
--------------------------------------------------------------------------------
1 | integer('sort_order')->unsigned()->nullable();
14 | });
15 | }
16 |
17 | public function down()
18 | {
19 | Schema::table('graker_photoalbums_photos', function($table)
20 | {
21 | $table->dropColumn('sort_order');
22 | });
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/updates/create_albums_table.php:
--------------------------------------------------------------------------------
1 | engine = 'InnoDB';
14 | $table->increments('id');
15 | $table->integer('user_id')->unsigned()->nullable()->index();
16 | $table->string('title')->nullable();
17 | $table->string('slug')->index();
18 | $table->text('description')->nullable();
19 | $table->timestamps();
20 | });
21 | }
22 |
23 | public function down()
24 | {
25 | Schema::dropIfExists('graker_photoalbums_albums');
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/updates/create_photos_table.php:
--------------------------------------------------------------------------------
1 | engine = 'InnoDB';
14 | $table->increments('id');
15 | $table->integer('user_id')->unsigned()->nullable()->index();
16 | $table->integer('album_id')->unsigned()->nullable()->index();
17 | $table->string('title')->nullable();
18 | $table->text('description')->nullable();
19 | $table->timestamps();
20 | });
21 | }
22 |
23 | public function down()
24 | {
25 | Schema::dropIfExists('graker_photoalbums_photos');
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/updates/update_sort_order_on_existing_photos.php:
--------------------------------------------------------------------------------
1 | sort_order = $photo->id;
15 | $photo->save();
16 | }
17 | }
18 |
19 | public function down()
20 | {
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/updates/version.yaml:
--------------------------------------------------------------------------------
1 | 1.0.1: First version of PhotoAlbums
2 | 1.0.2:
3 | - Update with migrations to create albums and photos table
4 | - create_albums_table.php
5 | - create_photos_table.php
6 | 1.1.0:
7 | - Add ability to select front photo for album from the interface
8 | - add_album_front.php
9 | 1.2.0:
10 | - Added ability to reorder photos in the album
11 | - add_sort_order_field.php
12 | 1.2.1:
13 | - Fill default sort_order values for existing photos
14 | - update_sort_order_on_existing_photos.php
15 | 1.2.2:
16 | - Sqlite support for RandomPhotos component
17 | 1.2.3:
18 | - Added helper method to get album's cover photo
19 | 1.2.4:
20 | - Fix for album front photo eager loading
21 | 1.2.5:
22 | - Fix for photos count in only_full_group_by sql mode
23 | 1.3.0:
24 | - New dialog to insert photos into blog posts
25 | 1.4.0:
26 | - Integration with RainLab.Pages to use Albums and Photos in Menu Items (and Sitemap)
27 | 1.4.1:
28 | - Improved layout of Photo form (thanks to gergo85)
29 | - Improved lang.php strings (thanks to gergo85)
30 | - Localized Menu Item types
31 | 1.4.2:
32 | - Fixed second insert photo icon from occuring in blog post form
33 |
--------------------------------------------------------------------------------
/widgets/PhotoSelector.php:
--------------------------------------------------------------------------------
1 | vars['albums'] = NULL;
38 | $this->vars['album'] = $this->album($album_id);
39 | } else {
40 | $this->vars['albums'] = $this->albums();
41 | $this->vars['album'] = NULL;
42 | }
43 |
44 |
45 | return $this->makePartial('body');
46 | }
47 |
48 |
49 | /**
50 | * Loads widget assets
51 | */
52 | protected function loadAssets() {
53 | $this->addJs('js/photoselector.js');
54 | $this->addCss('css/photoselector.css');
55 | }
56 |
57 |
58 | /**
59 | *
60 | * Callback for when the dialog is initially open
61 | *
62 | * @return string
63 | */
64 | public function onDialogOpen() {
65 | return $this->render();
66 | }
67 |
68 |
69 | /**
70 | *
71 | * Callback to generate albums list
72 | *
73 | * @return array
74 | */
75 | public function onAlbumListLoad() {
76 | $this->vars['albums'] = $this->albums();
77 |
78 | return [
79 | '#listContainer' => $this->makePartial('albums'),
80 | ];
81 | }
82 |
83 |
84 | /**
85 | *
86 | * Callback to generate photos list
87 | * Photos list is to replace albums list in dialog markup
88 | *
89 | * @return array
90 | */
91 | public function onAlbumLoad() {
92 | $album_id = input('id');
93 | $album = $this->album($album_id);
94 | $this->vars['album'] = $album;
95 |
96 | return [
97 | '#listContainer' => $this->makePartial('photos'),
98 | ];
99 | }
100 |
101 |
102 | /**
103 | *
104 | * Returns a collection of all user's albums
105 | *
106 | * @return Collection
107 | */
108 | protected function albums() {
109 | $albums = Album::orderBy('created_at', 'desc')
110 | ->has('photos')
111 | ->with(['latestPhoto' => function ($query) {
112 | $query->with('image');
113 | }])
114 | ->with(['front' => function ($query) {
115 | $query->with('image');
116 | }])
117 | ->get();
118 |
119 | foreach ($albums as $album) {
120 | // prepare thumb from $album->front if it is set or from latestPhoto otherwise
121 | $image = ($album->front) ? $album->front->image : $album->latestPhoto->image;
122 | $album->thumb = $image->getThumb(
123 | 160,
124 | 120,
125 | ['mode' => 'crop']
126 | );
127 | }
128 |
129 | return $albums;
130 | }
131 |
132 |
133 | /**
134 | *
135 | * Returns album with its photos loaded and prepared for display in dialog
136 | *
137 | * @param int $album_id
138 | * @return Album
139 | */
140 | protected function album($album_id) {
141 | $album = Album::where('id', $album_id)
142 | ->with(['photos' => function ($query) {
143 | $query->orderBy('sort_order', 'desc');
144 | $query->with('image');
145 | // TODO implement pagination
146 | }])
147 | ->first();
148 |
149 | if ($album) {
150 | //prepare photo urls and thumbs
151 | foreach ($album->photos as $photo) {
152 | // set thumb
153 | $photo->thumb = $photo->image->getThumb(
154 | 160,
155 | 120,
156 | ['mode' => 'crop']
157 | );
158 | // set code
159 | $photo->code = $this->createPhotoCode($photo);
160 | }
161 | }
162 |
163 | return $album;
164 | }
165 |
166 |
167 | /**
168 | *
169 | * Create an insert markdown code for photo from plugin settings
170 | *
171 | * @param Photo $photo
172 | * @return string
173 | */
174 | protected function createPhotoCode($photo) {
175 | $code_template = Settings::get('code', '');
176 | $code = str_replace(
177 | array('%id%', '%title%'),
178 | array($photo->id, $photo->title),
179 | $code_template
180 | );
181 | return $code;
182 | }
183 |
184 | }
185 |
--------------------------------------------------------------------------------
/widgets/photoselector/assets/css/photoselector.css:
--------------------------------------------------------------------------------
1 | #photosList .photo-link.image-link {
2 | display: inline-block;
3 | padding: 7px;
4 | }
5 |
6 | #photosList .photo-link.image-link.selected {
7 | border: 1px solid;
8 | padding: 6px;
9 | border-radius: 6px;
10 | }
11 |
12 | #photosList .photo-link.title-link.selected {
13 | font-weight: bold;
14 | }
15 |
16 | #photosList .back-to-albums {
17 | margin-top: 16px;
18 | margin-bottom: 16px;
19 | display: block;
20 | }
21 |
--------------------------------------------------------------------------------
/widgets/photoselector/assets/js/photoselector.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * PhotoSelector dialog
4 | */
5 |
6 | +function () {
7 |
8 | if ($.oc.photoselector === undefined) {
9 | $.oc.photoselector = {};
10 | }
11 |
12 | var Base = $.oc.foundation.base,
13 | BaseProto = Base.prototype;
14 |
15 | var PhotoSelector = function (options) {
16 | this.$dialog = $('');
17 | this.options = $.extend({}, PhotoSelector.DEFAULTS, options);
18 |
19 | Base.call(this);
20 |
21 | this.show();
22 | };
23 |
24 |
25 | PhotoSelector.prototype = Object.create(BaseProto);
26 | PhotoSelector.prototype.constructor = PhotoSelector;
27 |
28 |
29 | /**
30 | * Load and show the dialog
31 | */
32 | PhotoSelector.prototype.show = function () {
33 | this.$dialog.one('complete.oc.popup', this.proxy(this.onPopupShown));
34 | this.$dialog.popup({
35 | size: 'large',
36 | extraData: {album: this.options.album },
37 | handler: this.options.alias + '::onDialogOpen'
38 | });
39 | };
40 |
41 |
42 | /**
43 | * Callback when the popup is loaded and shown
44 | *
45 | * @param event
46 | * @param element
47 | * @param popup
48 | */
49 | PhotoSelector.prototype.onPopupShown = function (event, element, popup) {
50 | this.$dialog = popup;
51 | // bind clicks for album thumb and title links
52 | if (this.options.album) {
53 | this.bindPhotosListHandlers();
54 | } else {
55 | $('#albumsList .album-link', popup).one('click', this.proxy(this.onAlbumClicked));
56 | }
57 | $('div.photo-selection-dialog').find('button.btn-insert').click(this.proxy(this.onInsertClicked));
58 | };
59 |
60 |
61 | /**
62 | * Album clicked callback
63 | * @param event
64 | */
65 | PhotoSelector.prototype.onAlbumClicked = function (event) {
66 | var link_id = $(event.currentTarget).data('request-data');
67 | var selector = this;
68 | $.request('onAlbumLoad', {
69 | data: {id: link_id},
70 | update: {photos: '#listContainer'},
71 | loading: $.oc.stripeLoadIndicator,
72 | success: function (data) {
73 | this.success(data);
74 | selector.bindPhotosListHandlers();
75 | }
76 | });
77 | };
78 |
79 |
80 | /**
81 | * Bind event handlers for photos list
82 | */
83 | PhotoSelector.prototype.bindPhotosListHandlers = function () {
84 | // bind photo link click and double click events
85 | $('#photosList').find('a.photo-link').click(this.proxy(this.onPhotoSelected));
86 | $('#photosList').find('a.photo-link').dblclick(this.proxy(this.onPhotoDoubleClicked));
87 | // bind back to albums click event
88 | $('#photosList').find('a.back-to-albums').one('click', this.proxy(this.onBackToAlbums));
89 | };
90 |
91 |
92 | /**
93 | *
94 | * Photo clicked callback
95 | *
96 | * @param event
97 | */
98 | PhotoSelector.prototype.onPhotoSelected = function (event) {
99 | // remove old selected classes
100 | $('#photosList').find('a.selected').removeClass('selected');
101 |
102 | // add new selected classes
103 | var wrapper = $(event.currentTarget).parents('.photo-links-wrapper');
104 | wrapper.find('a.photo-link').addClass('selected');
105 | };
106 |
107 |
108 | /**
109 | *
110 | * Back to albums clicked callback
111 | *
112 | * @param event
113 | */
114 | PhotoSelector.prototype.onBackToAlbums = function (event) {
115 | var selector = this;
116 | $.request('onAlbumListLoad', {
117 | 'update': { albums: '#listContainer'},
118 | loading: $.oc.stripeLoadIndicator,
119 | success: function (data) {
120 | this.success(data);
121 | $('#albumsList').find('.album-link').one('click', selector.proxy(selector.onAlbumClicked));
122 | }
123 | });
124 | };
125 |
126 |
127 | /**
128 | * Photo insert button callback
129 | *
130 | * @param event
131 | */
132 | PhotoSelector.prototype.onInsertClicked = function (event) {
133 | var selected = $('#photosList').find('a.selected').first();
134 | if (!selected.length) {
135 | // FIXME Localize when it is supported
136 | alert('You have to select a photo first. Click on the photo, then click "Insert". Or just double-click the photo.');
137 | } else {
138 | var code = selected.data('request-data');
139 | var album = $('#photosList').data('request-data');
140 | this.options.onInsert.call(this, code, album);
141 | }
142 | };
143 |
144 |
145 | /**
146 | *
147 | * Double click callback
148 | *
149 | * @param event
150 | */
151 | PhotoSelector.prototype.onPhotoDoubleClicked = function (event) {
152 | // select the photo and insert it
153 | var link = $(event.currentTarget);
154 | link.trigger('click');
155 | $('div.photo-selection-dialog').find('button.btn-insert').trigger('click');
156 | };
157 |
158 |
159 | /**
160 | * Hide popup
161 | */
162 | PhotoSelector.prototype.hide = function () {
163 | if (this.$dialog) {
164 | this.$dialog.trigger('close.oc.popup');
165 | }
166 | };
167 |
168 |
169 | /**
170 | * Default options
171 | */
172 | PhotoSelector.DEFAULTS = {
173 | alias: undefined,
174 | album: 0,
175 | onInsert: undefined
176 | };
177 |
178 | $.oc.photoselector.popup = PhotoSelector;
179 |
180 | } (window.jQuery);
181 |
--------------------------------------------------------------------------------
/widgets/photoselector/partials/_albums.htm:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/widgets/photoselector/partials/_body.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 | = $this->makePartial('albums') ?>
10 |
11 | = $this->makePartial('photos') ?>
12 |
13 |
= e(trans('graker.photoalbums::lang.errors.no_albums')) ?>
14 |
15 |
16 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/widgets/photoselector/partials/_photos.htm:
--------------------------------------------------------------------------------
1 |
2 |
= $album->title; ?>
3 | photos as $photo) : ?>
4 |
22 |
23 |
26 |
27 |
--------------------------------------------------------------------------------