RomanL 6 سال پیش
والد
کامیت
8db9eeb26e

+ 23 - 0
modules/boonex/media/classes/BxMediaConfig.php

@@ -0,0 +1,23 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    MediaManager MediaManager
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+bx_import('BxDolModuleConfig');
+
+class BxMediaConfig extends BxDolModuleConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+        $this->CNF = array ();
+    }
+}
+
+/** @} */

+ 19 - 0
modules/boonex/media/classes/BxMediaDb.php

@@ -0,0 +1,19 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+* Copyright (c) UNA, Inc - https://una.io
+* MIT License - https://opensource.org/licenses/MIT
+*
+* @defgroup    MediaManager MediaManager
+* @ingroup     UnaModules
+*
+* @{
+*/
+
+/*
+ * Module database queries
+ */
+class BxMediaDb extends BxDolModuleDb
+{
+}
+
+/** @} */

+ 75 - 0
modules/boonex/media/classes/BxMediaModule.php

@@ -0,0 +1,75 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+* Copyright (c) UNA, Inc - https://una.io
+* MIT License - https://opensource.org/licenses/MIT
+*
+* @defgroup    MediaManager MediaManager
+* @ingroup     UnaModules
+*
+* @{
+*/
+
+/**for 
+ * MediaManager module
+ */     
+class BxMediaModule extends BxDolModule
+{         
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+    
+     /**
+    * Action methods
+    */
+          
+    public function actionCopyFile()
+    {
+       
+        $sFileName = bx_get('FileName');
+        $sStorageObject = bx_get('StorageObject');
+        $sUniqId = bx_get('UniqId'); 
+        $sUploaderInstanceName = bx_get('UploaderInstanceName');
+        $bPrivate = bx_get('isPrivate');
+        $iContentId = bx_get('ContentId');
+        $sUploaderObject = "bx_media_uploader";
+        $oUploader = BxDolUploader::getObjectInstance($sUploaderObject, $sStorageObject, $sUniqId);
+        $isMultiple = (bool)bx_get('isMultiple');
+        if ($sStorageObject && $sFileName){
+            $iProfileId = bx_get_logged_profile_id();
+            $oStorage = BxDolStorage::getObjectInstance($sStorageObject);
+            if (!$isMultiple){
+                $oUploader->deleteGhostsForProfile($iProfileId, $iContentId && $oUploader);
+            }
+            $iId = $oStorage->storeFileFromUrl($sFileName, $bPrivate, $iProfileId, $iContentId);
+            if (!$iId)
+                $oUploader->appendUploadErrorMessage(_t('_sys_uploader_err_msg', $sFileName, $oStorage->getErrorString()));
+            echo '<script>window.parent.' . $sUploaderInstanceName . '.onUploadCompleted(\'' . bx_js_string($oUploader->getUploadErrorMessages(), BX_ESCAPE_STR_APOS) . '\');</script>';
+        }
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_media Anonymous Follow
+     * @subsection bx_media-page_blocks Page Blocks
+     * @subsubsection bx_media-include_js include_js
+     * 
+     * @code bx_srv('bx_media', 'include_js', [...]); @endcode
+     * 
+     * Add js to injection in head
+     *
+     * @param $aParams an array with search params.
+     * @return void
+     * 
+     * @see BxMediaModule::serviceIncludeJs
+     */
+    /** 
+     * @ref bx_media-include_js "include_js"
+     */
+    public function serviceIncludeJs ()
+    {
+        return $this->_oTemplate->parseHtmlByName('MediaUploaderSettings.js', array());
+    }
+}
+
+/** @} */

+ 20 - 0
modules/boonex/media/classes/BxMediaTemplate.php

@@ -0,0 +1,20 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    MediaManager MediaManager
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+class BxMediaTemplate extends BxDolModuleTemplate
+{
+    function __construct(&$oConfig, &$oDb)
+    {
+        $this->MODULE = 'bx_media';
+        parent::__construct($oConfig, $oDb);
+    }
+}
+
+/** @} */

+ 130 - 0
modules/boonex/media/classes/BxMediaUploader.php

@@ -0,0 +1,130 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    MediaManager MediaManager
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxMediaUploader extends BxDolUploader
+{
+    protected $_sIframeId;
+    protected $_sUploaderFormTemplate = 'media_uploader_form.html';
+    protected $_oModule;
+
+    function __construct ($aObject, $sStorageObject, $sUniqId, $oTemplate)
+    {
+        $this->_oModule = BxDolModule::getInstance('bx_media');
+        
+        parent::__construct($aObject, $sStorageObject, $sUniqId, $oTemplate);
+        $this->_sIframeId = 'bx-form-input-files-' . $sUniqId . '-iframe';
+        $this->_sButtonTemplate = 'media_uploader_button.html';
+    }
+
+    /**
+     * Get uploader button title
+     */
+    public function getUploaderButtonTitle($mixed = false)
+    {
+        return _t('_bx_media_uploader_button_title');
+    }
+    
+    /**
+     * Show uploader form.
+     * @return HTML string
+     */
+    public function getUploaderForm($isMultiple = true, $iContentId = false, $isPrivate = true)
+    {
+        $aStorageData = array();
+        $aGhosts = BxDolStorageQuery::getAllGhosts(array('profile_id' => bx_get_logged_profile_id()));
+        foreach ($aGhosts as $k => $aGhost) {
+            $oStorage = BxDolStorage::getObjectInstance($aGhost['object']);
+            if ($oStorage){
+                $aStorageData[] = array('uploader_instance_name' => $this->getNameJsInstanceUploader(),'url' => $oStorage->getFileUrlById($aGhost['id']));
+            }
+        }
+        
+        $sAcceptedFiles = $this->getAcceptedFilesExtensions();
+        return $this->_oModule->_oTemplate->parseHtmlByName($this->_sUploaderFormTemplate, array(
+            'form_container_id' => $this->_sFormContainerId,
+            'errors_container_id' => $this->_sErrorsContainerId,
+            'uploader_instance_name' => $this->getNameJsInstanceUploader(),
+            'restrictions_text' => $this->getRestrictionsText(),
+            'iframe_id' => $this->_sIframeId,
+            'engine' => $this->_aObject['object'],
+            'storage_object' => $this->_sStorageObject,
+            'uniq_id' => $this->_sUniqId,
+            'multiple' => $isMultiple,
+            'filepond_multiple' => $isMultiple ? 'true' : 'false',
+            'content_id' => $iContentId,
+            'storage_private' => $isPrivate,
+            'accepted_files' => null === $sAcceptedFiles ? '' : 'accept="' . bx_js_string($sAcceptedFiles) . '"',
+            'bx_if:recent_files' => array(
+				'condition' => count($aStorageData) >0,
+				'content' => array(
+                    'bx_repeat:items' => $aStorageData,
+                    'item_count' => count($aStorageData)
+                )
+			),
+        ));
+    }
+    
+    /**
+     * Show uploader button.
+     * @return HTML string
+     */
+    public function getUploaderButton($mixedGhostTemplate, $isMultiple = true, $aParams = array(), $bDynamic = false)
+    {
+        $sJsValue = '';
+        if (is_array($mixedGhostTemplate)) {
+            $sJsValue = "{\n";
+            foreach ($mixedGhostTemplate as $iFileId => $s) {
+                $sJsValue .= $iFileId . ':' . "'" . bx_js_string($s, BX_ESCAPE_STR_APOS) . "',\n";
+            }
+            $sJsValue = substr($sJsValue, 0, -2);
+            $sJsValue .= "}\n";
+        } else {
+            $sJsValue = "'" . bx_js_string($mixedGhostTemplate, BX_ESCAPE_STR_APOS) . "'";
+        }
+        $aParamsDefault = array (
+            'uploader_instance_name' => $this->getNameJsInstanceUploader(),
+            'engine' => $this->_aObject['object'],
+            'storage_object' => $this->_sStorageObject,
+            'images_transcoder' => '',
+            'uniq_id' => $this->_sUniqId,
+            'template_ghost' => $sJsValue,
+            'multiple' => $isMultiple ? 1 : 0,
+            'storage_private' => isset($aParams['storage_private']) ? $aParams['storage_private'] : 1,
+            'action_url' => $this->_oModule->_oConfig->getBaseUri(),
+            'uploader_instance_name' => $this->getNameJsInstanceUploader(),
+        );
+        $aParams = array_merge($aParamsDefault, $aParams);
+        
+        $this->_oModule->_oTemplate->addJs(
+            array(
+                'BxMediaUploader.js',
+                BX_DIRECTORY_PATH_MODULES . 'boonex/media/plugins/filepond-master/dist/|filepond.min.js',
+                BX_DIRECTORY_PATH_MODULES . 'boonex/media/plugins/filepond-plugin-image-preview-master/dist/|filepond-plugin-image-preview.min.js',
+                BX_DIRECTORY_PATH_MODULES . 'boonex/media/plugins/filepond-plugin-media-preview-master/dist/|filepond-plugin-media-preview.min.js',
+                BX_DIRECTORY_PATH_MODULES . 'boonex/media/plugins/filepond-plugin-file-validate-type-master/dist/|filepond-plugin-file-validate-type.min.js',
+                BX_DIRECTORY_PATH_MODULES . 'boonex/media/plugins/filepond-plugin-image-edit-master/dist/|filepond-plugin-image-edit.min.js'
+            )
+        );
+        $this->_oModule->_oTemplate->addCss(
+            array(
+                'main.css',
+                BX_DIRECTORY_PATH_MODULES . 'boonex/media/plugins/filepond-master/dist/|filepond.min.css',
+                BX_DIRECTORY_PATH_MODULES . 'boonex/media/plugins/filepond-plugin-image-preview-master/dist/|filepond-plugin-image-preview.min.css',
+                BX_DIRECTORY_PATH_MODULES . 'boonex/media/plugins/filepond-plugin-media-preview-master/dist/|filepond-plugin-media-preview.min.css',
+                BX_DIRECTORY_PATH_MODULES . 'boonex/media/plugins/filepond-plugin-image-edit-master/dist/|filepond-plugin-image-edit.min.css',
+            )
+        );
+        return $this->addCssJs ($bDynamic) . $this->_oModule->_oTemplate->parseHtmlByName($this->_sButtonTemplate, $aParams);
+    }
+
+}
+
+/** @} */

+ 77 - 0
modules/boonex/media/install/config.php

@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    MediaManager MediaManager
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_media',
+    'title' => 'Media Manager',
+    'note' => 'Media Manager module.',
+    'version' => '11.0.1.DEV',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '10.0.x'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/media/',
+    'home_uri' => 'media',
+
+    'db_prefix' => 'bx_media_',
+    'class_prefix' => 'BxMedia',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'MediaManager',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 77 - 0
modules/boonex/media/install/installer.php

@@ -0,0 +1,77 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    MediaManager MediaManager
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxMediaInstaller extends BxBaseModTextInstaller
+{
+    protected $_oModule;
+    
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);   
+    }
+    
+    public function enable($aParams)
+    {
+        $aResult = parent::enable($aParams);
+        if($aResult['result'])
+            $this->_saveSettings();
+        return $aResult;
+    }
+    
+    public function disable($aParams)
+    {
+        $aResult = parent::disable($aParams);
+        if($aResult['result'])
+            $this->_restoreSettings();
+        return $aResult;
+    }
+    
+    private function _saveSettings()
+    {
+    	$this->oDb->query("INSERT INTO `bx_media_input_settings`(`input_id`, `value`, `values`) SELECT `id`, `value`, `values` FROM `sys_form_inputs` WHERE `type` = 'files'");
+        $aInputs = $this->oDb->getAll("SELECT `id`, `value`, `values` FROM `sys_form_inputs` WHERE `type` = 'files'");
+        foreach($aInputs as $aInput){
+            $aValue = array('bx_media_uploader');
+            $aValues = unserialize($aInput['values']);
+            $aValues['bx_media_uploader'] = '_bx_media_uploader_title';
+            
+            $aBindings = array(
+                'id' => $aInput['id'],
+                'value' => serialize($aValue),
+                'values' => serialize($aValues)
+            );
+            $sQuery = "UPDATE `sys_form_inputs` SET `value` = :value, `values`  = :values WHERE `id` = :id";
+            $this->oDb->query($sQuery, $aBindings);
+        }
+    }
+    
+    private function _restoreSettings()
+    {
+        $aInputs = $this->oDb->getAll("SELECT `id`, `input_id`, `value`, `values` FROM `bx_media_input_settings`");
+        foreach($aInputs as $aInput){
+            $aBindings = array(
+                'id' => $aInput['input_id'],
+                'value' => $aInput['value'],
+                'values' => $aInput['values']
+            );
+            $sQuery = "UPDATE `sys_form_inputs` SET `value` = :value, `values` = :values WHERE `id` = :id";
+            $this->oDb->query($sQuery, $aBindings);
+            
+            $sQuery = "DELETE FROM `bx_media_input_settings` WHERE `id` = :id";
+            $aBindings = array(
+                'id' => $aInput['id'],
+            );
+            $this->oDb->query($sQuery, $aBindings);
+        }
+    }
+}
+
+/** @} */

+ 35 - 0
modules/boonex/media/install/langs/en.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+  <string name="_bx_media"><![CDATA[Media Manager]]></string>
+  <string name="_bx_media_uploader_title"><![CDATA[Media Manager]]></string>
+  <string name="_bx_media_upload_file_title"><![CDATA[Upload file]]></string>
+  <string name="_bx_media_edit_file_title"><![CDATA[Edit file]]></string>
+  <string name="_bx_media_uploader_button_title"><![CDATA[Media Manager]]></string>
+  <string name="_bx_media_uploader_filepond_labelIdle"><![CDATA[Add file(s)]]></string>
+  <string name="_bx_media_uploader_filepond_labelInvalidField"><![CDATA[Field contains invalid files]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileWaitingForSize"><![CDATA[Waiting for size]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileSizeNotAvailable"><![CDATA[Size not available]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileCountSingular"><![CDATA[file in list]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileCountPlural"><![CDATA[files in list]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileLoading"><![CDATA[Loading]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileAdded"><![CDATA[Added]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileLoadError"><![CDATA[Error during load]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileRemoved"><![CDATA[Removed]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileRemoveError"><![CDATA[Error during remove]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileProcessing"><![CDATA[Upload complete]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileProcessingComplete"><![CDATA[Upload complete]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileProcessingAborted"><![CDATA[Upload cancelled]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileProcessingError"><![CDATA[Error during upload]]></string>
+  <string name="_bx_media_uploader_filepond_labelFileProcessingRevertError"><![CDATA[Error during revert]]></string>
+  <string name="_bx_media_uploader_filepond_labelTapToCancel"><![CDATA[tap to cancel]]></string>
+  <string name="_bx_media_uploader_filepond_labelTapToRetry"><![CDATA[tap to retry]]></string>
+  <string name="_bx_media_uploader_filepond_labelTapToUndo"><![CDATA[tap to undo]]></string>
+  <string name="_bx_media_uploader_filepond_labelButtonRemoveItem"><![CDATA[Remove]]></string>
+  <string name="_bx_media_uploader_filepond_labelButtonAbortItemLoad"><![CDATA[Abort]]></string>
+  <string name="_bx_media_uploader_filepond_labelButtonRetryItemLoad"><![CDATA[Retry]]></string>
+  <string name="_bx_media_uploader_filepond_labelButtonAbortItemProcessing"><![CDATA[Cancel]]></string>
+  <string name="_bx_media_uploader_filepond_labelButtonUndoItemProcessing"><![CDATA[Undo]]></string>
+  <string name="_bx_media_uploader_filepond_labelButtonRetryItemProcessing"><![CDATA[Retry]]></string>
+  <string name="_bx_media_uploader_filepond_labelButtonProcessItem"><![CDATA[Upload]]></string>
+  <string name="_bx_media_subheader_recent_files"><![CDATA[Recent media]]></string>
+</resources>

+ 4 - 0
modules/boonex/media/install/sql/disable.sql

@@ -0,0 +1,4 @@
+SET @sName = 'bx_media';
+
+-- INJECTION
+DELETE FROM `sys_injections` WHERE `name`= @sName;

+ 5 - 0
modules/boonex/media/install/sql/enable.sql

@@ -0,0 +1,5 @@
+SET @sName = 'bx_media';
+
+-- INJECTION
+INSERT INTO `sys_injections`(`name`, `page_index`, `key`, `type`, `data`, `replace`, `active`) VALUES
+(@sName, 0, 'injection_head', 'service', 'a:2:{s:6:"module";s:8:"bx_media";s:6:"method";s:10:"include_js";}', 0, 1);

+ 27 - 0
modules/boonex/media/install/sql/install.sql

@@ -0,0 +1,27 @@
+-- TABLE: PROFILES
+CREATE TABLE IF NOT EXISTS `bx_media_input_settings` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `input_id` int(10) unsigned NOT NULL,
+  `value` varchar(255) NOT NULL,
+  `values` text NOT NULL,
+  PRIMARY KEY (`id`)
+  );
+
+  -- UPLOADERS
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_media_uploader', 1, 'BxMediaUploader', 'modules/boonex/media/classes/BxMediaUploader.php');
+
+-- STUDIO: page & widget
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, @sName, '_bx_media', '_bx_media', 'bx_media@modules/boonex/media/|std-icon.svg');
+
+SET @iPageId = LAST_INSERT_ID();
+
+INSERT INTO `sys_std_widgets` (`page_id`, `module`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`, `bookmark`) 
+VALUES(@iPageId, @sName, '{url_studio}module.php?name=bx_media', '', 'bx_media@modules/boonex/media/|std-icon.svg', '_bx_media', '', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_actions";s:6:"params";a:0:{}s:5:"class";s:18:"TemplStudioModules";}', 0);
+
+SET @iParentPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name` = 'home');
+SET @iParentPageOrder = (SELECT IFNULL(MAX(`order`), 0) + 1 FROM `sys_std_pages_widgets` WHERE `page_id` = @iParentPageId);
+
+INSERT INTO `sys_std_pages_widgets` (`page_id`, `widget_id`, `order`) VALUES
+(@iParentPageId, LAST_INSERT_ID(), @iParentPageOrder);

+ 14 - 0
modules/boonex/media/install/sql/uninstall.sql

@@ -0,0 +1,14 @@
+SET @sName = 'bx_media';
+
+-- TABLES
+DROP TABLE IF EXISTS `bx_media_input_settings`;
+
+-- STUDIO WIDGET
+DELETE FROM `tp`, `tw`, `tpw`
+USING `sys_std_pages` AS `tp`, `sys_std_widgets` AS `tw`, `sys_std_pages_widgets` AS `tpw`
+WHERE `tp`.`id` = `tw`.`page_id` AND `tw`.`id` = `tpw`.`widget_id` AND `tp`.`name` = @sName;
+
+-- UPLOADERS
+DELETE FROM `sys_objects_storage` WHERE `object` IN('bx_media_uploader');
+
+

+ 258 - 0
modules/boonex/media/js/BxMediaUploader.js

@@ -0,0 +1,258 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    MediaManager MediaManager
+ * @ingroup     UnaModules
+ */
+
+/**
+ * Simple Uploader js class
+ */
+function BxMediaUploader(sUploaderObject, sStorageObject, sUniqId, sActionsUri, options) {
+    this.init(sUploaderObject, sStorageObject, sUniqId, sActionsUri, options);
+    this._sIframeId = 'bx-form-input-files-' + sUniqId + '-iframe';
+    this._eForm = null;
+}
+
+BxMediaUploader.prototype.init = function (sUploaderObject, sStorageObject, sUniqId, sActionsUri, options) {
+    this._isUploadsInProgress = false;
+
+    this._sUploaderObject = sUploaderObject;
+    this._sStorageObject = sStorageObject;
+
+    this._sUniqId = sUniqId;
+
+    this._sActionsUri = sActionsUri;
+
+    this._sUploaderJsInstance = 'glUploader_' + sUniqId + '_' + this._sUploaderObject;
+    this._sUploadInProgressContainerId = 'bx-form-input-files-' + sUniqId + '-upload-in-progress-' + this._sUploaderObject;
+    this._sPopupContainerId = 'bx-form-input-files-' + sUniqId + '-popup-wrapper-' + this._sUploaderObject;
+
+    this._sResultContainerId = 'bx-form-input-files-' + sUniqId + '-upload-result';
+    this._sErrorsContainerId = 'bx-form-input-files-' + sUniqId + '-errors'; 
+
+    this._sFormContainerId = 'bx-form-input-files-' + sUniqId + '-form-cont';
+
+    this._sTemplateGhost = options.template_ghost ? options.template_ghost : '<div id="' + this._getFileContainerId('{file_id}') + '"><input type="hidden" name="f[]" value="{file_id}" />{file_name} (<a href="javascript:void(0);" onclick="{js_instance_name}.deleteGhost(\'{file_id}\')">delete</a>)</div>';
+    this._sTemplateError = options.template_error_msg ? options.template_error_msg : '<div>{error}</div>' ;
+    this._sTemplateErrorGhosts = options.template_error_ghosts ? options.template_error_ghosts : this._sTemplateError;
+
+    this._isMultiple = undefined == options.multiple || !options.multiple ? false : true;
+
+    this._iContentId = undefined == options.content_id || '' == options.content_id ? '' : parseInt(options.content_id);
+
+    this._sImagesTranscoder = options.images_transcoder ? options.images_transcoder : '';
+
+    this._isPrivate = undefined == options.storage_private || parseInt(options.storage_private) ? 1 : 0;
+
+    this._sUploaderInstanceName = options.uploader_instance_name ? options.uploader_instance_name : '';
+
+    this._isErrorShown = false;
+}
+
+BxMediaUploader.prototype.isMultiple = function () {
+    return this._isMultiple;
+}
+
+BxMediaUploader.prototype.getCurrentFilesCount = function () {
+    return $('#' + $this._sResultContainerId + ' .bx-uploader-ghost').length;
+}
+
+BxMediaUploader.prototype.showUploaderForm = function () {
+    var $this = this;
+    var sUrl = this._getUrlWithStandardParams() + '&a=show_uploader_form&m=' + (this._isMultiple ? 1 : 0) + '&c=' + this._iContentId + '&p=' + this._isPrivate + '&_t=' + escape(new Date());
+
+    $(window).dolPopupAjax({
+        url: sUrl,
+        id: {force: true, value: this._sPopupContainerId},
+        onBeforeShow: function() {
+            if ($this.isMultiple())
+                $('#' + $this._sPopupContainerId + ' .bx-uploader-add-more-files').show();
+            else
+                $('#' + $this._sPopupContainerId + ' .bx-uploader-add-more-files').hide();
+            $('#' + $this._sPopupContainerId + ' .bx-popup-element-close').click(function() {
+                $this.onClickCancel();
+            });
+            if ('undefined' !== typeof($this.onBeforeShowPopup))
+                $this.onBeforeShowPopup();
+        },
+        onShow: function () {
+            if ('undefined' !== typeof($this.onShowPopup))
+                $this.onShowPopup();
+        },
+        closeElement: false,
+        closeOnOuterClick: false
+    });
+}
+
+BxMediaUploader.prototype.onClickCancel = function () {
+    var $this = this;
+    if (this._isUploadsInProgress) {
+        bx_confirm(_t('_sys_uploader_confirm_close_popup'), function() {
+            $this.cancelAll();
+            $('#' + $this._sPopupContainerId).dolPopupHide({});
+        });
+    } else {
+        $('#' + this._sPopupContainerId).dolPopupHide();
+    }
+}
+
+BxMediaUploader.prototype.onBeforeUpload = function (params) {
+
+    this._eForm = params;
+
+    this._loading(true, false);
+        
+    this._isUploadsInProgress = true;
+    this._lockPageFromLeaving();
+    this._clearErrors();
+}
+
+BxMediaUploader.prototype.onStartCopy = function (url) {
+    var $this = this;
+
+    $.post($this._sActionsUri + 'CopyFile/', { FileName: url, StorageObject: this._sStorageObject, UniqId: this._sUniqId, UploaderInstanceName: this._sUploaderInstanceName, isPrivate: this._isPrivate, ContentId: this._iContentId, isMultiple: this._isMultiple ? 1 : 0 }, function (data, textStatus) {
+        eval(jQuery(data).text())
+    });
+}
+
+BxMediaUploader.prototype.onStartEdit = function (params) {
+    alert('not implemented')
+}
+
+BxMediaUploader.prototype.onProgress = function (params) {
+
+}
+
+BxMediaUploader.prototype.onUploadCompleted = function (sErrorMsg) {
+
+    this._isUploadsInProgress = false;
+    this._unlockPageFromLeaving();
+    this._loading(false, true);
+
+    if (sErrorMsg.length) {
+        this.restoreGhosts();        
+        this._showError(sErrorMsg);
+    } else {        
+        this.restoreGhosts();
+        $('#' + this._sPopupContainerId).dolPopupHide({});
+        eval("oObj" + this._sUploaderInstanceName + ".removeFiles()");
+    }
+}
+
+BxMediaUploader.prototype.cancelAll = function () {
+    $('#' + this._sIframeId).attr('src', 'javascript:false;');
+    this.onUploadCompleted(_t('_sys_uploader_upload_canceled'));
+}
+
+BxMediaUploader.prototype.restoreGhosts = function () {
+    var sUrl = this._getUrlWithStandardParams() + '&img_trans=' + this._sImagesTranscoder + '&a=restore_ghosts&f=json' + '&c=' + this._iContentId + '&_t=' + (new Date());
+    var $this = this;
+
+    bx_loading(this._sResultContainerId, true);
+
+    $.getJSON(sUrl, function (aData) {
+        bx_loading($this._sResultContainerId, false);
+   
+        if (!$this.isMultiple())
+            $('#' + $this._sResultContainerId + ' .bx-uploader-ghost').remove();
+
+        if ('object' === typeof(aData)) {
+            $.each(aData, function(iFileId, oVars) {
+                var oFileContainer = $('#' + $this._getFileContainerId(iFileId));
+                if (oFileContainer.length > 0)
+                    return;
+                var sHTML;
+                if (typeof $this._sTemplateGhost == 'object')
+                    sHTML = $this._sTemplateGhost[iFileId];
+                else
+                    sHTML = $this._sTemplateGhost;
+                for (var i in oVars)
+                    sHTML = sHTML.replace (new RegExp('{'+i+'}', 'g'), oVars[i]);
+                
+                $('#' + $this._sResultContainerId).prepend(sHTML);
+
+                oFileContainer.find('.bx-uploader-ghost-preview img').hide().fadeIn(1000);
+            });
+        }
+    });
+};
+
+BxMediaUploader.prototype.deleteGhost = function (iFileId) {
+    var sUrl = this._getUrlWithStandardParams() + '&a=delete&id=' + iFileId;
+    var $this = this;
+
+    var sFileContainerId = $this._getFileContainerId(iFileId);
+    bx_loading(sFileContainerId, true);
+
+    $.post(sUrl, {_t: new Date()}, function (sMsg) {
+        bx_loading(sFileContainerId, false);
+        if ('ok' == sMsg) {
+            $('#' + sFileContainerId).slideUp('slow', function () {
+                $(this).remove();
+            });
+        } else {
+            $('#' + this._sResultContainerId).prepend($this._sTemplateErrorGhosts.replace('{error}', sMsg));
+        }        
+    });
+};
+
+BxMediaUploader.prototype._clearErrors = function () {
+    $('#' + this._sPopupContainerId + ' #' + this._sErrorsContainerId).html('');
+    this._isErrorShown = false;
+}
+
+BxMediaUploader.prototype._showError = function (s, bAppend) {
+    if (s == undefined || !s.length)
+        return;
+    if (!bAppend)
+        $('#' + this._sPopupContainerId + ' #' + this._sErrorsContainerId).html(this._sTemplateError.replace('{error}', s));
+    else
+        $('#' + this._sPopupContainerId + ' #' + this._sErrorsContainerId).prepend(this._sTemplateError.replace('{error}', s));
+    this._isErrorShown = true;
+};
+
+BxMediaUploader.prototype._getFileContainerId = function (iFileId) {
+    return 'bx-uploader-file-' + this._sStorageObject + '-' + iFileId;
+};
+
+BxMediaUploader.prototype._getUrlWithStandardParams = function () {
+    return sUrlRoot + 'storage_uploader.php?uo=' + this._sUploaderObject + '&so=' + this._sStorageObject + '&uid=' + this._sUniqId;
+}
+
+BxMediaUploader.prototype._lockPageFromLeaving = function () {
+    $(window).bind('beforeunload', function (e) {
+        var e = e || window.event;
+        // for ie, ff
+        e.returnValue = _t('_sys_uploader_confirm_leaving_page');
+        // for webkit
+        return _t('_sys_uploader_confirm_leaving_page');
+    });
+}
+
+BxMediaUploader.prototype._unlockPageFromLeaving = function () {
+    $(window).unbind('beforeunload');
+}
+
+BxMediaUploader.prototype._loading = function (bShowProgress, bShowForm) {
+
+    var eForm = $('#' + this._sFormContainerId + ' .bx-uploader-files-list');
+    var eBtn = $('#' + this._sFormContainerId + ' .bx-btn-primary');
+
+    if (bShowForm) {
+        if (null != this._eForm) {
+            eForm.find('.bx-uploader-simple-file').filter(':not(:first)').remove();
+            if ('undefined' !== typeof(this._eForm.reset)) 
+                this._eForm.reset();
+        }
+        eForm.show();
+        eBtn.show();
+    } else {
+        eForm.hide();
+        eBtn.hide();
+    }
+
+    bx_loading($('#' + this._sFormContainerId + ' .bx-uploader-loading').get(0), bShowProgress);
+}
+

+ 18 - 0
modules/boonex/media/request.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+* Copyright (c) UNA, Inc - https://una.io
+* MIT License - https://opensource.org/licenses/MIT
+*
+ * @defgroup   MediaManager MediaManager
+* @ingroup     UnaModules
+*
+* @{
+*/
+
+require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
+
+check_logged();
+
+BxBaseModTextRequest::processAsAction($GLOBALS['aModule'], $GLOBALS['aRequest']);
+
+/** @} */

+ 46 - 0
modules/boonex/media/template/MediaUploaderSettings.js

@@ -0,0 +1,46 @@
+<script>
+   FilePond.registerPlugin(FilePondPluginImagePreview);
+    FilePond.registerPlugin(FilePondPluginMediaPreview);
+    FilePond.registerPlugin(FilePondPluginFileValidateType);
+    FilePond.registerPlugin(FilePondPluginImageEdit);
+
+
+var oFilePondDefaultSettings = {
+    allowReorder: true,
+    imageEditEditor: Doka.create({
+        utils: ['crop', 'filter', 'color']
+    }),
+    labelIdle: '<span class="filepond--label-action"><bx_text:_bx_media_uploader_filepond_labelIdle /></span>',
+    labelInvalidField: '<bx_text:_bx_media_uploader_filepond_labelInvalidField />',
+    labelFileWaitingForSize: '<bx_text:_bx_media_uploader_filepond_labelFileWaitingForSize />',
+    labelFileSizeNotAvailable: '<bx_text:_bx_media_uploader_filepond_labelFileSizeNotAvailable />',
+    labelFileCountSingular: '<bx_text:_bx_media_uploader_filepond_labelFileCountSingular />',
+    labelFileCountPlural: '<bx_text:_bx_media_uploader_filepond_labelFileCountPlural />',
+    labelFileLoading: '<bx_text:_bx_media_uploader_filepond_labelFileLoading />',
+    labelFileAdded: '<bx_text:_bx_media_uploader_filepond_labelFileAdded />',
+    labelFileLoadErro: '<bx_text:_bx_media_uploader_filepond_labelFileLoadError />',
+    labelFileRemoved: '<bx_text:_bx_media_uploader_filepond_labelFileRemoved />',
+    labelFileRemoveError: '<bx_text:_bx_media_uploader_filepond_labelFileRemoveError />',
+    labelFileProcessing: '<bx_text:_bx_media_uploader_filepond_labelFileProcessing />',
+    labelFileProcessingComplete: '<bx_text:_bx_media_uploader_filepond_labelFileProcessingComplete />',
+    labelFileProcessingAborted: '<bx_text:_bx_media_uploader_filepond_labelFileProcessingAborted />',
+    labelFileProcessingError: '<bx_text:_bx_media_uploader_filepond_labelFileProcessingError />',
+    labelFileProcessingRevertError: '<bx_text:_bx_media_uploader_filepond_labelFileProcessingRevertError />',
+    labelTapToCancel: '<bx_text:_bx_media_uploader_filepond_labelTapToCancel />',
+    labelTapToRetry: '<bx_text:_bx_media_uploader_filepond_labelTapToRetry />',
+    labelTapToUndo: '<bx_text:_bx_media_uploader_filepond_labelTapToUndo />',
+    labelButtonRemoveItem: '<bx_text:_bx_media_uploader_filepond_labelButtonRemoveItem />',
+    labelButtonAbortItemLoad: '<bx_text:_bx_media_uploader_filepond_labelButtonAbortItemLoad />',
+    labelButtonRetryItemLoad: '<bx_text:_bx_media_uploader_filepond_labelButtonRetryItemLoad />',
+    labelButtonAbortItemProcessing: '<bx_text:_bx_media_uploader_filepond_labelButtonAbortItemProcessing />',
+    labelButtonUndoItemProcessing: '<bx_text:_bx_media_uploader_filepond_labelButtonUndoItemProcessing />',
+    labelButtonRetryItemProcessing: '<bx_text:_bx_media_uploader_filepond_labelButtonRetryItemProcessing />',
+    labelButtonProcessItem: '<bx_text:_bx_media_uploader_filepond_labelButtonProcessItem />',
+    fileValidateTypeDetectType: (source, type) => new Promise((resolve, reject) => {
+        if (type != ''){
+            aFileType = type.split("/");
+            resolve('.'+aFileType[1]);
+        }
+    })
+}
+</script>

+ 63 - 0
modules/boonex/media/template/css/main.css

@@ -0,0 +1,63 @@
+.bx_media_container{
+    min-width:800px;
+}
+.bx_media_container .bx_media_cell{
+    display:inline-block; 
+    width:calc(48% - 1rem); 
+    margin:0.5rem;
+    vertical-align:top
+}
+.bx_media_cell_link{
+    display:block;
+    height:76px;
+    line-height:76px;
+    border-radius:5px;
+    background:#f1f0ef;
+    color:rgb(79, 79, 79);
+    text-align:center;
+    text-decoration:underline;
+}
+.bx_media_lists_container{
+    position:absolute;
+    top:0px;
+    left:0px;
+    width:calc(100%)
+}
+.bx_media_lists{
+    height:10rem;
+    overflow-x:scroll;
+    overflow-y:hidden;
+    position:relative;
+}
+               
+.bx_media_list_item{
+    background-size:contain;
+	background-repeat: no-repeat;
+	background-position: center center;
+	border:1px solid #a7a4a4;
+    width:8rem;
+    height:8rem;
+    margin:0.5rem;
+    position:relative;
+    display:inline-block;
+}
+.bx_media_list_item:hover {
+    cursor:pointer;
+}
+
+.bx_media_container .filepond--item {
+    width: calc(50% - .5em);
+}
+
+.bx_media_container .filepond--drop-label.filepond--drop-label label {
+    width:100%;
+    padding:0px !important;
+    height:100%;
+}
+ .bx_media_container .filepond--label-action {
+    display:block;
+    width:100%;
+    height:100%;
+    line-height:76px !important;
+    vertical-align:middle;
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 11 - 0
modules/boonex/media/template/images/icons/std-icon.svg


+ 16 - 0
modules/boonex/media/template/media_uploader_button.html

@@ -0,0 +1,16 @@
+<a __attrs__ href="javascript:void(0);" class="bx-btn bx-btn-small bx-def-margin-sec-right __btn_class__">__button_title__</a>
+<script>
+    $(document).ready(function () {
+        __uploader_instance_name__ = new BxMediaUploader('__engine__', '__storage_object__', '__uniq_id__', '__action_url__', {
+            'multiple': __multiple__,
+            'content_id': '__content_id__',
+            'images_transcoder': '__images_transcoder__',
+            'storage_private': '__storage_private__',
+            'template_error_msg': '<div class="bx-uploader-msg-err">{error}</div>',
+            'template_ghost': __template_ghost__,
+            'uploader_instance_name': '__uploader_instance_name__',
+            'storage_private': __storage_private__,
+        });
+    });
+</script>
+

+ 84 - 0
modules/boonex/media/template/media_uploader_form.html

@@ -0,0 +1,84 @@
+<div class="bx_media_container">
+    <div class="bx_media_cell">
+        <div id="__form_container_id__" class="bx-uploader-form-cont">
+            <form enctype="multipart/form-data" method="POST" target="__iframe_id__" action="
+                <bx_url_root />storage_uploader.php" onsubmit="__uploader_instance_name__.onBeforeUpload(this);">
+                <div class="bx-uploader-loading"></div>
+                <div class="bx-uploader-files-list">
+
+                    <div id="__errors_container_id__"></div>
+                    <div class="bx-uploader-simple-file"><input name="f[]" __accepted_files__ type="file" /></div>
+                </div>
+
+            </form>
+        </div>
+        <div class="bx-def-font-small">__restrictions_text__</div>
+    </div>
+    <div class="bx_media_cell"><a class="bx_media_cell_link"  href="javascript:" onclick="__uploader_instance_name__.onStartEdit();">Edit</a></div>
+</div>
+<bx_if:recent_files>
+    <h4><bx_text:_bx_media_subheader_recent_files /></h4>
+    <div class="bx_media_lists">
+        <div class="bx_media_lists_container" style="width:__item_count__0rem">
+            <bx_repeat:items>
+                <div class="bx_media_list_item" style="background-image:url(__url__)" onclick="__uploader_instance_name__.onStartCopy('__url__');"></div>
+            </bx_repeat:items>
+        </div>
+    </div>
+</bx_if:recent_files>
+<div class="bx-def-padding-top bx-clearfix">
+    <div class="bx-btn" onclick="__uploader_instance_name__.onClickCancel()"><bx_text:_sys_uploader_close /></div>
+</div>
+<!--<div class="bx-btn bx-btn-primary bx-def-margin-sec-right" onclick="sas()">123</div>-->
+<script>
+var oObj__uploader_instance_name__;
+$(function(){
+    var oStat__uploader_instance_name__
+    var oSett__uploader_instance_name__ = Object.assign(
+        oFilePondDefaultSettings, 
+        {
+            allowMultiple: __filepond_multiple__,
+            onprocessfiles : (formData) => {
+                eval(oStat__uploader_instance_name__);
+            },
+            server: {
+                process: (fieldName, file, metadata, load, error, progress, abort) => {
+                    const formData = new FormData();
+                    formData.append(fieldName, file, file.name);
+                    formData.append('uo', '__engine__');
+                    formData.append('so', '__storage_object__');
+                    formData.append('uid', '__uniq_id__');
+                    formData.append('m', '__multiple__');
+                    formData.append('c', '__content_id__');
+                    formData.append('p', '__storage_private__');
+                    formData.append('a', 'upload');
+
+                    const request = new XMLHttpRequest();
+                    request.open('POST', '/storage_uploader.php');
+
+                    request.upload.onprogress = (e) => {
+                        progress(e.lengthComputable, e.loaded, e.total)
+                    };
+
+                    request.onload = function(res) {
+                        if (request.status >= 200 && request.status < 300) {
+                            load("__uploader_instance_name__");
+                            oStat__uploader_instance_name__ = jQuery(request.responseText).text();
+                        }
+                        else {
+                            error('<bx_text:_bx_media_uploader_filepond_labelFileLoadError />');
+                        }
+                    };
+                    request.send(formData);
+                }
+            }
+        }
+    );
+
+    oObj__uploader_instance_name__ = FilePond.create(
+        document.querySelector('#__form_container_id__ input[type="file"]'),
+        oSett__uploader_instance_name__
+    );
+});
+
+</script>

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است