📜 ⬆️ ⬇️

Selecting images is simple and effective.

Good day. Consider the following application functionality: adding an image to the text. Images are not embedded in the text itself (as, for example, in Wikipedia), but exist separately. Text can have one or more images. I wanted to make the binding procedure as user-friendly as possible.
The choice fell on the presentation of data using two areas: on the left are all the images available for selection, on the right are the selected ones. The user can select images using both the mouse and additional buttons.
Plugin example


Prerequisites


The rest of this article is about the CakePHP framework. I assume that the reader is familiar with it and such words as “controller”, “behavior”, “presentation” (view) do not frighten him. Getting to know MeioUpload will be a plus.

The full source code for the plugin is on GitHub . Here I will only talk about the main points and use.
')

Why plugin?


CakePHP plugins make it easy to add functionality to existing code. The plugin contains in its depths everything necessary for its work: controllers, data models, CSS rules, files with javascript functions, etc. An application can use a plugin through inheritance. My plugin consists of an ImageSelects controller, ImageUpload behavior, a preview view, and additional CSS, javascript files.

The implementation of the plugin can be divided into several subtasks:

A separate item is the use of the plugin. The idea is that the controller associated with the table in the database is inherited from the plugin. This controller is then used in the view of the other controller via AJAX .

File upload


To upload files, I modified the behavior of MeioUpload . My ImageUpload behavior is inherited from MeioUpload and makes some changes to it. MeioUpload stores all downloaded files in one folder. I entered the maxFiles parameter, which defines the maximum number of files in one directory. The folder structure is simple: <base_dir> / <i>, where base_dir is the base directory and i is the sequence number. The numbering starts from 1. In each folder with a number, an additional folder is created to store thumbnails.

Unlike MeioUpload , which uses the original file name, I generate a unique file name.
$ new_filename = md5 ( uniqid ( rand ( ) , true ) ) ;


Since my behavior is inherited from MeioUpload , all settings applicable to MeioUpload can be used with ImageUpload . Using them, you can set the maximum size of the uploaded file, permissible file types, thumbnail sizes, etc.

The file information is recorded in the database, as well as the relative path to the file, for example, “uploads / 1”. In the future, I plan to record a relative path to the image thumbnail, which may look like “uploads / 1 / thumb320”.

Image selection


To select images using the controller ImageSelects . It consists of one method - preview . As parameters, an array of identifiers of selected images can be passed to this method. This is needed when the user wants to change an already existing set of linked images.

  1. function preview ( )
  2. {
  3. $ this -> model_instance -> recursive = 0 ;
  4. // get the id of selected items:
  5. if ( ! empty ( $ this -> params [ 'form' ] [ 'selected' ] ) )
  6. {
  7. $ selected = $ this -> params [ 'form' ] [ 'selected' ] ;
  8. $ selected_ids = array ( 'id' => $ selected ) ;
  9. $ conditions = array ( "NOT" => $ selected_ids ) ;
  10. $ this -> set ( 'allselected' , $ this -> model_instance -> find ( 'all' , array ( 'conditions' => $ selected_ids ) ) ) ;
  11. }
  12. else
  13. {
  14. $ conditions = array ( ) ;
  15. $ this -> set ( 'allselected' , array ( ) ) ;
  16. }
  17. $ data = $ this -> paginate ( $ conditions ) ;
  18. $ this -> set ( 'allphotos' , $ data ) ;
  19. $ this -> set ( 'modelClass' , $ this -> modelClass ) ;
  20. // Point that we are using. Plugin .ctp for rendering
  21. $ this -> plugin = 'image_select' ;
  22. $ this -> render ( false , null , '/ image_selects / preview' ) ;
  23. }

The function returns two arrays allphotos and allselected , and also slightly corrects the output mechanism. You need to display the page through the plug-in view.

The functionality of the choice itself is implemented using jQuery . All available images are in the container with the ID leftimgs . Each picture is inside a container that has a selected attribute. Valid attribute values ​​are the selected string and the empty string. With jQuery, you can easily find all marked images:
$ ( "#leftimgs> div [selected = 'selected']" )


Already selected images are in the container with the identifier rightimgs . You can work with them similarly to the pictures from the leftimgs container.

Code marking an image by a single mouse click:
  1. $ ( document ) . ready ( function ( )
  2. {
  3. $ ( "#leftimgs> div [selected]" ) . click ( function ( event ) { toggle_img ( this ) ; } ) ;
  4. }
  5. function toggle_img ( div )
  6. {
  7. var isselected = div. getAttribute ( 'selected' ) == 'selected' ;
  8. if ( isselected )
  9. {
  10. div. style . backgroundColor = " ;
  11. div. childNodes [ 4 ] . childNodes [ 0 ] . checked = false ;
  12. div. setAttribute ( 'selected' , '' ) ;
  13. }
  14. else
  15. {
  16. div. style . backgroundColor = '# 3961af' ;
  17. div. childNodes [ 4 ] . childNodes [ 0 ] . checked = true ;
  18. div. setAttribute ( 'selected' , 'selected' ) ;
  19. }
  20. }

As you can see from the code, I set the background color to manual. The correct change is the CSS class of the object.

Using


To use all of this, we need to create a table in the database and everything we need for it: the controller, the data model, and the views. The path to the table is called photos , the corresponding controller is PhotosController , and the model is Photo . We also need another table and everything related to it. Let its name be cities , controller CitiesController , etc. as is customary in CakePHP .

The source code is placed in the app / plugins / image_select folder.

Use behavior


Behavior is used in the PhotosController data model of the controller (photo.php file):
  1. <? php
  2. class Photo extends AppModel {
  3. var $ name = 'Photo' ;
  4. var $ actsAs = array (
  5. 'ImageSelect.ImageSelect' => array (
  6. 'filename' => array (
  7. 'dir' => 'uploads' ,
  8. 'create_directory' => true
  9. 'generateName' => true
  10. 'maxFiles' => 5 ,
  11. 'useTable' => true
  12. 'thumbsizes' => array (
  13. 'my320' => array ( 'width' => 150 , 'height' => 150 ) ,
  14. ) ,
  15. )
  16. )
  17. ) ;
  18. }
  19. ?>

On the page for adding photos we write:
<? php
echo $ form -> create ( 'Photo' , array ( 'type' => 'file' ) ) ;
...
echo $ form -> input ( 'Photo.filename' , array ( 'type' => 'file' ) ) ;
?>

That's all. Uploading pictures ready!

Controller use


The created controller PhotosController inherits ImageSelectsController :
App :: import ( 'Controller' , 'ImageSelect.ImageSelects' ) ;
class PhotosController extends ImageSelectsController
{
}

Thus, PhotosController accesses the preview method from ImageSelectsController .

Binding image selection to another controller


Remember that we have created CitiesControlles . On the add new city page (app / views / cities / add.ctp) we want to add a selection of pictures. In the add.ctp file you need to connect CSS and Javascript from the plugin:
<? php
echo $ javascript -> link ( '/image_select/js/image_upload.js' , false ) ; // load js in header
echo $ html -> css ( '/image_select/css/image_select.css' , false ) ;
?>

The panels and buttons will be stored in a container with the imageList id :
< div id = "imageList" > < / div >

Data from the preview representation of the ImageSelectsController controller is loaded into this container using AJAX . For loading, the loadPiece function is responsible , which is located in the file “app / plugins / image_select / vendors / js / image_upload.js”. Here she is:
  1. function loadPiece ( href , divName , data )
  2. {
  3. $ ( divName ) . load ( href , data , function ( )
  4. {
  5. var divPaginationLinks = divName + "#pagination a" ;
  6. $ ( divPaginationLinks ) . click ( function ( )
  7. {
  8. var thisHref = $ ( this ) . attr ( "href" ) ;
  9. loadPiece ( thisHref , divName , data ) ;
  10. return false ;
  11. } ) ;
  12. } ) ;
  13. }


Let's go back to the file app / views / cities / add.ctp. We need to add another call to the loadPiece function:
< script type = "text / javascript" >
var selected = new Array ( ) ;
// selected [0] = 2; // possible id for the selected images
// selected [1] = 38;
var data = new Object ( ) ;
data. selected = selected ;
var reload_url = "<? php echo $ html-> url (array ('controller' => 'photos', 'action' => 'preview'));?>" ;
$ ( document ) . ready ( function ( )
{
loadPiece ( reload_url , "#imageList" , data ) ;
} ) ;
</ script >


This completes the installation. All is ready! On the shoulders of the developer will only get the identifiers of the selected images and save them in the database. Get a list of selected images using jQuery .

Source: https://habr.com/ru/post/90289/


All Articles