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.

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:
- make support downloadable files;
- make panels for displaying images; to provide minimal functionality for selecting images.
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.
- function preview ( )
- {
- $ this -> model_instance -> recursive = 0 ;
- // get the id of selected items:
- if ( ! empty ( $ this -> params [ 'form' ] [ 'selected' ] ) )
- {
- $ selected = $ this -> params [ 'form' ] [ 'selected' ] ;
- $ selected_ids = array ( 'id' => $ selected ) ;
- $ conditions = array ( "NOT" => $ selected_ids ) ;
- $ this -> set ( 'allselected' , $ this -> model_instance -> find ( 'all' , array ( 'conditions' => $ selected_ids ) ) ) ;
- }
- else
- {
- $ conditions = array ( ) ;
- $ this -> set ( 'allselected' , array ( ) ) ;
- }
- $ data = $ this -> paginate ( $ conditions ) ;
- $ this -> set ( 'allphotos' , $ data ) ;
- $ this -> set ( 'modelClass' , $ this -> modelClass ) ;
- // Point that we are using. Plugin .ctp for rendering
- $ this -> plugin = 'image_select' ;
- $ this -> render ( false , null , '/ image_selects / preview' ) ;
- }
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:
- $ ( document ) . ready ( function ( )
- {
- $ ( "#leftimgs> div [selected]" ) . click ( function ( event ) { toggle_img ( this ) ; } ) ;
- }
- function toggle_img ( div )
- {
- var isselected = div. getAttribute ( 'selected' ) == 'selected' ;
- if ( isselected )
- {
- div. style . backgroundColor = " ;
- div. childNodes [ 4 ] . childNodes [ 0 ] . checked = false ;
- div. setAttribute ( 'selected' , '' ) ;
- }
- else
- {
- div. style . backgroundColor = '# 3961af' ;
- div. childNodes [ 4 ] . childNodes [ 0 ] . checked = true ;
- div. setAttribute ( 'selected' , 'selected' ) ;
- }
- }
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):
- <? php
- class Photo extends AppModel {
- var $ name = 'Photo' ;
- var $ actsAs = array (
- 'ImageSelect.ImageSelect' => array (
- 'filename' => array (
- 'dir' => 'uploads' ,
- 'create_directory' => true
- 'generateName' => true
- 'maxFiles' => 5 ,
- 'useTable' => true
- 'thumbsizes' => array (
- 'my320' => array ( 'width' => 150 , 'height' => 150 ) ,
- ) ,
- )
- )
- ) ;
- }
- ?>
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:
- function loadPiece ( href , divName , data )
- {
- $ ( divName ) . load ( href , data , function ( )
- {
- var divPaginationLinks = divName + "#pagination a" ;
- $ ( divPaginationLinks ) . click ( function ( )
- {
- var thisHref = $ ( this ) . attr ( "href" ) ;
- loadPiece ( thisHref , divName , data ) ;
- return false ;
- } ) ;
- } ) ;
- }
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 .