jquery-attachments

This plugin provides the UI of an attachment of the files that are in the one repository.

Usage no npm install needed!

<script type="module">
  import jqueryAttachments from 'https://cdn.skypack.dev/jquery-attachments';
</script>

README

jQuery Attachments


This plugin provides the UI of an attachment of the files that are in the one repository.

  1. Simple usage
  2. Options
  3. Methods
  4. Events
  5. Data schemes
  6. Templates
  7. Translate
  8. Dialog

Simple usage

The minimum configuration requires that you had to specify the urls of server handlers.

<form>
    ...
    <label for="attachments">Attachments:</label>
    <input type="text" name="attachments" id="attachments"/>
    ...
</form>
<script>
    $(document).ready(function () {
        $('#attachments').attachments({
            url: {
                find: 'http://your_server/you_handler_find',
                list: 'http://your_server/you_handler_list',
                upload: 'http://your_server/you_handler_upload',
                delete: 'http://your_server/you_handler_delete'
            },
        });
    });
</script>

Options

  • {} url - Required. Object with urls for server handlers. At current moment, objects have 4 properties:

    find - url of find handler. It is used for find uploaded files on server. Parameters may be string or array strings.
    list - url of list handler. It is used for load a list of uploaded files from server. Parameters "offset" and "limit" are int. Others parameters may be string or array strings.
    upload - url of upload handler. It is used for upload files to server.
    delete - url of delete list handler. It is used for delete uploaded files on server.

    See params for requests in data schemes (requests).

  • null|string[] extensions - Default null. Allowed extensions for upload and attachments.

  • null|int maxUploadSize - Default null. Max size (kb) of file which allow to upload on server.

  • null|int maxSelected - Default null. Max selected files for attachments.

  • int listLimit - Default 25. Limit of page size for load from list handler.

  • null|int animationSpeed - Default 500. Speed for jQuery animation.

  • string valueDelimiter - Default ', '. Delimiter between files id in field value.

  • {} schemes - Default standard schemes. Object for setting data schemes. See details in data schemes.

  • {} views - Default standard templates. Object with templates for UI. See details in templates

  • null|{} translate - Default null. Object for translated plugin UI. See details in translate

  • {} dialog - Default standard Dialog. Object for dialog to user to confirm actions of plugin and inform him. See details in dialog.

Methods

  • array allReceivedFiles() - get all files which loaded from server on current moment.
  • array selectedFiles() - get all selected files.
  • jQuery selectFile(string id) - select file by id.
  • jQuery deSelectFile(string id) - deselect file by id.
  • string getUID() - get unique id for current field

Events

  • attachments.change(e, files) Event triggered when value is changed
    Params:
    jQuery.Event e - object jQuery Event
    array files - array with objects of file fields

Data schemes

Scheme used to match the fields of the external data (from server) to the fields of internal data. There are two types of scheme: request and response. In the schemes the key is the internal name of the field, and the value is the name of an external field. Conceptual scheme example:

entity = {
    id:'id_name_from_server',
    field: 'field_name_from_server'
};

Plugin uses the following schemes:

  • requests.find - scheme for "find" of request to server. Scheme uses following fields: id, name, extension.

  • requests.list - scheme for "list" of request to server. Scheme uses following fields: id, name, extension, offset, limit.

  • requests.upload - scheme for "upload" of request to server. Scheme uses following fields: file.

  • requests.delete - scheme for "delete" of request to server. Scheme uses following fields: id.

  • responses.file - scheme for convert object with file fields to internal File model. Scheme using in responses for "find", "list" and "upload" of requests (see default config schemes). Scheme uses following fields: id, name, extension. size, url, preview_url, created_at, updated_at.

  • responses.list - scheme for response from server at "list" of request. Scheme uses following fields: total, files.

  • responses.upload - scheme for response from server at "upload" of request. Scheme uses following fields: files.

  • responses.find - scheme for response from server at "upload" of request. Scheme uses following fields: files.

Default config schemes

  requests:
    find:
      id: 'id'
      name: 'name'
      extension: 'extension'
    list:
      id: 'id'
      name: 'name'
      extension: 'extension'
      offset: 'offset'
      limit: 'limit'
    upload:
      file: 'file' # array with File from FormData
    delete:
      id: 'id'
  responses:
    file:
      id: 'id'
      name: 'name'
      extension: 'extension'
      size: 'size'
      url: 'url'
      preview_url: 'preview_url'
      created_at: 'created_at'
      updated_at: 'updated_at'
    list:
      total: 'total'
      files: 'files' # value should be array of objects with scheme responses.file
    upload:
      files: 'files' # value should be array of objects with scheme responses.file
    find:
      files: 'files' # value should be array of objects with scheme responses.file

Example

For example, the files on server are stored in the table with the following fields:

File (
    primaryID,
    file_name,
    file_extension,
    file_size,
    download_url,
    preview_url,
    created_date,
    updated_date
)

Then schemes configuration can be:

$('#selectorField').attachments({
    ...
    schemes: {
        requests: {
            find: {
                id: 'primaryID',
                name: 'file_name',
                extension: 'file_extension'
            },
            list: {
                id: 'primaryID',
                name: 'file_name',
                extension: 'file_extension',
                offset: 'offset',
                limit: 'limit'
            },
            upload: {
                file: 'file'
            },
            "delete": {
                id: 'primaryID'
            }
        },
        responses: {
            file: {
                id: 'primaryID',
                name: 'file_name',
                extension: 'file_extension',
                size: 'file_size',
                url: 'download_url',
                preview_url: 'preview_url',
                created_at: 'created_date',
                updated_at: 'updated_date'
            },
            list: {
                total: 'total',
                files: 'files'
            },
            upload: {
                files: 'files'
            },
            find: {
                files: 'files'
            }
        }
    }
    ...
});

Templates

You can use custom templates for more full integrate plugin in your UI. Plugin uses LoDash library for templating and you must observe it syntax when creating a your interfaces.

Using example

<script>
    $(document).ready(function () {
        var templateString = '<div data-id="<%= file.getField(\'id\')%>" data-selected="<%= (selected ? \'true\' : \'false\')%>" jq-attachments-file>......</div>';
        $('#attachments').attachments({
            ...
            view: {
                field: {selector: '#fieldTemplate'},
                selector: {selector: '#selectorTemplate'},
                selectorFile: templateString,
            },
            ...
        });
    });
</script>

field template

Start interface for attached files.

Input variables

  • Translate translate - object for getting of translated text.
  • File[] files - selected files.

Required attributes

  • [jq-attachments-selected-files] - main container for selected files.
  • [jq-attachments-selected-files-file] - container for selected file.
  • [data-id="{FILE_ID}"] - file id. Should be have value = file id and be attribute for main container for selected file ([jq-attachments-selected-files-file]).
  • [jq-attachments-selected-files-file-remove] - attribute of element that is a deselect file (by click event). Should be inside [jq-attachments-selected-files-file].
  • [jq-attachments-add] - attribute of element that is opening selection file UI (by click event).

Example

<div class="jq-attachments-selected <%= (files.length == 0) ? 'empty' : '' %>">
    <div class="jq-attachments-selected-empty"><%= translate.t('No attached files.')%></div>
    <ul class="jq-attachments-selected-files" jq-attachments-selected-files>
        <% for (var i = 0, l = files.length; i<l; i++) {%>
        <% file = files[i]%>
        <li class="jq-attachments-selected-file" data-id="<%= file.getField('id')%>" jq-attachments-selected-files-file>
            <a class="jq-attachments-selected-file-load" href="<%= file.getField('url')%>" target="_blank"><%= file.getField('name')%></a>
            <span class="jq-attachments-selected-file-remove" jq-attachments-selected-files-file-remove>+</span>
        </li>
        <%}%>
    </ul>
    <button class="jq-attachments-add" jq-attachments-add><%= translate.t('Add files')%></button>
</div>

selector template

Window for attachments and upload files (Selector).

Input variables

  • Translate translate - object for getting of translated text.
  • string uid - unique window id.
  • string accept - accepted extensions for upload.

Required attributes

  • [jq-attachments-window] - main container for window.
  • [jq-attachments-window-close] - attribute of element which had to close window by click (click event).
  • [uid="{FILE_ID}"] - unique window id. Should be have value = uid and be attribute for main container.
  • [jq-attachments-upload] - input field (type="file") for upload.
  • [jq-attachments-upload-send] - attribute of element that is a button for start upload (by click event).
  • [jq-attachments-progress] - attribute of element which show loading process.
  • [jq-attachments-files] - attribute of element which contain loaded files.
  • [jq-attachments-files-more] - attribute of element that is a button for load more files from server (by click event).
  • [jq-attachments-apply] - attribute of element that is a button for apply select files.

Example

<section uid="<%= uid%>" class="jq-attachments-window" jq-attachments-window>
    <div class="jq-attachments-window-content">
        <header class="jq-attachments-window-content-header">
            <form enctype="multipart/form-data">
                <div class="jq-attachments-upload">
                    <label>
                        <input type="file" name="file[]" jq-attachments-upload multiple accept="<%= accept%>"/>
                        <span data-role="upload-text"><%= translate.t('Select files')%></span>
                    </label>
                </div>
                <input type="submit" class="jq-attachments-upload-send" value="upload" jq-attachments-upload-send
                       disabled/>
            </form>
            <div class="jq-attachments-progress" title="<%= translate.t('Wait...')%>" jq-attachments-progress>
                <div></div>
            </div>
            <span class="jq-attachments-window-close" jq-attachments-window-close>+</span>
        </header>
        <main class="jq-attachments-window-content-main">
            <div class="jq-attachments-files">
                <div jq-attachments-files>
                </div>
                <input type="submit" value="<%= translate.t('Load more files')%>" class="jq-attachments-files-more"
                       jq-attachments-files-more/>
            </div>
        </main>
        <footer class="jq-attachments-window-content-footer">
            <input type="submit" value="<%= translate.t('Save')%>" class="jq-attachments-apply" jq-attachments-apply/>
            <input type="submit" value="<%= translate.t('Cancel')%>" class="jq-attachments-cancel"
                   jq-attachments-window-close/>
        </footer>
    </div>
    <div class="jq-attachments-window-bg" jq-attachments-window-close></div>
</section>

<%
//script for  UI logic (custom file input)
var interval = null;
var renderUpload = function () {
    var fieldFile = document.querySelector('[uid="' + uid + '"] [jq-attachments-upload]');
    if (fieldFile) {
        clearInterval(interval);
        var uploadSendButton = document.querySelector('[uid="' + uid + '"] [jq-attachments-upload-send]');
        var uploadText = document.querySelector('[uid="' + uid + '"] [data-role="upload-text"]');
        fieldFile.onchange = function () {
            var countFiles = this.files.length;
            var message;
            if (countFiles) {
                message = translate.t('Selected {countFiles} files', {countFiles: countFiles});
            } else {
                message = translate.t('Select files');
            }
            uploadText.innerHTML = message;
            uploadSendButton.disabled = !countFiles;
        };
    }
};

interval = setInterval(renderUpload, 100);
%>

selectorFile template

File element in Selector.

Input variables

  • Translate translate - object for getting of translated text.
  • File file - file which need show.
  • bool selected - status of selected file for attach.

Required attributes

  • [jq-attachments-file] - main container for file.
  • [data-id="{FILE_ID}"] - file id. Should be have value = file id and be attribute for main container.
  • [data-selected="true|false"] - status of selected file for attach. Should be have value = true|false and be attribute for main container.
  • [jq-attachments-file-select] - attribute of element that is a file selection interface for attachments (by click event).
  • [jq-attachments-file-delete] - attribute of element that is a file deletion interface (by click event).

Example

<div class="jq-attachments-file" data-id="<%= file.getField('id')%>" data-selected="<%= (selected ? 'true' : 'false')%>" jq-attachments-file>
    <input type="checkbox" jq-attachments-file-select<%= (selected ? ' checked' : '')%>/>
    <span class="jq-attachments-file-delete" jq-attachments-file-delete></span>
    <img src="<%= file.getField('preview_url')%>" alt="<%= file.getField('name')%>"/>
    <a href="<%= file.getField('url')%>" target="_blank" title="<%= file.getField('name')%>" class="jq-attachments-file-link"><%= file.getField('name')%></a>
</div>

Translate

For translate plugin on custom language, you should set map object with dictionary to option "translate". In that the object key should be original phrase and value should be translated phrase. For example:

translate: {
    'original phrase': 'translate phrase',
},

The following phrases are used in the plugin:

  • Are you sure deselect file?
  • Sorry, you can select not more than {maxSelected} file(s).
  • Are you sure want to delete the file?
  • File "{name}" is not valid. Error: "{error}"
  • File size should be <= {size} kb.
  • Invalid file extension. Allowed the following extensions: {extensions}.
  • No attached files.
  • Add files
  • Select files
  • Wait...
  • Load more files
  • Save
  • Cancel
  • Selected {countFiles} files

Example

<script>
    $(document).ready(function () {
        $('#attachments').attachments({
            //...
            translate: {
                'You are sure deselect file?': 'Вы действительно хотите открепить файл?',
                'Sorry, you can select not more than {maxSelected} file(s).': 'Извините, вы можете выбрать не более {maxSelected} файлов.',
                'Are you sure want to delete the file?': 'Вы действительно хотите удалить данный файл?',
                'File "{name}" is not valid. Error: "{error}"': 'Файл "{name}" не прошел валидацию. ошибка: "{error}".',
                'File size should be <= {size} kb.': 'Размер файла не должен превышать {size}} кб.',
                'Invalid file extension. Allowed the following extensions: {extensions}.': 'Некорректнове расширение. Допустимы следующие расширения: {extensions}.',
                'No attached files.': 'Прикрепленных файлов нет.',
                'Add files': 'Добавить файлы',
                'Select files': 'Выбрать файлы',
                'Wait...': 'Подождите',
                'Load more files': 'Загрузить больше файлов',
                'Save': 'Сохранить',
                'Cancel': 'Отменить',
                'Selected {countFiles} files': 'Выбрано {countFiles} файла(ов)'
            }
            //...
        });
    });
</script>

Dialog

You can used custom dialogs. To do this, you need to set in option "dialog" object that implements the following interface:

interface Dialog {
    void alert(string message);
    bool confirm(string message);
}

Example

<script>
    $(document).ready(function () {
        $('#attachments').attachments({
            //...
            dialog: {
                alert: function (message) {
                    alert(message);
                },
                confirm: function (message) {
                    return confirm(message);
                }
            }
            //...
        });
    });
</script>