Enable Media Replace - Version 3.3.0

Version Description

  • When replacing an image and changing the name, Search / Replace is now also done on the meta_value of postmeta.
  • Replace PDF thumbnails too
  • Copy title from EXIF
  • RTL View incorporated into the CSS
  • wp_handle_upload filter should be treated as such (and not as action)
  • Use wp_attached_file instead of the GUID
  • Fix: replace missing file
  • Fix: aphostrophe breaking the upload
  • Fix: broken "before" image
  • Fix: update properly the date
  • Fix: errors for non-image items in Media Library
  • Fix: empty admin menu item created
  • Refactored all the code
Download this release

Release Info

Developer ShortPixel
Plugin Icon 128x128 Enable Media Replace
Version 3.3.0
Comparing to
See all releases

Code changes from version 3.2.9 to 3.3.0

classes/cache.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace EnableMediaReplace;
3
+
4
+ class emrCache
5
+ {
6
+ protected $has_supercache = false; // supercache seems to replace quite fine, without our help. @todo Test if this is needed
7
+ protected $has_w3tc = false;
8
+ protected $has_wpengine = false;
9
+ protected $has_fastestcache = false;
10
+ protected $has_siteground = false;
11
+
12
+ public function __construct()
13
+ {
14
+
15
+ }
16
+
17
+ /** Checks which cache plugins are active on the moment a flush is needed */
18
+ public function checkCaches()
19
+ {
20
+ if ( function_exists( 'w3tc_pgcache_flush' ) )
21
+ $this->has_w3tc = true;
22
+
23
+ if ( function_exists('wp_cache_clean_cache') )
24
+ $this->has_supercache = true;
25
+
26
+ if ( class_exists( 'WpeCommon' ) )
27
+ $this->has_wpengine = true;
28
+
29
+ global $wp_fastest_cache;
30
+ if ( method_exists( 'WpFastestCache', 'deleteCache' ) && !empty( $wp_fastest_cache ) )
31
+ $this->has_fastestcache = true;
32
+
33
+ // SG SuperCacher
34
+ if (function_exists('sg_cachepress_purge_cache')) {
35
+ $this->has_siteground = true;
36
+ }
37
+
38
+ // @todo WpRocket?
39
+ // @todo BlueHost Caching?
40
+ }
41
+
42
+ /* Tries to flush cache there were we have issues
43
+ *
44
+ * @param Array $args Argument Array to provide data.
45
+ */
46
+ public function flushCache($args)
47
+ {
48
+ $defaults = array(
49
+ 'flush_mode' => 'post',
50
+ 'post_id' => 0,
51
+ );
52
+
53
+ $args = wp_parse_args($args, $defaults);
54
+ $post_id = $args['post_id']; // can be zero!
55
+
56
+ // important - first check the available cache plugins
57
+ $this->checkCaches();
58
+
59
+ // general WP
60
+ if ($post_id > 0)
61
+ clean_post_cache($post_id);
62
+ else
63
+ wp_cache_flush();
64
+
65
+ /* Verified working without.
66
+ if ($this->has_supercache)
67
+ $this->removeSuperCache();
68
+ */
69
+ if ($this->has_w3tc)
70
+ $this->removeW3tcCache();
71
+
72
+ if ($this->has_wpengine)
73
+ $this->removeWpeCache();
74
+
75
+ if ($this->has_siteground)
76
+ $this->removeSiteGround();
77
+
78
+ if ($this->has_fastestcache)
79
+ $this->removeFastestCache();
80
+
81
+ }
82
+
83
+ protected function removeSuperCache()
84
+ {
85
+ global $file_prefix, $supercachedir;
86
+ if ( empty( $supercachedir ) && function_exists( 'get_supercache_dir' ) ) {
87
+ $supercachedir = get_supercache_dir();
88
+ }
89
+ wp_cache_clean_cache( $file_prefix );
90
+ }
91
+
92
+ protected function removeW3tcCache()
93
+ {
94
+ w3tc_pgcache_flush();
95
+ }
96
+
97
+ protected function removeWpeCache()
98
+ {
99
+ if ( method_exists( 'WpeCommon', 'purge_memcached' ) ) {
100
+ WpeCommon::purge_memcached();
101
+ }
102
+ if ( method_exists( 'WpeCommon', 'clear_maxcdn_cache' ) ) {
103
+ WpeCommon::clear_maxcdn_cache();
104
+ }
105
+ if ( method_exists( 'WpeCommon', 'purge_varnish_cache' ) ) {
106
+ WpeCommon::purge_varnish_cache();
107
+ }
108
+ }
109
+
110
+ protected function removeFastestCache()
111
+ {
112
+ global $wp_fastest_cache;
113
+ $wp_fastest_cache->deleteCache();
114
+ }
115
+
116
+ protected function removeSiteGround()
117
+ {
118
+ sg_cachepress_purge_cache();
119
+ }
120
+
121
+ }
classes/emr-plugin.php ADDED
@@ -0,0 +1,293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace EnableMediaReplace;
3
+
4
+ // Does what a plugin does.
5
+ class EnableMediaReplacePlugin
6
+ {
7
+
8
+ protected $plugin_path;
9
+
10
+ public function __construct()
11
+ {
12
+ $this->plugin_actions(); // init
13
+
14
+
15
+ }
16
+
17
+ public function plugin_actions()
18
+ {
19
+ $this->plugin_path = plugin_dir_path(EMR_ROOT_FILE);
20
+ $this->plugin_url = plugin_dir_url(EMR_ROOT_FILE);
21
+
22
+ // init plugin
23
+ add_action('admin_menu', array($this,'menu'));
24
+ add_action('admin_init', array($this,'init'));
25
+ add_action('admin_enqueue_scripts', array($this,'admin_scripts'));
26
+
27
+ // content filters
28
+ add_filter('attachment_fields_to_edit', array($this, 'attachment_editor'), 10, 2);
29
+ add_filter('media_row_actions', array($this,'add_media_action'), 10, 2);
30
+ add_action('attachment_submitbox_misc_actions', array($this,'admin_date_replaced_media_on_edit_media_screen'), 91 );
31
+ add_filter('upload_mimes', array($this,'add_mime_types'), 1, 1);
32
+
33
+ // notices
34
+ add_action('admin_notices', array($this,'display_notices'));
35
+ add_action('network_admin_notices', array($this,'display_network_notices'));
36
+ add_action('wp_ajax_emr_dismiss_notices', array($this,'dismiss_notices'));
37
+
38
+ // shortcode
39
+ add_shortcode('file_modified', array($this, 'get_modified_date'));
40
+
41
+ }
42
+
43
+ /**
44
+ * Register this file in WordPress so we can call it with a ?page= GET var.
45
+ * To suppress it in the menu we give it an empty menu title.
46
+ */
47
+ public function menu()
48
+ {
49
+ add_submenu_page(null, esc_html__("Replace media", "enable-media-replace"), esc_html__("Replace media", "enable-media-replace"), 'upload_files', 'enable-media-replace/enable-media-replace', array($this, 'route'));
50
+ }
51
+
52
+ /**
53
+ * Initialize this plugin. Called by 'admin_init' hook.
54
+ * Only languages files needs loading during init.
55
+ */
56
+ public function init()
57
+ {
58
+ load_plugin_textdomain( 'enable-media-replace', false, basename(dirname(EMR_ROOT_FILE) ) . '/languages' );
59
+ }
60
+
61
+ /** Load EMR views based on request */
62
+ public function route()
63
+ {
64
+ global $plugin_page;
65
+ switch($plugin_page)
66
+ {
67
+ case 'enable-media-replace/enable-media-replace.php':
68
+ $action = isset($_GET['action']) ? sanitize_text_field($_GET['action']) : '';
69
+ wp_enqueue_style('emr_style');
70
+ wp_enqueue_script('jquery-ui-datepicker');
71
+ wp_enqueue_style('jquery-ui-datepicker');
72
+ wp_enqueue_script('emr_admin');
73
+
74
+ if (! check_admin_referer( $action, '_wpnonce') )
75
+ {
76
+ die('Invalid Nonce');
77
+ }
78
+
79
+ // @todo Later this should be move to it's own controller, and built view from there.
80
+ if ( $action == 'media_replace' ) {
81
+ if ( array_key_exists("attachment_id", $_GET) && intval($_GET["attachment_id"]) > 0) {
82
+ require_once($this->plugin_path . "views/popup.php"); // warning variables like $action be overwritten here.
83
+ }
84
+ }
85
+ elseif ( $action == 'media_replace_upload' ) {
86
+ require_once($this->plugin_path . 'views/upload.php');
87
+ }
88
+ else {
89
+ exit('Something went wrong loading page, please try again');
90
+ }
91
+
92
+ break;
93
+ }
94
+
95
+ }
96
+
97
+ /** register styles and scripts
98
+ *
99
+ * Nothing should ever by -enqueued- here, just registered.
100
+ */
101
+ public function admin_scripts()
102
+ {
103
+ if (is_rtl())
104
+ {
105
+ wp_register_style('emr_style', plugins_url('css/admin.rtl.css', EMR_ROOT_FILE) );
106
+ }
107
+ else {
108
+ wp_register_style('emr_style', plugins_url('css/admin.css', EMR_ROOT_FILE) );
109
+ }
110
+
111
+ wp_register_script('emr_admin', plugins_url('js/emr_admin.js', EMR_ROOT_FILE), array('jquery'), false, true );
112
+ wp_localize_script('emr_admin', 'emr_options', array('dateFormat' => $this->convertdate(get_option( 'date_format' ))));
113
+
114
+ }
115
+
116
+ /** Utility function for the Jquery UI Datepicker */
117
+ function convertdate( $sFormat ) {
118
+ switch( $sFormat ) {
119
+ //Predefined WP date formats
120
+ case 'F j, Y':
121
+ return( 'MM dd, yy' );
122
+ break;
123
+ case 'Y/m/d':
124
+ return( 'yy/mm/dd' );
125
+ break;
126
+ case 'm/d/Y':
127
+ return( 'mm/dd/yy' );
128
+ break;
129
+ case 'd/m/Y':
130
+ default:
131
+ return( 'dd/mm/yy' );
132
+ break;
133
+ }
134
+ }
135
+
136
+ /** Get the URL to the media replace page
137
+ * @param $attach_id The attachment ID to replace
138
+ * @return Admin URL to the page.
139
+ */
140
+ protected function getMediaReplaceURL($attach_id)
141
+ {
142
+ $url = admin_url( "upload.php");
143
+ $url = add_query_arg(array(
144
+ 'page' => 'enable-media-replace/enable-media-replace.php',
145
+ 'action' => 'media_replace',
146
+ 'attachment_id' => $attach_id,
147
+ ), $url);
148
+
149
+ return $url;
150
+
151
+ }
152
+
153
+ /**
154
+ * Add some new fields to the attachment edit panel.
155
+ * @param array form fields edit panel
156
+ * @return array form fields with enable-media-replace fields added
157
+ */
158
+ public function attachment_editor($form_fields, $post)
159
+ {
160
+ $url = $this->getMediaReplaceURL($post->ID);
161
+
162
+ $action = "media_replace";
163
+ $editurl = wp_nonce_url( $url, $action );
164
+
165
+ /* Unneeded - admin_url already checks for force_ssl_admin ( in set_scheme function )
166
+ if (FORCE_SSL_ADMIN) {
167
+ $editurl = str_replace("http:", "https:", $editurl);
168
+ } */
169
+ $link = "href=\"$editurl\"";
170
+ $form_fields["enable-media-replace"] = array(
171
+ "label" => esc_html__("Replace media", "enable-media-replace"),
172
+ "input" => "html",
173
+ "html" => "<p><a class='button-secondary'$link>" . esc_html__("Upload a new file", "enable-media-replace") . "</a></p>", "helps" => esc_html__("To replace the current file, click the link and upload a replacement.", "enable-media-replace")
174
+ );
175
+
176
+ return $form_fields;
177
+ }
178
+
179
+ /**
180
+ * @param array $mime_types
181
+ * @return array
182
+ */
183
+
184
+ public function add_mime_types($mime_types)
185
+ {
186
+ $mime_types['dat'] = 'text/plain'; // Adding .dat extension
187
+ return $mime_types;
188
+ }
189
+
190
+ /**
191
+ * Function called by filter 'media_row_actions'
192
+ * Enables linking to EMR straight from the media library
193
+ */
194
+ public function add_media_action( $actions, $post) {
195
+ $url = $this->getMediaReplaceURL($post->ID);
196
+ $action = "media_replace";
197
+ $editurl = wp_nonce_url( $url, $action );
198
+
199
+ /* See above, not needed.
200
+ if (FORCE_SSL_ADMIN) {
201
+ $editurl = str_replace("http:", "https:", $editurl);
202
+ } */
203
+ $link = "href=\"$editurl\"";
204
+
205
+ $newaction['adddata'] = '<a ' . $link . ' aria-label="' . esc_html__("Replace media", "enable-media-replace") . '" rel="permalink">' . esc_html__("Replace media", "enable-media-replace") . '</a>';
206
+ return array_merge($actions,$newaction);
207
+ }
208
+
209
+
210
+ public function display_notices() {
211
+ $current_screen = get_current_screen();
212
+
213
+ $crtScreen = function_exists("get_current_screen") ? get_current_screen() : (object)array("base" => false);
214
+
215
+ if(current_user_can( 'activate_plugins' ) && !get_option( 'emr_news') && !is_plugin_active('shortpixel-image-optimiser/wp-shortpixel.php')
216
+ && ($crtScreen->base == "upload" || $crtScreen->base == "plugins")
217
+ //for network installed plugins, don't display the message on subsites.
218
+ && !(function_exists('is_multisite') && is_multisite() && is_plugin_active_for_network('enable-media-replace/enable-media-replace.php') && !is_main_site()))
219
+ {
220
+ require_once($this->plugin_path . '/views/notice.php');
221
+ }
222
+ }
223
+
224
+ public function display_network_notices() {
225
+ if(current_user_can( 'activate_plugins' ) && !get_option( 'emr_news') && !is_plugin_active_for_network('shortpixel-image-optimiser/wp-shortpixel.php')) {
226
+ require_once( str_replace("enable-media-replace.php", "notice.php", __FILE__) );
227
+ }
228
+ }
229
+
230
+ /* Ajax function to dismiss notice */
231
+ public function dismiss_notices() {
232
+ update_option( 'emr_news', true);
233
+ exit(json_encode(array("Status" => 0)));
234
+ }
235
+
236
+ /** Outputs the replaced date of the media on the edit_attachment screen
237
+ *
238
+ * @param $post Obj Post Object
239
+ */
240
+ function admin_date_replaced_media_on_edit_media_screen($post) {
241
+ $post_id = $post->ID;
242
+
243
+ if ( $post->post_modified == $post->post_date ) {
244
+ return;
245
+ }
246
+
247
+ $modified = date_i18n( __( 'M j, Y @ H:i' ) , strtotime( $post->post_modified ) );
248
+
249
+ ?>
250
+ <div class="misc-pub-section curtime">
251
+ <span id="timestamp"><?php echo esc_html__( 'Revised', 'enable-media-replace' ); ?>: <b><?php echo $modified; ?></b></span>
252
+ </div>
253
+ <?php
254
+ }
255
+
256
+ /**
257
+ * Shorttag function to show the media file modification date/time.
258
+ * @param array shorttag attributes
259
+ * @return string content / replacement shorttag
260
+ * @todo Note this returns the wrong date, ie. server date not corrected for timezone. Function could be removed altogether, not sure about purpose.
261
+ */
262
+ public function get_modified_date($atts) {
263
+ $id=0;
264
+ $format= '';
265
+
266
+ extract(shortcode_atts(array(
267
+ 'id' => '',
268
+ 'format' => get_option('date_format') . " " . get_option('time_format'),
269
+ ), $atts));
270
+
271
+ if ($id == '') return false;
272
+
273
+ // Get path to file
274
+ $current_file = get_attached_file($id);
275
+
276
+ if ( ! file_exists( $current_file ) ) {
277
+ return false;
278
+ }
279
+
280
+ // Get file modification time
281
+ $filetime = filemtime($current_file);
282
+
283
+ if ( false !== $filetime ) {
284
+ // do date conversion
285
+ return date( $format, $filetime );
286
+ }
287
+
288
+ return false;
289
+ }
290
+
291
+
292
+
293
+ } // class
classes/file.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace EnableMediaReplace;
3
+
4
+ class emrFile
5
+ {
6
+
7
+ protected $file; // the full file w/ path.
8
+ protected $extension;
9
+ protected $fileName;
10
+ protected $filePath;
11
+ protected $fileURL;
12
+ protected $fileMime;
13
+ protected $permissions = 0;
14
+
15
+ protected $exists = false;
16
+
17
+ public function __construct($file)
18
+ {
19
+ clearstatcache($file);
20
+ // file can not exist i.e. crashed files replacement and the lot.
21
+ if ( file_exists($file))
22
+ {
23
+ $this->exists = true;
24
+ }
25
+
26
+ $this->file = $file;
27
+ $fileparts = pathinfo($file);
28
+
29
+ $this->fileName = isset($fileparts['basename']) ? $fileparts['basename'] : '';
30
+ $this->filePath = isset($fileparts['dirname']) ? $fileparts['dirname'] : '';
31
+ $this->extension = isset($fileparts['extension']) ? $fileparts['extension'] : '';
32
+ if ($this->exists) // doesn't have to be.
33
+ $this->permissions = fileperms($file) & 0777;
34
+
35
+ $filedata = wp_check_filetype_and_ext($this->file, $this->fileName);
36
+ // This will *not* be checked, is not meant for permission of validation!
37
+ $this->fileMime = (isset($filedata['type'])) ? $filedata['type'] : false;
38
+
39
+ // echo "<PRE>"; var_dump($this); echo "</PRE><BR>";
40
+ }
41
+
42
+ public function getFullFilePath()
43
+ {
44
+ return $this->file;
45
+ }
46
+
47
+ public function getPermissions()
48
+ {
49
+ return $this->permissions;
50
+ }
51
+
52
+ public function setPermissions($permissions)
53
+ {
54
+ @chmod($this->file, $permissions);
55
+ }
56
+
57
+ public function getFilePath()
58
+ {
59
+ return $this->filePath;
60
+ }
61
+
62
+ public function getFileName()
63
+ {
64
+ return $this->fileName;
65
+ }
66
+
67
+ public function getFileMime()
68
+ {
69
+ return $this->fileMime;
70
+ }
71
+
72
+
73
+ }
74
+
75
+
76
+ ?>
classes/replacer.php ADDED
@@ -0,0 +1,309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace EnableMediaReplace;
3
+ use \EnableMediaReplace\emrFile as File;
4
+
5
+ class Replacer
6
+ {
7
+ protected $post_id;
8
+
9
+ // everything source is the attachment being replaced
10
+ protected $sourceFile; // File Object
11
+ protected $source_post; // wpPost;
12
+ protected $source_is_image;
13
+ protected $source_metadata;
14
+ protected $source_url;
15
+
16
+ // everything target is what will be.
17
+ protected $targetFile;
18
+ protected $targetName;
19
+ protected $target_metadata;
20
+ protected $target_url;
21
+
22
+ protected $replaceMode = null;
23
+ protected $timeMode = null;
24
+ protected $datetime = null;
25
+
26
+ protected $ThumbnailUpdater; // class
27
+
28
+ const MODE_REPLACE = 1;
29
+ const MODE_SEARCHREPLACE = 2;
30
+
31
+ const TIME_UPDATEALL = 1;
32
+ const TIME_UPDATEMODIFIED = 2;
33
+ const TIME_CUSTOM = 3;
34
+
35
+ public function __construct($post_id)
36
+ {
37
+ $this->post_id = $post_id;
38
+
39
+ $source_file = trim(get_attached_file($post_id, apply_filters( 'emr_unfiltered_get_attached_file', true )));
40
+
41
+ $this->sourceFile = new File($source_file);
42
+ $this->source_post = get_post($post_id);
43
+ $this->source_is_image = wp_attachment_is('image', $this->source_post);
44
+ $this->source_metadata = wp_get_attachment_metadata( $post_id );
45
+ $this->source_url = wp_get_attachment_url($post_id);
46
+
47
+ $this->ThumbnailUpdater = new \ThumbnailUpdater($post_id);
48
+ $this->ThumbnailUpdater->setOldMetadata($this->source_metadata);
49
+ }
50
+
51
+ public function setMode($mode)
52
+ {
53
+ $this->replaceMode = $mode;
54
+ }
55
+
56
+ public function setTimeMode($mode, $datetime = 0)
57
+ {
58
+ if ($datetime == 0)
59
+ $datetime = current_time('mysql');
60
+
61
+ $this->datetime = $datetime;
62
+ $this->timeMode = $mode;
63
+ }
64
+
65
+ /** Replace the sourceFile with a target
66
+ * @param $file String Full Path to the Replacement File. This will usually be an uploaded file in /tmp/
67
+ * @param $fileName String The fileName of the uploaded file. This will be used if sourcefile is not to be overwritten.
68
+ */
69
+ public function replaceWith($file, $fileName)
70
+ {
71
+ global $wpdb;
72
+ //$this->targetFile = new File($file);
73
+ $this->targetName = $fileName;
74
+ //$this->targetFile = new File($file); // this will point to /tmp!
75
+
76
+ $this->removeCurrent(); // tries to remove the current files.
77
+ $targetFile = $this->getTargetFile();
78
+
79
+ if (is_null($targetFile))
80
+ {
81
+ _e('Target File could not be set. The source file might not be there. In case of search and replace, a filter might prevent this', "enable-media-replace");
82
+ exit;
83
+ }
84
+
85
+ /* @todo See if wp_handle_sideload / wp_handle_upload can be more securely used for this */
86
+ $result_moved = move_uploaded_file($file,$targetFile);
87
+
88
+ if (false === $result_moved)
89
+ {
90
+ printf( esc_html__('The uploaded file could not be moved to %1$s , most likely because it could not remove the old images (file permissions) or the upload failed.', "enable-media-replace"), $targetFile );
91
+ exit;
92
+ }
93
+ $this->targetFile = new File($targetFile);
94
+
95
+ if ($this->sourceFile->getPermissions() > 0)
96
+ chmod( $targetFile, $this->sourceFile->getPermissions() ); // restore permissions
97
+ else {
98
+ // 'Setting permissions failed';
99
+ }
100
+
101
+ // update the file attached. This is required for wp_get_attachment_url to work.
102
+ update_attached_file($this->post_id, $this->targetFile->getFullFilePath() );
103
+ $this->target_url = wp_get_attachment_url($this->post_id);
104
+
105
+ // Run the filter, so other plugins can hook if needed.
106
+ $filtered = apply_filters( 'wp_handle_upload', array(
107
+ 'file' => $this->targetFile->getFullFilePath(),
108
+ 'url' => $this->target_url,
109
+ 'type' => $this->targetFile->getFileMime(),
110
+ ), 'sideload');
111
+
112
+ // check if file changed during filter. Set changed to attached file meta properly.
113
+ if (isset($filtered['file']) && $filtered['file'] != $this->targetFile->getFullFilePath() )
114
+ {
115
+ update_attached_file($this->post_id, $filtered['file'] );
116
+ $this->targetFile = new File($filtered['file']); // handle as a new file
117
+ }
118
+
119
+ $metadata = wp_generate_attachment_metadata( $this->post_id, $this->targetFile->getFullFilePath() );
120
+ wp_update_attachment_metadata( $this->post_id, $metadata );
121
+ $this->target_metadata = $metadata;
122
+
123
+ if ($this->replaceMode == self::MODE_SEARCHREPLACE)
124
+ {
125
+ $title = $this->getNewTitle();
126
+
127
+ $update_ar = array('ID' => $this->post_id);
128
+ $update_ar['post_title'] = $title;
129
+ $update_ar['post_name'] = sanitize_title($title);
130
+ // $update_ar['guid'] = wp_get_attachment_url($this->post_id);
131
+ $update_ar['post_mime_type'] = $this->targetFile->getFileMime();
132
+ $post_id = \wp_update_post($update_ar, true);
133
+
134
+ // update post doesn't update GUID on updates.
135
+ $wpdb->update( $wpdb->posts, array( 'guid' => $this->target_url), array('ID' => $this->post_id) );
136
+ //enable-media-replace-upload-done
137
+ if (is_wp_error($post_id))
138
+ {
139
+ $errors = $post_id->get_error_messages();
140
+ foreach ($errors as $error) {
141
+ echo $error;
142
+ }
143
+ }
144
+ $this->doSearchReplace();
145
+ do_action("enable-media-replace-upload-done", $this->target_url, $this->source_url);
146
+ }
147
+
148
+ if(wp_attachment_is_image($this->post_id))
149
+ {
150
+ $this->ThumbnailUpdater->setNewMetadata($metadata);
151
+ $this->ThumbnailUpdater->updateThumbnails();
152
+ }
153
+
154
+ // if all set and done, update the date.
155
+ // This must be done after wp_update_posts
156
+ $this->updateDate(); // updates the date.
157
+
158
+ // Give the caching a kick. Off pending specifics.
159
+ $cache_args = array(
160
+ 'flush_mode' => 'post',
161
+ 'post_id' => $this->post_id,
162
+ );
163
+
164
+ $cache = new emrCache();
165
+ $cache->flushCache($cache_args);
166
+
167
+ }
168
+
169
+ protected function getNewTitle()
170
+ {
171
+ $title = $this->targetFile->getFileName();
172
+ $meta = $this->target_metadata;
173
+
174
+ if (isset($meta['image_meta']))
175
+ {
176
+ if (isset($meta['image_meta']['title']))
177
+ {
178
+ if (strlen($meta['image_meta']['title']) > 0)
179
+ {
180
+ $title = $meta['image_meta']['title'];
181
+ }
182
+ }
183
+ }
184
+
185
+ // Thanks Jonas Lundman (http://wordpress.org/support/topic/add-filter-hook-suggestion-to)
186
+ $title = apply_filters( 'enable_media_replace_title', $title );
187
+
188
+ return $title;
189
+ }
190
+
191
+ /** Returns a full target path to place to new file. Including the file name! **/
192
+ protected function getTargetFile()
193
+ {
194
+ $targetPath = null;
195
+ if ($this->replaceMode == self::MODE_REPLACE)
196
+ {
197
+ $targetPath = $this->sourceFile->getFullFilePath(); // overwrite source
198
+ }
199
+ elseif ($this->replaceMode == self::MODE_SEARCHREPLACE)
200
+ {
201
+ $path = $this->sourceFile->getFilePath();
202
+ $unique = wp_unique_filename($path, $this->targetName);
203
+
204
+ $new_filename = apply_filters( 'emr_unique_filename', $unique, $path, $this->post_id );
205
+ $targetPath = trailingslashit($path) . $new_filename;
206
+ }
207
+ return $targetPath;
208
+ }
209
+
210
+ /** Tries to remove all of the old image, without touching the metadata in database
211
+ * This might fail on certain files, but this is not an indication of success ( remove might fail, but overwrite can still work)
212
+ */
213
+ protected function removeCurrent()
214
+ {
215
+ $meta = wp_get_attachment_metadata( $this->post_id );
216
+ $backup_sizes = get_post_meta( $this->post_id, '_wp_attachment_backup_sizes', true );
217
+ $result = wp_delete_attachment_files($this->post_id, $meta, $backup_sizes, $this->sourceFile->getFullFilePath() );
218
+ }
219
+
220
+ /** Handle new dates for the replacement */
221
+ protected function updateDate()
222
+ {
223
+ global $wpdb;
224
+ $post_date = $this->datetime;
225
+ $post_date_gmt = get_gmt_from_date($post_date);
226
+
227
+ $update_ar = array('ID' => $this->post_id);
228
+ if ($this->timeMode == static::TIME_UPDATEALL || $this->timeMode == static::TIME_CUSTOM)
229
+ {
230
+ $update_ar['post_date'] = $post_date;
231
+ $update_ar['post_date_gmt'] = $post_date_gmt;
232
+ }
233
+ else {
234
+ //$update_ar['post_date'] = 'post_date';
235
+ // $update_ar['post_date_gmt'] = 'post_date_gmt';
236
+ }
237
+ $update_ar['post_modified'] = $post_date;
238
+ $update_ar['post_modified_gmt'] = $post_date_gmt;
239
+
240
+ $updated = $wpdb->update( $wpdb->posts, $update_ar , array('ID' => $this->post_id) );
241
+
242
+ wp_cache_delete($this->post_id, 'posts');
243
+
244
+
245
+ /* $sql = $wpdb->prepare(
246
+ "UPDATE $table_name SET post_date = '$post_date', post_date_gmt = '$post_date_gmt' WHERE ID = %d;",
247
+ $ID
248
+ );
249
+ $wpdb->query($sql); */
250
+ }
251
+
252
+
253
+ protected function doSearchReplace()
254
+ {
255
+ global $wpdb;
256
+
257
+ // Search-and-replace filename in post database
258
+ $current_base_url = emr_get_match_url( $this->source_url );
259
+
260
+ /* Search and replace in WP_POSTS */
261
+ $posts_sql = $wpdb->remove_placeholder_escape($wpdb->prepare(
262
+ "SELECT ID, post_content FROM $wpdb->posts WHERE post_status = 'publish' AND post_content LIKE %s;",
263
+ '%' . $current_base_url . '%'));
264
+
265
+ //INNER JOIN ' . $wpdb->posts . ' on ' . $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id
266
+
267
+ $postmeta_sql = 'SELECT meta_id, post_id, meta_value FROM ' . $wpdb->postmeta . '
268
+ WHERE post_id in (SELECT ID from '. $wpdb->posts . ' where post_status = "publish") AND meta_value like %s ';
269
+ $postmeta_sql = $wpdb->remove_placeholder_escape($wpdb->prepare($postmeta_sql, '%' . $current_base_url . '%'));
270
+
271
+ $rsmeta = $wpdb->get_results($postmeta_sql, ARRAY_A);
272
+ $rs = $wpdb->get_results( $posts_sql, ARRAY_A );
273
+
274
+ $number_of_updates = 0;
275
+
276
+ $search_urls = emr_get_file_urls( $this->source_url, $this->source_metadata );
277
+ $replace_urls = emr_get_file_urls( $this->target_url, $this->target_metadata );
278
+ $replace_urls = array_values(emr_normalize_file_urls( $search_urls, $replace_urls ));
279
+
280
+ if ( ! empty( $rs ) ) {
281
+
282
+ foreach ( $rs AS $rows ) {
283
+ $number_of_updates = $number_of_updates + 1;
284
+ // replace old URLs with new URLs.
285
+ $post_content = $rows["post_content"];
286
+ $post_content = str_replace( $search_urls, $replace_urls, $post_content );
287
+
288
+ $sql = $wpdb->prepare(
289
+ "UPDATE $wpdb->posts SET post_content = %s WHERE ID = %d;",
290
+ array($post_content, $rows["ID"])
291
+ );
292
+ // echo "$sql <BR>";
293
+ $wpdb->query( $sql );
294
+ }
295
+ foreach ($rsmeta as $row)
296
+ {
297
+ $number_of_updates++;
298
+ $content = $row['meta_value'];
299
+ $content = str_replace($search_urls, $replace_urls, $content);
300
+
301
+ $sql = $wpdb->prepare('UPDATE ' . $wpdb->postmeta . ' SET meta_value = %s WHERE meta_id = %d', $content, $row['meta_id'] );
302
+ $wpdb->query($sql);
303
+ }
304
+
305
+ }
306
+
307
+ } // doSearchReplace
308
+
309
+ } // class
css/admin.css ADDED
@@ -0,0 +1,834 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .ui-widget-content {
2
+ border: 1px solid #dddddd;
3
+ background: #ffffff;
4
+ color: #333333; }
5
+
6
+ .ui-widget-overlay {
7
+ position: fixed;
8
+ top: 0;
9
+ left: 0;
10
+ width: 100%;
11
+ height: 100%; }
12
+
13
+ .ui-datepicker {
14
+ width: 17em;
15
+ padding: .2em .2em 0;
16
+ display: none; }
17
+
18
+ .ui-datepicker .ui-datepicker-header {
19
+ position: relative;
20
+ padding: .2em 0; }
21
+
22
+ .ui-datepicker .ui-datepicker-prev,
23
+ .ui-datepicker .ui-datepicker-next {
24
+ position: absolute;
25
+ top: 2px;
26
+ width: 1.8em;
27
+ height: 1.8em; }
28
+
29
+ .ui-datepicker .ui-datepicker-prev-hover,
30
+ .ui-datepicker .ui-datepicker-next-hover {
31
+ top: 1px; }
32
+
33
+ .ui-datepicker .ui-datepicker-prev {
34
+ left: 2px; }
35
+
36
+ .ui-datepicker .ui-datepicker-next {
37
+ right: 2px; }
38
+
39
+ .ui-datepicker .ui-datepicker-prev-hover {
40
+ left: 1px; }
41
+
42
+ .ui-datepicker .ui-datepicker-next-hover {
43
+ right: 1px; }
44
+
45
+ .ui-datepicker .ui-datepicker-prev span,
46
+ .ui-datepicker .ui-datepicker-next span {
47
+ display: block;
48
+ position: absolute;
49
+ left: 50%;
50
+ margin-left: -8px;
51
+ top: 50%;
52
+ margin-top: -8px; }
53
+
54
+ .ui-datepicker .ui-datepicker-title {
55
+ margin: 0 2.3em;
56
+ line-height: 1.8em;
57
+ text-align: center; }
58
+
59
+ .ui-datepicker .ui-datepicker-title select {
60
+ font-size: 1em;
61
+ margin: 1px 0; }
62
+
63
+ .ui-datepicker select.ui-datepicker-month,
64
+ .ui-datepicker select.ui-datepicker-year {
65
+ width: 45%; }
66
+
67
+ .ui-datepicker table {
68
+ width: 100%;
69
+ font-size: .9em;
70
+ border-collapse: collapse;
71
+ margin: 0 0 .4em; }
72
+
73
+ .ui-datepicker th {
74
+ padding: .7em .3em;
75
+ text-align: center;
76
+ font-weight: bold;
77
+ border: 0; }
78
+
79
+ .ui-datepicker td {
80
+ border: 0;
81
+ padding: 1px; }
82
+
83
+ .ui-datepicker td span,
84
+ .ui-datepicker td a {
85
+ display: block;
86
+ padding: .2em;
87
+ text-align: center;
88
+ text-decoration: none; }
89
+
90
+ .ui-datepicker .ui-datepicker-buttonpane {
91
+ background-image: none;
92
+ margin: .7em 0 0 0;
93
+ padding: 0 .2em;
94
+ border-left: 0;
95
+ border-right: 0;
96
+ border-bottom: 0; }
97
+
98
+ .ui-datepicker .ui-datepicker-buttonpane button {
99
+ float: right;
100
+ margin: .5em .2em .4em;
101
+ cursor: pointer;
102
+ padding: .2em .6em .3em .6em;
103
+ width: auto;
104
+ overflow: visible; }
105
+
106
+ .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
107
+ float: left; }
108
+
109
+ /* with multiple calendars */
110
+ .ui-datepicker.ui-datepicker-multi {
111
+ width: auto; }
112
+
113
+ .ui-datepicker-multi .ui-datepicker-group {
114
+ float: left; }
115
+
116
+ .ui-datepicker-multi .ui-datepicker-group table {
117
+ width: 95%;
118
+ margin: 0 auto .4em; }
119
+
120
+ .ui-datepicker-multi-2 .ui-datepicker-group {
121
+ width: 50%; }
122
+
123
+ .ui-datepicker-multi-3 .ui-datepicker-group {
124
+ width: 33.3%; }
125
+
126
+ .ui-datepicker-multi-4 .ui-datepicker-group {
127
+ width: 25%; }
128
+
129
+ .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
130
+ .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
131
+ border-left-width: 0; }
132
+
133
+ .ui-datepicker-multi .ui-datepicker-buttonpane {
134
+ clear: left; }
135
+
136
+ .ui-datepicker-row-break {
137
+ clear: both;
138
+ width: 100%;
139
+ font-size: 0; }
140
+
141
+ /* RTL support */
142
+ .ui-datepicker-rtl {
143
+ direction: rtl; }
144
+
145
+ .ui-datepicker-rtl .ui-datepicker-prev {
146
+ right: 2px;
147
+ left: auto; }
148
+
149
+ .ui-datepicker-rtl .ui-datepicker-next {
150
+ left: 2px;
151
+ right: auto; }
152
+
153
+ .ui-datepicker-rtl .ui-datepicker-prev:hover {
154
+ right: 1px;
155
+ left: auto; }
156
+
157
+ .ui-datepicker-rtl .ui-datepicker-next:hover {
158
+ left: 1px;
159
+ right: auto; }
160
+
161
+ .ui-datepicker-rtl .ui-datepicker-buttonpane {
162
+ clear: right; }
163
+
164
+ .ui-datepicker-rtl .ui-datepicker-buttonpane button {
165
+ float: left; }
166
+
167
+ .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
168
+ .ui-datepicker-rtl .ui-datepicker-group {
169
+ float: right; }
170
+
171
+ .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
172
+ .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
173
+ border-right-width: 0;
174
+ border-left-width: 1px; }
175
+
176
+ /* Icons */
177
+ .ui-datepicker .ui-icon {
178
+ display: block;
179
+ text-indent: -99999px;
180
+ overflow: hidden;
181
+ background-repeat: no-repeat;
182
+ left: .5em;
183
+ top: .3em; }
184
+
185
+ .ui-icon {
186
+ width: 16px;
187
+ height: 16px; }
188
+
189
+ .ui-icon,
190
+ .ui-widget-content .ui-icon {
191
+ background-image: url("../img/ui-icons_444444_256x240.png"); }
192
+
193
+ .ui-widget-header .ui-icon {
194
+ background-image: url("../img/ui-icons_444444_256x240.png"); }
195
+
196
+ .ui-state-hover .ui-icon,
197
+ .ui-state-focus .ui-icon,
198
+ .ui-button:hover .ui-icon,
199
+ .ui-button:focus .ui-icon {
200
+ background-image: url("../img/ui-icons_555555_256x240.png"); }
201
+
202
+ .ui-state-active .ui-icon,
203
+ .ui-button:active .ui-icon {
204
+ background-image: url("../img/ui-icons_ffffff_256x240.png"); }
205
+
206
+ .ui-state-highlight .ui-icon,
207
+ .ui-button .ui-state-highlight.ui-icon {
208
+ background-image: url("../img/ui-icons_777620_256x240.png"); }
209
+
210
+ /* positioning */
211
+ .ui-icon-blank {
212
+ background-position: 16px 16px; }
213
+
214
+ .ui-icon-caret-1-n {
215
+ background-position: 0 0; }
216
+
217
+ .ui-icon-caret-1-ne {
218
+ background-position: -16px 0; }
219
+
220
+ .ui-icon-caret-1-e {
221
+ background-position: -32px 0; }
222
+
223
+ .ui-icon-caret-1-se {
224
+ background-position: -48px 0; }
225
+
226
+ .ui-icon-caret-1-s {
227
+ background-position: -65px 0; }
228
+
229
+ .ui-icon-caret-1-sw {
230
+ background-position: -80px 0; }
231
+
232
+ .ui-icon-caret-1-w {
233
+ background-position: -96px 0; }
234
+
235
+ .ui-icon-caret-1-nw {
236
+ background-position: -112px 0; }
237
+
238
+ .ui-icon-caret-2-n-s {
239
+ background-position: -128px 0; }
240
+
241
+ .ui-icon-caret-2-e-w {
242
+ background-position: -144px 0; }
243
+
244
+ .ui-icon-triangle-1-n {
245
+ background-position: 0 -16px; }
246
+
247
+ .ui-icon-triangle-1-ne {
248
+ background-position: -16px -16px; }
249
+
250
+ .ui-icon-triangle-1-e {
251
+ background-position: -32px -16px; }
252
+
253
+ .ui-icon-triangle-1-se {
254
+ background-position: -48px -16px; }
255
+
256
+ .ui-icon-triangle-1-s {
257
+ background-position: -65px -16px; }
258
+
259
+ .ui-icon-triangle-1-sw {
260
+ background-position: -80px -16px; }
261
+
262
+ .ui-icon-triangle-1-w {
263
+ background-position: -96px -16px; }
264
+
265
+ .ui-icon-triangle-1-nw {
266
+ background-position: -112px -16px; }
267
+
268
+ .ui-icon-triangle-2-n-s {
269
+ background-position: -128px -16px; }
270
+
271
+ .ui-icon-triangle-2-e-w {
272
+ background-position: -144px -16px; }
273
+
274
+ .ui-icon-arrow-1-n {
275
+ background-position: 0 -32px; }
276
+
277
+ .ui-icon-arrow-1-ne {
278
+ background-position: -16px -32px; }
279
+
280
+ .ui-icon-arrow-1-e {
281
+ background-position: -32px -32px; }
282
+
283
+ .ui-icon-arrow-1-se {
284
+ background-position: -48px -32px; }
285
+
286
+ .ui-icon-arrow-1-s {
287
+ background-position: -65px -32px; }
288
+
289
+ .ui-icon-arrow-1-sw {
290
+ background-position: -80px -32px; }
291
+
292
+ .ui-icon-arrow-1-w {
293
+ background-position: -96px -32px; }
294
+
295
+ .ui-icon-arrow-1-nw {
296
+ background-position: -112px -32px; }
297
+
298
+ .ui-icon-arrow-2-n-s {
299
+ background-position: -128px -32px; }
300
+
301
+ .ui-icon-arrow-2-ne-sw {
302
+ background-position: -144px -32px; }
303
+
304
+ .ui-icon-arrow-2-e-w {
305
+ background-position: -160px -32px; }
306
+
307
+ .ui-icon-arrow-2-se-nw {
308
+ background-position: -176px -32px; }
309
+
310
+ .ui-icon-arrowstop-1-n {
311
+ background-position: -192px -32px; }
312
+
313
+ .ui-icon-arrowstop-1-e {
314
+ background-position: -208px -32px; }
315
+
316
+ .ui-icon-arrowstop-1-s {
317
+ background-position: -224px -32px; }
318
+
319
+ .ui-icon-arrowstop-1-w {
320
+ background-position: -240px -32px; }
321
+
322
+ .ui-icon-arrowthick-1-n {
323
+ background-position: 1px -48px; }
324
+
325
+ .ui-icon-arrowthick-1-ne {
326
+ background-position: -16px -48px; }
327
+
328
+ .ui-icon-arrowthick-1-e {
329
+ background-position: -32px -48px; }
330
+
331
+ .ui-icon-arrowthick-1-se {
332
+ background-position: -48px -48px; }
333
+
334
+ .ui-icon-arrowthick-1-s {
335
+ background-position: -64px -48px; }
336
+
337
+ .ui-icon-arrowthick-1-sw {
338
+ background-position: -80px -48px; }
339
+
340
+ .ui-icon-arrowthick-1-w {
341
+ background-position: -96px -48px; }
342
+
343
+ .ui-icon-arrowthick-1-nw {
344
+ background-position: -112px -48px; }
345
+
346
+ .ui-icon-arrowthick-2-n-s {
347
+ background-position: -128px -48px; }
348
+
349
+ .ui-icon-arrowthick-2-ne-sw {
350
+ background-position: -144px -48px; }
351
+
352
+ .ui-icon-arrowthick-2-e-w {
353
+ background-position: -160px -48px; }
354
+
355
+ .ui-icon-arrowthick-2-se-nw {
356
+ background-position: -176px -48px; }
357
+
358
+ .ui-icon-arrowthickstop-1-n {
359
+ background-position: -192px -48px; }
360
+
361
+ .ui-icon-arrowthickstop-1-e {
362
+ background-position: -208px -48px; }
363
+
364
+ .ui-icon-arrowthickstop-1-s {
365
+ background-position: -224px -48px; }
366
+
367
+ .ui-icon-arrowthickstop-1-w {
368
+ background-position: -240px -48px; }
369
+
370
+ .ui-icon-arrowreturnthick-1-w {
371
+ background-position: 0 -64px; }
372
+
373
+ .ui-icon-arrowreturnthick-1-n {
374
+ background-position: -16px -64px; }
375
+
376
+ .ui-icon-arrowreturnthick-1-e {
377
+ background-position: -32px -64px; }
378
+
379
+ .ui-icon-arrowreturnthick-1-s {
380
+ background-position: -48px -64px; }
381
+
382
+ .ui-icon-arrowreturn-1-w {
383
+ background-position: -64px -64px; }
384
+
385
+ .ui-icon-arrowreturn-1-n {
386
+ background-position: -80px -64px; }
387
+
388
+ .ui-icon-arrowreturn-1-e {
389
+ background-position: -96px -64px; }
390
+
391
+ .ui-icon-arrowreturn-1-s {
392
+ background-position: -112px -64px; }
393
+
394
+ .ui-icon-arrowrefresh-1-w {
395
+ background-position: -128px -64px; }
396
+
397
+ .ui-icon-arrowrefresh-1-n {
398
+ background-position: -144px -64px; }
399
+
400
+ .ui-icon-arrowrefresh-1-e {
401
+ background-position: -160px -64px; }
402
+
403
+ .ui-icon-arrowrefresh-1-s {
404
+ background-position: -176px -64px; }
405
+
406
+ .ui-icon-arrow-4 {
407
+ background-position: 0 -80px; }
408
+
409
+ .ui-icon-arrow-4-diag {
410
+ background-position: -16px -80px; }
411
+
412
+ .ui-icon-extlink {
413
+ background-position: -32px -80px; }
414
+
415
+ .ui-icon-newwin {
416
+ background-position: -48px -80px; }
417
+
418
+ .ui-icon-refresh {
419
+ background-position: -64px -80px; }
420
+
421
+ .ui-icon-shuffle {
422
+ background-position: -80px -80px; }
423
+
424
+ .ui-icon-transfer-e-w {
425
+ background-position: -96px -80px; }
426
+
427
+ .ui-icon-transferthick-e-w {
428
+ background-position: -112px -80px; }
429
+
430
+ .ui-icon-folder-collapsed {
431
+ background-position: 0 -96px; }
432
+
433
+ .ui-icon-folder-open {
434
+ background-position: -16px -96px; }
435
+
436
+ .ui-icon-document {
437
+ background-position: -32px -96px; }
438
+
439
+ .ui-icon-document-b {
440
+ background-position: -48px -96px; }
441
+
442
+ .ui-icon-note {
443
+ background-position: -64px -96px; }
444
+
445
+ .ui-icon-mail-closed {
446
+ background-position: -80px -96px; }
447
+
448
+ .ui-icon-mail-open {
449
+ background-position: -96px -96px; }
450
+
451
+ .ui-icon-suitcase {
452
+ background-position: -112px -96px; }
453
+
454
+ .ui-icon-comment {
455
+ background-position: -128px -96px; }
456
+
457
+ .ui-icon-person {
458
+ background-position: -144px -96px; }
459
+
460
+ .ui-icon-print {
461
+ background-position: -160px -96px; }
462
+
463
+ .ui-icon-trash {
464
+ background-position: -176px -96px; }
465
+
466
+ .ui-icon-locked {
467
+ background-position: -192px -96px; }
468
+
469
+ .ui-icon-unlocked {
470
+ background-position: -208px -96px; }
471
+
472
+ .ui-icon-bookmark {
473
+ background-position: -224px -96px; }
474
+
475
+ .ui-icon-tag {
476
+ background-position: -240px -96px; }
477
+
478
+ .ui-icon-home {
479
+ background-position: 0 -112px; }
480
+
481
+ .ui-icon-flag {
482
+ background-position: -16px -112px; }
483
+
484
+ .ui-icon-calendar {
485
+ background-position: -32px -112px; }
486
+
487
+ .ui-icon-cart {
488
+ background-position: -48px -112px; }
489
+
490
+ .ui-icon-pencil {
491
+ background-position: -64px -112px; }
492
+
493
+ .ui-icon-clock {
494
+ background-position: -80px -112px; }
495
+
496
+ .ui-icon-disk {
497
+ background-position: -96px -112px; }
498
+
499
+ .ui-icon-calculator {
500
+ background-position: -112px -112px; }
501
+
502
+ .ui-icon-zoomin {
503
+ background-position: -128px -112px; }
504
+
505
+ .ui-icon-zoomout {
506
+ background-position: -144px -112px; }
507
+
508
+ .ui-icon-search {
509
+ background-position: -160px -112px; }
510
+
511
+ .ui-icon-wrench {
512
+ background-position: -176px -112px; }
513
+
514
+ .ui-icon-gear {
515
+ background-position: -192px -112px; }
516
+
517
+ .ui-icon-heart {
518
+ background-position: -208px -112px; }
519
+
520
+ .ui-icon-star {
521
+ background-position: -224px -112px; }
522
+
523
+ .ui-icon-link {
524
+ background-position: -240px -112px; }
525
+
526
+ .ui-icon-cancel {
527
+ background-position: 0 -128px; }
528
+
529
+ .ui-icon-plus {
530
+ background-position: -16px -128px; }
531
+
532
+ .ui-icon-plusthick {
533
+ background-position: -32px -128px; }
534
+
535
+ .ui-icon-minus {
536
+ background-position: -48px -128px; }
537
+
538
+ .ui-icon-minusthick {
539
+ background-position: -64px -128px; }
540
+
541
+ .ui-icon-close {
542
+ background-position: -80px -128px; }
543
+
544
+ .ui-icon-closethick {
545
+ background-position: -96px -128px; }
546
+
547
+ .ui-icon-key {
548
+ background-position: -112px -128px; }
549
+
550
+ .ui-icon-lightbulb {
551
+ background-position: -128px -128px; }
552
+
553
+ .ui-icon-scissors {
554
+ background-position: -144px -128px; }
555
+
556
+ .ui-icon-clipboard {
557
+ background-position: -160px -128px; }
558
+
559
+ .ui-icon-copy {
560
+ background-position: -176px -128px; }
561
+
562
+ .ui-icon-contact {
563
+ background-position: -192px -128px; }
564
+
565
+ .ui-icon-image {
566
+ background-position: -208px -128px; }
567
+
568
+ .ui-icon-video {
569
+ background-position: -224px -128px; }
570
+
571
+ .ui-icon-script {
572
+ background-position: -240px -128px; }
573
+
574
+ .ui-icon-alert {
575
+ background-position: 0 -144px; }
576
+
577
+ .ui-icon-info {
578
+ background-position: -16px -144px; }
579
+
580
+ .ui-icon-notice {
581
+ background-position: -32px -144px; }
582
+
583
+ .ui-icon-help {
584
+ background-position: -48px -144px; }
585
+
586
+ .ui-icon-check {
587
+ background-position: -64px -144px; }
588
+
589
+ .ui-icon-bullet {
590
+ background-position: -80px -144px; }
591
+
592
+ .ui-icon-radio-on {
593
+ background-position: -96px -144px; }
594
+
595
+ .ui-icon-radio-off {
596
+ background-position: -112px -144px; }
597
+
598
+ .ui-icon-pin-w {
599
+ background-position: -128px -144px; }
600
+
601
+ .ui-icon-pin-s {
602
+ background-position: -144px -144px; }
603
+
604
+ .ui-icon-play {
605
+ background-position: 0 -160px; }
606
+
607
+ .ui-icon-pause {
608
+ background-position: -16px -160px; }
609
+
610
+ .ui-icon-seek-next {
611
+ background-position: -32px -160px; }
612
+
613
+ .ui-icon-seek-prev {
614
+ background-position: -48px -160px; }
615
+
616
+ .ui-icon-seek-end {
617
+ background-position: -64px -160px; }
618
+
619
+ .ui-icon-seek-start {
620
+ background-position: -80px -160px; }
621
+
622
+ /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
623
+ .ui-icon-seek-first {
624
+ background-position: -80px -160px; }
625
+
626
+ .ui-icon-stop {
627
+ background-position: -96px -160px; }
628
+
629
+ .ui-icon-eject {
630
+ background-position: -112px -160px; }
631
+
632
+ .ui-icon-volume-off {
633
+ background-position: -128px -160px; }
634
+
635
+ .ui-icon-volume-on {
636
+ background-position: -144px -160px; }
637
+
638
+ .ui-icon-power {
639
+ background-position: 0 -176px; }
640
+
641
+ .ui-icon-signal-diag {
642
+ background-position: -16px -176px; }
643
+
644
+ .ui-icon-signal {
645
+ background-position: -32px -176px; }
646
+
647
+ .ui-icon-battery-0 {
648
+ background-position: -48px -176px; }
649
+
650
+ .ui-icon-battery-1 {
651
+ background-position: -64px -176px; }
652
+
653
+ .ui-icon-battery-2 {
654
+ background-position: -80px -176px; }
655
+
656
+ .ui-icon-battery-3 {
657
+ background-position: -96px -176px; }
658
+
659
+ .ui-icon-circle-plus {
660
+ background-position: 0 -192px; }
661
+
662
+ .ui-icon-circle-minus {
663
+ background-position: -16px -192px; }
664
+
665
+ .ui-icon-circle-close {
666
+ background-position: -32px -192px; }
667
+
668
+ .ui-icon-circle-triangle-e {
669
+ background-position: -48px -192px; }
670
+
671
+ .ui-icon-circle-triangle-s {
672
+ background-position: -64px -192px; }
673
+
674
+ .ui-icon-circle-triangle-w {
675
+ background-position: -80px -192px; }
676
+
677
+ .ui-icon-circle-triangle-n {
678
+ background-position: -96px -192px; }
679
+
680
+ .ui-icon-circle-arrow-e {
681
+ background-position: -112px -192px; }
682
+
683
+ .ui-icon-circle-arrow-s {
684
+ background-position: -128px -192px; }
685
+
686
+ .ui-icon-circle-arrow-w {
687
+ background-position: -144px -192px; }
688
+
689
+ .ui-icon-circle-arrow-n {
690
+ background-position: -160px -192px; }
691
+
692
+ .ui-icon-circle-zoomin {
693
+ background-position: -176px -192px; }
694
+
695
+ .ui-icon-circle-zoomout {
696
+ background-position: -192px -192px; }
697
+
698
+ .ui-icon-circle-check {
699
+ background-position: -208px -192px; }
700
+
701
+ .ui-icon-circlesmall-plus {
702
+ background-position: 0 -208px; }
703
+
704
+ .ui-icon-circlesmall-minus {
705
+ background-position: -16px -208px; }
706
+
707
+ .ui-icon-circlesmall-close {
708
+ background-position: -32px -208px; }
709
+
710
+ .ui-icon-squaresmall-plus {
711
+ background-position: -48px -208px; }
712
+
713
+ .ui-icon-squaresmall-minus {
714
+ background-position: -64px -208px; }
715
+
716
+ .ui-icon-squaresmall-close {
717
+ background-position: -80px -208px; }
718
+
719
+ .ui-icon-grip-dotted-vertical {
720
+ background-position: 0 -224px; }
721
+
722
+ .ui-icon-grip-dotted-horizontal {
723
+ background-position: -16px -224px; }
724
+
725
+ .ui-icon-grip-solid-vertical {
726
+ background-position: -32px -224px; }
727
+
728
+ .ui-icon-grip-solid-horizontal {
729
+ background-position: -48px -224px; }
730
+
731
+ .ui-icon-gripsmall-diagonal-se {
732
+ background-position: -64px -224px; }
733
+
734
+ .ui-icon-grip-diagonal-se {
735
+ background-position: -80px -224px; }
736
+
737
+ /* Corner radius */
738
+ .ui-corner-all,
739
+ .ui-corner-top,
740
+ .ui-corner-left,
741
+ .ui-corner-tl {
742
+ border-top-left-radius: 3px; }
743
+
744
+ .ui-corner-all,
745
+ .ui-corner-top,
746
+ .ui-corner-right,
747
+ .ui-corner-tr {
748
+ border-top-right-radius: 3px; }
749
+
750
+ .ui-corner-all,
751
+ .ui-corner-bottom,
752
+ .ui-corner-left,
753
+ .ui-corner-bl {
754
+ border-bottom-left-radius: 3px; }
755
+
756
+ .ui-corner-all,
757
+ .ui-corner-bottom,
758
+ .ui-corner-right,
759
+ .ui-corner-br {
760
+ border-bottom-right-radius: 3px; }
761
+
762
+ .emr_upload_form .wrapper {
763
+ margin: 15px 0;
764
+ padding: 18px;
765
+ border: 1px solid #ccc; }
766
+ .emr_upload_form .wrapper .section-header {
767
+ font-size: 18px;
768
+ border-bottom: 1px solid #ccc;
769
+ padding: 6px 0;
770
+ margin: 0 0 15px 0; }
771
+ .emr_upload_form .image_chooser.wrapper {
772
+ min-height: 350px; }
773
+ .emr_upload_form .image_chooser.wrapper .image_previews {
774
+ margin: 15px 0; }
775
+ .emr_upload_form .option-flex-wrapper {
776
+ display: flex; }
777
+ .emr_upload_form .replace_type.wrapper {
778
+ flex: 1;
779
+ border: 1px solid #ccc;
780
+ margin: 15px 0; }
781
+ .emr_upload_form .replace_type.wrapper label {
782
+ font-size: 1.2em; }
783
+ .emr_upload_form .options.wrapper {
784
+ flex: 1;
785
+ border: 1px solid #ccc;
786
+ padding: 15px;
787
+ margin: 15px 0 15px 35px; }
788
+ .emr_upload_form .options.wrapper .custom_date .emr_datepicker {
789
+ width: 150px; }
790
+ .emr_upload_form .options.wrapper .custom_date .emr_hour, .emr_upload_form .options.wrapper .custom_date .emr_minute {
791
+ width: 45px; }
792
+ .emr_upload_form .options.wrapper ul li input {
793
+ margin-right: 8px; }
794
+ .emr_upload_form .options.wrapper .option label {
795
+ vertical-align: top; }
796
+ .emr_upload_form .options.wrapper .small {
797
+ font-size: 10px;
798
+ vertical-align: top;
799
+ margin-left: 8px; }
800
+ .emr_upload_form .options.wrapper .custom_date {
801
+ margin: 8px 0 0 25px;
802
+ visibility: hidden;
803
+ opacity: 0; }
804
+ .emr_upload_form .options.wrapper .custom_date span.field-title {
805
+ display: inline-block;
806
+ margin-bottom: 4px;
807
+ color: #444;
808
+ font-size: 12px;
809
+ width: 100%;
810
+ text-align: left;
811
+ vertical-align: middle;
812
+ line-height: 26px; }
813
+ .emr_upload_form .options.wrapper .custom_date span.field-title::before {
814
+ font-size: 20px;
815
+ vertical-align: top;
816
+ margin-right: 4px; }
817
+ .emr_upload_form .form_controls.wrapper {
818
+ clear: both;
819
+ margin: 8px 0 15px 0;
820
+ border: 0;
821
+ padding: 0; }
822
+ .emr_upload_form .form_controls.wrapper .button {
823
+ padding-left: 20px;
824
+ padding-right: 20px; }
825
+ .emr_upload_form .shortpixel-notice {
826
+ background: #fff;
827
+ width: 250px;
828
+ min-height: 270px;
829
+ border: 1px solid #ccc;
830
+ padding: 15px;
831
+ margin: 0 0 10px;
832
+ float: right; }
833
+ .emr_upload_form .shortpixel-notice h3 {
834
+ line-height: 1.3em; }
css/admin.rtl.css ADDED
@@ -0,0 +1,834 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .ui-widget-content {
2
+ border: 1px solid #dddddd;
3
+ background: #ffffff;
4
+ color: #333333; }
5
+
6
+ .ui-widget-overlay {
7
+ position: fixed;
8
+ top: 0;
9
+ right: 0;
10
+ width: 100%;
11
+ height: 100%; }
12
+
13
+ .ui-datepicker {
14
+ width: 17em;
15
+ padding: .2em .2em 0;
16
+ display: none; }
17
+
18
+ .ui-datepicker .ui-datepicker-header {
19
+ position: relative;
20
+ padding: .2em 0; }
21
+
22
+ .ui-datepicker .ui-datepicker-prev,
23
+ .ui-datepicker .ui-datepicker-next {
24
+ position: absolute;
25
+ top: 2px;
26
+ width: 1.8em;
27
+ height: 1.8em; }
28
+
29
+ .ui-datepicker .ui-datepicker-prev-hover,
30
+ .ui-datepicker .ui-datepicker-next-hover {
31
+ top: 1px; }
32
+
33
+ .ui-datepicker .ui-datepicker-prev {
34
+ right: 2px; }
35
+
36
+ .ui-datepicker .ui-datepicker-next {
37
+ left: 2px; }
38
+
39
+ .ui-datepicker .ui-datepicker-prev-hover {
40
+ right: 1px; }
41
+
42
+ .ui-datepicker .ui-datepicker-next-hover {
43
+ left: 1px; }
44
+
45
+ .ui-datepicker .ui-datepicker-prev span,
46
+ .ui-datepicker .ui-datepicker-next span {
47
+ display: block;
48
+ position: absolute;
49
+ right: 50%;
50
+ margin-right: -8px;
51
+ top: 50%;
52
+ margin-top: -8px; }
53
+
54
+ .ui-datepicker .ui-datepicker-title {
55
+ margin: 0 2.3em;
56
+ line-height: 1.8em;
57
+ text-align: center; }
58
+
59
+ .ui-datepicker .ui-datepicker-title select {
60
+ font-size: 1em;
61
+ margin: 1px 0; }
62
+
63
+ .ui-datepicker select.ui-datepicker-month,
64
+ .ui-datepicker select.ui-datepicker-year {
65
+ width: 45%; }
66
+
67
+ .ui-datepicker table {
68
+ width: 100%;
69
+ font-size: .9em;
70
+ border-collapse: collapse;
71
+ margin: 0 0 .4em; }
72
+
73
+ .ui-datepicker th {
74
+ padding: .7em .3em;
75
+ text-align: center;
76
+ font-weight: bold;
77
+ border: 0; }
78
+
79
+ .ui-datepicker td {
80
+ border: 0;
81
+ padding: 1px; }
82
+
83
+ .ui-datepicker td span,
84
+ .ui-datepicker td a {
85
+ display: block;
86
+ padding: .2em;
87
+ text-align: center;
88
+ text-decoration: none; }
89
+
90
+ .ui-datepicker .ui-datepicker-buttonpane {
91
+ background-image: none;
92
+ margin: .7em 0 0 0;
93
+ padding: 0 .2em;
94
+ border-right: 0;
95
+ border-left: 0;
96
+ border-bottom: 0; }
97
+
98
+ .ui-datepicker .ui-datepicker-buttonpane button {
99
+ float: left;
100
+ margin: .5em .2em .4em;
101
+ cursor: pointer;
102
+ padding: .2em .6em .3em .6em;
103
+ width: auto;
104
+ overflow: visible; }
105
+
106
+ .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
107
+ float: right; }
108
+
109
+ /* with multiple calendars */
110
+ .ui-datepicker.ui-datepicker-multi {
111
+ width: auto; }
112
+
113
+ .ui-datepicker-multi .ui-datepicker-group {
114
+ float: right; }
115
+
116
+ .ui-datepicker-multi .ui-datepicker-group table {
117
+ width: 95%;
118
+ margin: 0 auto .4em; }
119
+
120
+ .ui-datepicker-multi-2 .ui-datepicker-group {
121
+ width: 50%; }
122
+
123
+ .ui-datepicker-multi-3 .ui-datepicker-group {
124
+ width: 33.3%; }
125
+
126
+ .ui-datepicker-multi-4 .ui-datepicker-group {
127
+ width: 25%; }
128
+
129
+ .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
130
+ .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
131
+ border-right-width: 0; }
132
+
133
+ .ui-datepicker-multi .ui-datepicker-buttonpane {
134
+ clear: right; }
135
+
136
+ .ui-datepicker-row-break {
137
+ clear: both;
138
+ width: 100%;
139
+ font-size: 0; }
140
+
141
+ /* RTL support */
142
+ .ui-datepicker-rtl {
143
+ direction: ltr; }
144
+
145
+ .ui-datepicker-rtl .ui-datepicker-prev {
146
+ left: 2px;
147
+ right: auto; }
148
+
149
+ .ui-datepicker-rtl .ui-datepicker-next {
150
+ right: 2px;
151
+ left: auto; }
152
+
153
+ .ui-datepicker-rtl .ui-datepicker-prev:hover {
154
+ left: 1px;
155
+ right: auto; }
156
+
157
+ .ui-datepicker-rtl .ui-datepicker-next:hover {
158
+ right: 1px;
159
+ left: auto; }
160
+
161
+ .ui-datepicker-rtl .ui-datepicker-buttonpane {
162
+ clear: left; }
163
+
164
+ .ui-datepicker-rtl .ui-datepicker-buttonpane button {
165
+ float: right; }
166
+
167
+ .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
168
+ .ui-datepicker-rtl .ui-datepicker-group {
169
+ float: left; }
170
+
171
+ .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
172
+ .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
173
+ border-left-width: 0;
174
+ border-right-width: 1px; }
175
+
176
+ /* Icons */
177
+ .ui-datepicker .ui-icon {
178
+ display: block;
179
+ text-indent: -99999px;
180
+ overflow: hidden;
181
+ background-repeat: no-repeat;
182
+ right: .5em;
183
+ top: .3em; }
184
+
185
+ .ui-icon {
186
+ width: 16px;
187
+ height: 16px; }
188
+
189
+ .ui-icon,
190
+ .ui-widget-content .ui-icon {
191
+ background-image: url("../img/ui-icons_444444_256x240.png"); }
192
+
193
+ .ui-widget-header .ui-icon {
194
+ background-image: url("../img/ui-icons_444444_256x240.png"); }
195
+
196
+ .ui-state-hover .ui-icon,
197
+ .ui-state-focus .ui-icon,
198
+ .ui-button:hover .ui-icon,
199
+ .ui-button:focus .ui-icon {
200
+ background-image: url("../img/ui-icons_555555_256x240.png"); }
201
+
202
+ .ui-state-active .ui-icon,
203
+ .ui-button:active .ui-icon {
204
+ background-image: url("../img/ui-icons_ffffff_256x240.png"); }
205
+
206
+ .ui-state-highlight .ui-icon,
207
+ .ui-button .ui-state-highlight.ui-icon {
208
+ background-image: url("../img/ui-icons_777620_256x240.png"); }
209
+
210
+ /* positioning */
211
+ .ui-icon-blank {
212
+ background-position: 16px 16px; }
213
+
214
+ .ui-icon-caret-1-n {
215
+ background-position: 100% 0; }
216
+
217
+ .ui-icon-caret-1-ne {
218
+ background-position: -16px 0; }
219
+
220
+ .ui-icon-caret-1-e {
221
+ background-position: -32px 0; }
222
+
223
+ .ui-icon-caret-1-se {
224
+ background-position: -48px 0; }
225
+
226
+ .ui-icon-caret-1-s {
227
+ background-position: -65px 0; }
228
+
229
+ .ui-icon-caret-1-sw {
230
+ background-position: -80px 0; }
231
+
232
+ .ui-icon-caret-1-w {
233
+ background-position: -96px 0; }
234
+
235
+ .ui-icon-caret-1-nw {
236
+ background-position: -112px 0; }
237
+
238
+ .ui-icon-caret-2-n-s {
239
+ background-position: -128px 0; }
240
+
241
+ .ui-icon-caret-2-e-w {
242
+ background-position: -144px 0; }
243
+
244
+ .ui-icon-triangle-1-n {
245
+ background-position: 100% -16px; }
246
+
247
+ .ui-icon-triangle-1-ne {
248
+ background-position: -16px -16px; }
249
+
250
+ .ui-icon-triangle-1-e {
251
+ background-position: -32px -16px; }
252
+
253
+ .ui-icon-triangle-1-se {
254
+ background-position: -48px -16px; }
255
+
256
+ .ui-icon-triangle-1-s {
257
+ background-position: -65px -16px; }
258
+
259
+ .ui-icon-triangle-1-sw {
260
+ background-position: -80px -16px; }
261
+
262
+ .ui-icon-triangle-1-w {
263
+ background-position: -96px -16px; }
264
+
265
+ .ui-icon-triangle-1-nw {
266
+ background-position: -112px -16px; }
267
+
268
+ .ui-icon-triangle-2-n-s {
269
+ background-position: -128px -16px; }
270
+
271
+ .ui-icon-triangle-2-e-w {
272
+ background-position: -144px -16px; }
273
+
274
+ .ui-icon-arrow-1-n {
275
+ background-position: 100% -32px; }
276
+
277
+ .ui-icon-arrow-1-ne {
278
+ background-position: -16px -32px; }
279
+
280
+ .ui-icon-arrow-1-e {
281
+ background-position: -32px -32px; }
282
+
283
+ .ui-icon-arrow-1-se {
284
+ background-position: -48px -32px; }
285
+
286
+ .ui-icon-arrow-1-s {
287
+ background-position: -65px -32px; }
288
+
289
+ .ui-icon-arrow-1-sw {
290
+ background-position: -80px -32px; }
291
+
292
+ .ui-icon-arrow-1-w {
293
+ background-position: -96px -32px; }
294
+
295
+ .ui-icon-arrow-1-nw {
296
+ background-position: -112px -32px; }
297
+
298
+ .ui-icon-arrow-2-n-s {
299
+ background-position: -128px -32px; }
300
+
301
+ .ui-icon-arrow-2-ne-sw {
302
+ background-position: -144px -32px; }
303
+
304
+ .ui-icon-arrow-2-e-w {
305
+ background-position: -160px -32px; }
306
+
307
+ .ui-icon-arrow-2-se-nw {
308
+ background-position: -176px -32px; }
309
+
310
+ .ui-icon-arrowstop-1-n {
311
+ background-position: -192px -32px; }
312
+
313
+ .ui-icon-arrowstop-1-e {
314
+ background-position: -208px -32px; }
315
+
316
+ .ui-icon-arrowstop-1-s {
317
+ background-position: -224px -32px; }
318
+
319
+ .ui-icon-arrowstop-1-w {
320
+ background-position: -240px -32px; }
321
+
322
+ .ui-icon-arrowthick-1-n {
323
+ background-position: 1px -48px; }
324
+
325
+ .ui-icon-arrowthick-1-ne {
326
+ background-position: -16px -48px; }
327
+
328
+ .ui-icon-arrowthick-1-e {
329
+ background-position: -32px -48px; }
330
+
331
+ .ui-icon-arrowthick-1-se {
332
+ background-position: -48px -48px; }
333
+
334
+ .ui-icon-arrowthick-1-s {
335
+ background-position: -64px -48px; }
336
+
337
+ .ui-icon-arrowthick-1-sw {
338
+ background-position: -80px -48px; }
339
+
340
+ .ui-icon-arrowthick-1-w {
341
+ background-position: -96px -48px; }
342
+
343
+ .ui-icon-arrowthick-1-nw {
344
+ background-position: -112px -48px; }
345
+
346
+ .ui-icon-arrowthick-2-n-s {
347
+ background-position: -128px -48px; }
348
+
349
+ .ui-icon-arrowthick-2-ne-sw {
350
+ background-position: -144px -48px; }
351
+
352
+ .ui-icon-arrowthick-2-e-w {
353
+ background-position: -160px -48px; }
354
+
355
+ .ui-icon-arrowthick-2-se-nw {
356
+ background-position: -176px -48px; }
357
+
358
+ .ui-icon-arrowthickstop-1-n {
359
+ background-position: -192px -48px; }
360
+
361
+ .ui-icon-arrowthickstop-1-e {
362
+ background-position: -208px -48px; }
363
+
364
+ .ui-icon-arrowthickstop-1-s {
365
+ background-position: -224px -48px; }
366
+
367
+ .ui-icon-arrowthickstop-1-w {
368
+ background-position: -240px -48px; }
369
+
370
+ .ui-icon-arrowreturnthick-1-w {
371
+ background-position: 100% -64px; }
372
+
373
+ .ui-icon-arrowreturnthick-1-n {
374
+ background-position: -16px -64px; }
375
+
376
+ .ui-icon-arrowreturnthick-1-e {
377
+ background-position: -32px -64px; }
378
+
379
+ .ui-icon-arrowreturnthick-1-s {
380
+ background-position: -48px -64px; }
381
+
382
+ .ui-icon-arrowreturn-1-w {
383
+ background-position: -64px -64px; }
384
+
385
+ .ui-icon-arrowreturn-1-n {
386
+ background-position: -80px -64px; }
387
+
388
+ .ui-icon-arrowreturn-1-e {
389
+ background-position: -96px -64px; }
390
+
391
+ .ui-icon-arrowreturn-1-s {
392
+ background-position: -112px -64px; }
393
+
394
+ .ui-icon-arrowrefresh-1-w {
395
+ background-position: -128px -64px; }
396
+
397
+ .ui-icon-arrowrefresh-1-n {
398
+ background-position: -144px -64px; }
399
+
400
+ .ui-icon-arrowrefresh-1-e {
401
+ background-position: -160px -64px; }
402
+
403
+ .ui-icon-arrowrefresh-1-s {
404
+ background-position: -176px -64px; }
405
+
406
+ .ui-icon-arrow-4 {
407
+ background-position: 100% -80px; }
408
+
409
+ .ui-icon-arrow-4-diag {
410
+ background-position: -16px -80px; }
411
+
412
+ .ui-icon-extlink {
413
+ background-position: -32px -80px; }
414
+
415
+ .ui-icon-newwin {
416
+ background-position: -48px -80px; }
417
+
418
+ .ui-icon-refresh {
419
+ background-position: -64px -80px; }
420
+
421
+ .ui-icon-shuffle {
422
+ background-position: -80px -80px; }
423
+
424
+ .ui-icon-transfer-e-w {
425
+ background-position: -96px -80px; }
426
+
427
+ .ui-icon-transferthick-e-w {
428
+ background-position: -112px -80px; }
429
+
430
+ .ui-icon-folder-collapsed {
431
+ background-position: 100% -96px; }
432
+
433
+ .ui-icon-folder-open {
434
+ background-position: -16px -96px; }
435
+
436
+ .ui-icon-document {
437
+ background-position: -32px -96px; }
438
+
439
+ .ui-icon-document-b {
440
+ background-position: -48px -96px; }
441
+
442
+ .ui-icon-note {
443
+ background-position: -64px -96px; }
444
+
445
+ .ui-icon-mail-closed {
446
+ background-position: -80px -96px; }
447
+
448
+ .ui-icon-mail-open {
449
+ background-position: -96px -96px; }
450
+
451
+ .ui-icon-suitcase {
452
+ background-position: -112px -96px; }
453
+
454
+ .ui-icon-comment {
455
+ background-position: -128px -96px; }
456
+
457
+ .ui-icon-person {
458
+ background-position: -144px -96px; }
459
+
460
+ .ui-icon-print {
461
+ background-position: -160px -96px; }
462
+
463
+ .ui-icon-trash {
464
+ background-position: -176px -96px; }
465
+
466
+ .ui-icon-locked {
467
+ background-position: -192px -96px; }
468
+
469
+ .ui-icon-unlocked {
470
+ background-position: -208px -96px; }
471
+
472
+ .ui-icon-bookmark {
473
+ background-position: -224px -96px; }
474
+
475
+ .ui-icon-tag {
476
+ background-position: -240px -96px; }
477
+
478
+ .ui-icon-home {
479
+ background-position: 100% -112px; }
480
+
481
+ .ui-icon-flag {
482
+ background-position: -16px -112px; }
483
+
484
+ .ui-icon-calendar {
485
+ background-position: -32px -112px; }
486
+
487
+ .ui-icon-cart {
488
+ background-position: -48px -112px; }
489
+
490
+ .ui-icon-pencil {
491
+ background-position: -64px -112px; }
492
+
493
+ .ui-icon-clock {
494
+ background-position: -80px -112px; }
495
+
496
+ .ui-icon-disk {
497
+ background-position: -96px -112px; }
498
+
499
+ .ui-icon-calculator {
500
+ background-position: -112px -112px; }
501
+
502
+ .ui-icon-zoomin {
503
+ background-position: -128px -112px; }
504
+
505
+ .ui-icon-zoomout {
506
+ background-position: -144px -112px; }
507
+
508
+ .ui-icon-search {
509
+ background-position: -160px -112px; }
510
+
511
+ .ui-icon-wrench {
512
+ background-position: -176px -112px; }
513
+
514
+ .ui-icon-gear {
515
+ background-position: -192px -112px; }
516
+
517
+ .ui-icon-heart {
518
+ background-position: -208px -112px; }
519
+
520
+ .ui-icon-star {
521
+ background-position: -224px -112px; }
522
+
523
+ .ui-icon-link {
524
+ background-position: -240px -112px; }
525
+
526
+ .ui-icon-cancel {
527
+ background-position: 100% -128px; }
528
+
529
+ .ui-icon-plus {
530
+ background-position: -16px -128px; }
531
+
532
+ .ui-icon-plusthick {
533
+ background-position: -32px -128px; }
534
+
535
+ .ui-icon-minus {
536
+ background-position: -48px -128px; }
537
+
538
+ .ui-icon-minusthick {
539
+ background-position: -64px -128px; }
540
+
541
+ .ui-icon-close {
542
+ background-position: -80px -128px; }
543
+
544
+ .ui-icon-closethick {
545
+ background-position: -96px -128px; }
546
+
547
+ .ui-icon-key {
548
+ background-position: -112px -128px; }
549
+
550
+ .ui-icon-lightbulb {
551
+ background-position: -128px -128px; }
552
+
553
+ .ui-icon-scissors {
554
+ background-position: -144px -128px; }
555
+
556
+ .ui-icon-clipboard {
557
+ background-position: -160px -128px; }
558
+
559
+ .ui-icon-copy {
560
+ background-position: -176px -128px; }
561
+
562
+ .ui-icon-contact {
563
+ background-position: -192px -128px; }
564
+
565
+ .ui-icon-image {
566
+ background-position: -208px -128px; }
567
+
568
+ .ui-icon-video {
569
+ background-position: -224px -128px; }
570
+
571
+ .ui-icon-script {
572
+ background-position: -240px -128px; }
573
+
574
+ .ui-icon-alert {
575
+ background-position: 100% -144px; }
576
+
577
+ .ui-icon-info {
578
+ background-position: -16px -144px; }
579
+
580
+ .ui-icon-notice {
581
+ background-position: -32px -144px; }
582
+
583
+ .ui-icon-help {
584
+ background-position: -48px -144px; }
585
+
586
+ .ui-icon-check {
587
+ background-position: -64px -144px; }
588
+
589
+ .ui-icon-bullet {
590
+ background-position: -80px -144px; }
591
+
592
+ .ui-icon-radio-on {
593
+ background-position: -96px -144px; }
594
+
595
+ .ui-icon-radio-off {
596
+ background-position: -112px -144px; }
597
+
598
+ .ui-icon-pin-w {
599
+ background-position: -128px -144px; }
600
+
601
+ .ui-icon-pin-s {
602
+ background-position: -144px -144px; }
603
+
604
+ .ui-icon-play {
605
+ background-position: 100% -160px; }
606
+
607
+ .ui-icon-pause {
608
+ background-position: -16px -160px; }
609
+
610
+ .ui-icon-seek-next {
611
+ background-position: -32px -160px; }
612
+
613
+ .ui-icon-seek-prev {
614
+ background-position: -48px -160px; }
615
+
616
+ .ui-icon-seek-end {
617
+ background-position: -64px -160px; }
618
+
619
+ .ui-icon-seek-start {
620
+ background-position: -80px -160px; }
621
+
622
+ /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
623
+ .ui-icon-seek-first {
624
+ background-position: -80px -160px; }
625
+
626
+ .ui-icon-stop {
627
+ background-position: -96px -160px; }
628
+
629
+ .ui-icon-eject {
630
+ background-position: -112px -160px; }
631
+
632
+ .ui-icon-volume-off {
633
+ background-position: -128px -160px; }
634
+
635
+ .ui-icon-volume-on {
636
+ background-position: -144px -160px; }
637
+
638
+ .ui-icon-power {
639
+ background-position: 100% -176px; }
640
+
641
+ .ui-icon-signal-diag {
642
+ background-position: -16px -176px; }
643
+
644
+ .ui-icon-signal {
645
+ background-position: -32px -176px; }
646
+
647
+ .ui-icon-battery-0 {
648
+ background-position: -48px -176px; }
649
+
650
+ .ui-icon-battery-1 {
651
+ background-position: -64px -176px; }
652
+
653
+ .ui-icon-battery-2 {
654
+ background-position: -80px -176px; }
655
+
656
+ .ui-icon-battery-3 {
657
+ background-position: -96px -176px; }
658
+
659
+ .ui-icon-circle-plus {
660
+ background-position: 100% -192px; }
661
+
662
+ .ui-icon-circle-minus {
663
+ background-position: -16px -192px; }
664
+
665
+ .ui-icon-circle-close {
666
+ background-position: -32px -192px; }
667
+
668
+ .ui-icon-circle-triangle-e {
669
+ background-position: -48px -192px; }
670
+
671
+ .ui-icon-circle-triangle-s {
672
+ background-position: -64px -192px; }
673
+
674
+ .ui-icon-circle-triangle-w {
675
+ background-position: -80px -192px; }
676
+
677
+ .ui-icon-circle-triangle-n {
678
+ background-position: -96px -192px; }
679
+
680
+ .ui-icon-circle-arrow-e {
681
+ background-position: -112px -192px; }
682
+
683
+ .ui-icon-circle-arrow-s {
684
+ background-position: -128px -192px; }
685
+
686
+ .ui-icon-circle-arrow-w {
687
+ background-position: -144px -192px; }
688
+
689
+ .ui-icon-circle-arrow-n {
690
+ background-position: -160px -192px; }
691
+
692
+ .ui-icon-circle-zoomin {
693
+ background-position: -176px -192px; }
694
+
695
+ .ui-icon-circle-zoomout {
696
+ background-position: -192px -192px; }
697
+
698
+ .ui-icon-circle-check {
699
+ background-position: -208px -192px; }
700
+
701
+ .ui-icon-circlesmall-plus {
702
+ background-position: 100% -208px; }
703
+
704
+ .ui-icon-circlesmall-minus {
705
+ background-position: -16px -208px; }
706
+
707
+ .ui-icon-circlesmall-close {
708
+ background-position: -32px -208px; }
709
+
710
+ .ui-icon-squaresmall-plus {
711
+ background-position: -48px -208px; }
712
+
713
+ .ui-icon-squaresmall-minus {
714
+ background-position: -64px -208px; }
715
+
716
+ .ui-icon-squaresmall-close {
717
+ background-position: -80px -208px; }
718
+
719
+ .ui-icon-grip-dotted-vertical {
720
+ background-position: 100% -224px; }
721
+
722
+ .ui-icon-grip-dotted-horizontal {
723
+ background-position: -16px -224px; }
724
+
725
+ .ui-icon-grip-solid-vertical {
726
+ background-position: -32px -224px; }
727
+
728
+ .ui-icon-grip-solid-horizontal {
729
+ background-position: -48px -224px; }
730
+
731
+ .ui-icon-gripsmall-diagonal-se {
732
+ background-position: -64px -224px; }
733
+
734
+ .ui-icon-grip-diagonal-se {
735
+ background-position: -80px -224px; }
736
+
737
+ /* Corner radius */
738
+ .ui-corner-all,
739
+ .ui-corner-top,
740
+ .ui-corner-left,
741
+ .ui-corner-tl {
742
+ border-top-right-radius: 3px; }
743
+
744
+ .ui-corner-all,
745
+ .ui-corner-top,
746
+ .ui-corner-right,
747
+ .ui-corner-tr {
748
+ border-top-left-radius: 3px; }
749
+
750
+ .ui-corner-all,
751
+ .ui-corner-bottom,
752
+ .ui-corner-left,
753
+ .ui-corner-bl {
754
+ border-bottom-right-radius: 3px; }
755
+
756
+ .ui-corner-all,
757
+ .ui-corner-bottom,
758
+ .ui-corner-right,
759
+ .ui-corner-br {
760
+ border-bottom-left-radius: 3px; }
761
+
762
+ .emr_upload_form .wrapper {
763
+ margin: 15px 0;
764
+ padding: 18px;
765
+ border: 1px solid #ccc; }
766
+ .emr_upload_form .wrapper .section-header {
767
+ font-size: 18px;
768
+ border-bottom: 1px solid #ccc;
769
+ padding: 6px 0;
770
+ margin: 0 0 15px 0; }
771
+ .emr_upload_form .image_chooser.wrapper {
772
+ min-height: 350px; }
773
+ .emr_upload_form .image_chooser.wrapper .image_previews {
774
+ margin: 15px 0; }
775
+ .emr_upload_form .option-flex-wrapper {
776
+ display: flex; }
777
+ .emr_upload_form .replace_type.wrapper {
778
+ flex: 1;
779
+ border: 1px solid #ccc;
780
+ margin: 15px 0; }
781
+ .emr_upload_form .replace_type.wrapper label {
782
+ font-size: 1.2em; }
783
+ .emr_upload_form .options.wrapper {
784
+ flex: 1;
785
+ border: 1px solid #ccc;
786
+ padding: 15px;
787
+ margin: 15px 35px 15px 0; }
788
+ .emr_upload_form .options.wrapper .custom_date .emr_datepicker {
789
+ width: 150px; }
790
+ .emr_upload_form .options.wrapper .custom_date .emr_hour, .emr_upload_form .options.wrapper .custom_date .emr_minute {
791
+ width: 45px; }
792
+ .emr_upload_form .options.wrapper ul li input {
793
+ margin-left: 8px; }
794
+ .emr_upload_form .options.wrapper .option label {
795
+ vertical-align: top; }
796
+ .emr_upload_form .options.wrapper .small {
797
+ font-size: 10px;
798
+ vertical-align: top;
799
+ margin-right: 8px; }
800
+ .emr_upload_form .options.wrapper .custom_date {
801
+ margin: 8px 25px 0 0;
802
+ visibility: hidden;
803
+ opacity: 0; }
804
+ .emr_upload_form .options.wrapper .custom_date span.field-title {
805
+ display: inline-block;
806
+ margin-bottom: 4px;
807
+ color: #444;
808
+ font-size: 12px;
809
+ width: 100%;
810
+ text-align: right;
811
+ vertical-align: middle;
812
+ line-height: 26px; }
813
+ .emr_upload_form .options.wrapper .custom_date span.field-title::before {
814
+ font-size: 20px;
815
+ vertical-align: top;
816
+ margin-left: 4px; }
817
+ .emr_upload_form .form_controls.wrapper {
818
+ clear: both;
819
+ margin: 8px 0 15px 0;
820
+ border: 0;
821
+ padding: 0; }
822
+ .emr_upload_form .form_controls.wrapper .button {
823
+ padding-right: 20px;
824
+ padding-left: 20px; }
825
+ .emr_upload_form .shortpixel-notice {
826
+ background: #fff;
827
+ width: 250px;
828
+ min-height: 270px;
829
+ border: 1px solid #ccc;
830
+ padding: 15px;
831
+ margin: 0 0 10px;
832
+ float: left; }
833
+ .emr_upload_form .shortpixel-notice h3 {
834
+ line-height: 1.3em; }
enable-media-replace.php CHANGED
@@ -1,12 +1,13 @@
1
  <?php
2
  /*
3
  Plugin Name: Enable Media Replace
4
- Plugin URI: http://www.mansjonasson.se/enable-media-replace
5
  Description: Enable replacing media files by uploading a new file in the "Edit Media" section of the WordPress Media Library.
6
- Version: 3.2.8
7
  Author: ShortPixel
8
  Author URI: https://shortpixel.com
9
-
 
10
  Dual licensed under the MIT and GPL licenses:
11
  http://www.opensource.org/licenses/mit-license.php
12
  http://www.gnu.org/licenses/gpl.html
@@ -31,186 +32,18 @@ if(!defined("S3_UPLOADS_AUTOENABLE")) {
31
  define('S3_UPLOADS_AUTOENABLE', true);
32
  }
33
 
34
- add_action('admin_init', 'enable_media_replace_init');
35
- add_action('admin_menu', 'emr_menu');
36
- add_filter('attachment_fields_to_edit', 'enable_media_replace', 10, 2);
37
- add_filter('media_row_actions', 'add_media_action', 10, 2);
38
- add_filter('upload_mimes', 'dat_mime_types', 1, 1);
39
-
40
- add_action('admin_notices', 'emr_display_notices');
41
- add_action('network_admin_notices', 'emr_display_network_notices');
42
- add_action('wp_ajax_emr_dismiss_notices', 'emr_dismiss_notices');
43
-
44
- add_shortcode('file_modified', 'emr_get_modified_date');
45
 
46
  if(!defined("SHORTPIXEL_AFFILIATE_CODE")) {
47
  define("SHORTPIXEL_AFFILIATE_CODE", 'VKG6LYN28044');
48
  }
49
 
50
- /**
51
- * @param array $mime_types
52
- * @return array
53
- */
54
- function dat_mime_types($mime_types) {
55
- $mime_types['dat'] = 'text/plain'; // Adding .dat extension
56
-
57
- return $mime_types;
58
- }
59
-
60
- /**
61
- * Register this file in WordPress so we can call it with a ?page= GET var.
62
- * To suppress it in the menu we give it an empty menu title.
63
- */
64
- function emr_menu() {
65
- add_submenu_page('upload.php', esc_html__("Replace media", "enable-media-replace"), '','upload_files', 'enable-media-replace/enable-media-replace', 'emr_options');
66
- }
67
-
68
- /**
69
- * Initialize this plugin. Called by 'admin_init' hook.
70
- * Only languages files needs loading during init.
71
- */
72
- function enable_media_replace_init() {
73
- load_plugin_textdomain( 'enable-media-replace', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
74
- }
75
-
76
- /**
77
- * Add some new fields to the attachment edit panel.
78
- * @param array form fields edit panel
79
- * @return array form fields with enable-media-replace fields added
80
- */
81
- function enable_media_replace( $form_fields, $post ) {
82
-
83
- $url = admin_url( "upload.php?page=enable-media-replace/enable-media-replace.php&action=media_replace&attachment_id=" . $post->ID);
84
- $action = "media_replace";
85
- $editurl = wp_nonce_url( $url, $action );
86
-
87
- if (FORCE_SSL_ADMIN) {
88
- $editurl = str_replace("http:", "https:", $editurl);
89
- }
90
- $link = "href=\"$editurl\"";
91
- $form_fields["enable-media-replace"] = array("label" => esc_html__("Replace media", "enable-media-replace"), "input" => "html", "html" => "<p><a class='button-secondary'$link>" . esc_html__("Upload a new file", "enable-media-replace") . "</a></p>", "helps" => esc_html__("To replace the current file, click the link and upload a replacement.", "enable-media-replace"));
92
-
93
- return $form_fields;
94
- }
95
-
96
- /**
97
- * Load the replace media panel.
98
- * Panel is show on the action 'media-replace' and a given attachement.
99
- * Called by GET var ?page=enable-media-replace/enable-media-replace.php
100
- */
101
- function emr_options() {
102
-
103
- if ( isset( $_GET['action'] ) && $_GET['action'] == 'media_replace' ) {
104
- check_admin_referer( 'media_replace' ); // die if invalid or missing nonce
105
- if ( array_key_exists("attachment_id", $_GET) && (int) $_GET["attachment_id"] > 0) {
106
- include("popup.php");
107
- }
108
- }
109
-
110
- if ( isset( $_GET['action'] ) && $_GET['action'] == 'media_replace_upload' ) {
111
- $plugin_url = str_replace("enable-media-replace.php", "", __FILE__);
112
- check_admin_referer( 'media_replace_upload' ); // die if invalid or missing nonce
113
- require_once($plugin_url . "upload.php");
114
- }
115
-
116
- }
117
-
118
- /**
119
- * Function called by filter 'media_row_actions'
120
- * Enables linking to EMR straight from the media library
121
- */
122
- function add_media_action( $actions, $post) {
123
- $url = admin_url( "upload.php?page=enable-media-replace/enable-media-replace.php&action=media_replace&attachment_id=" . $post->ID);
124
- $action = "media_replace";
125
- $editurl = wp_nonce_url( $url, $action );
126
-
127
- if (FORCE_SSL_ADMIN) {
128
- $editurl = str_replace("http:", "https:", $editurl);
129
- }
130
- $link = "href=\"$editurl\"";
131
-
132
- $newaction['adddata'] = '<a ' . $link . ' aria-label="' . esc_html__("Replace media", "enable-media-replace") . '" rel="permalink">' . esc_html__("Replace media", "enable-media-replace") . '</a>';
133
- return array_merge($actions,$newaction);
134
- }
135
-
136
- /**
137
- * Shorttag function to show the media file modification date/time.
138
- * @param array shorttag attributes
139
- * @return string content / replacement shorttag
140
- */
141
- function emr_get_modified_date($atts) {
142
- $id=0;
143
- $format= '';
144
-
145
- extract(shortcode_atts(array(
146
- 'id' => '',
147
- 'format' => get_option('date_format') . " " . get_option('time_format'),
148
- ), $atts));
149
-
150
- if ($id == '') return false;
151
-
152
- // Get path to file
153
- $current_file = get_attached_file($id);
154
-
155
- if ( ! file_exists( $current_file ) ) {
156
- return false;
157
- }
158
-
159
- // Get file modification time
160
- $filetime = filemtime($current_file);
161
 
162
- if ( false !== $filetime ) {
163
- // do date conversion
164
- return date( $format, $filetime );
165
- }
166
-
167
- return false;
168
- }
169
-
170
- // Add Last replaced by EMR plugin in the media edit screen metabox - Thanks Jonas Lundman (http://wordpress.org/support/topic/add-filter-hook-suggestion-to)
171
- function ua_admin_date_replaced_media_on_edit_media_screen() {
172
- if( !function_exists( 'enable_media_replace' ) ) return;
173
- global $post;
174
- $id = $post->ID;
175
- $shortcode = "[file_modified id=$id]";
176
-
177
- $file_modified_time = do_shortcode($shortcode);
178
- if ( ! $file_modified_time ) {
179
- return;
180
- }
181
- ?>
182
- <div class="misc-pub-section curtime">
183
- <span id="timestamp"><?php echo esc_html__( 'Revised', 'enable-media-replace' ); ?>: <b><?php echo $file_modified_time; ?></b></span>
184
- </div>
185
- <?php
186
- }
187
- add_action( 'attachment_submitbox_misc_actions', 'ua_admin_date_replaced_media_on_edit_media_screen', 91 );
188
-
189
- /*----------------------------------------------------------------------------------------------------------
190
- Display/dismiss admin notices if needed
191
- -----------------------------------------------------------------------------------------------------------*/
192
-
193
- function emr_display_notices() {
194
- $current_screen = get_current_screen();
195
-
196
- $crtScreen = function_exists("get_current_screen") ? get_current_screen() : (object)array("base" => false);
197
-
198
- if(current_user_can( 'activate_plugins' ) && !get_option( 'emr_news') && !is_plugin_active('shortpixel-image-optimiser/wp-shortpixel.php')
199
- && ($crtScreen->base == "upload" || $crtScreen->base == "plugins")
200
- //for network installed plugins, don't display the message on subsites.
201
- && !(function_exists('is_multisite') && is_multisite() && is_plugin_active_for_network('enable-media-replace/enable-media-replace.php') && !is_main_site()))
202
- {
203
- require_once( str_replace("enable-media-replace.php", "notice.php", __FILE__) );
204
- }
205
- }
206
-
207
- function emr_display_network_notices() {
208
- if(current_user_can( 'activate_plugins' ) && !get_option( 'emr_news') && !is_plugin_active_for_network('shortpixel-image-optimiser/wp-shortpixel.php')) {
209
- require_once( str_replace("enable-media-replace.php", "notice.php", __FILE__) );
210
- }
211
- }
212
-
213
- function emr_dismiss_notices() {
214
- update_option( 'emr_news', true);
215
- exit(json_encode(array("Status" => 0)));
216
- }
1
  <?php
2
  /*
3
  Plugin Name: Enable Media Replace
4
+ Plugin URI: https://wordpress.org/plugins/enable-media-replace/
5
  Description: Enable replacing media files by uploading a new file in the "Edit Media" section of the WordPress Media Library.
6
+ Version: 3.3.0
7
  Author: ShortPixel
8
  Author URI: https://shortpixel.com
9
+ Text Domain: enable-media-replace
10
+ Domain Path: /languages
11
  Dual licensed under the MIT and GPL licenses:
12
  http://www.opensource.org/licenses/mit-license.php
13
  http://www.gnu.org/licenses/gpl.html
32
  define('S3_UPLOADS_AUTOENABLE', true);
33
  }
34
 
35
+ if (! defined("EMR_ROOT_FILE")) {
36
+ define("EMR_ROOT_FILE", __FILE__);
37
+ }
 
 
 
 
 
 
 
 
38
 
39
  if(!defined("SHORTPIXEL_AFFILIATE_CODE")) {
40
  define("SHORTPIXEL_AFFILIATE_CODE", 'VKG6LYN28044');
41
  }
42
 
43
+ require_once('classes/replacer.php');
44
+ require_once('classes/file.php');
45
+ require_once('classes/cache.php');
46
+ require_once('classes/emr-plugin.php');
47
+ require_once('thumbnail_updater.php');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
+ $emr_plugin = new \EnableMediaReplace\EnableMediaReplacePlugin();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
img/ui-icons_444444_256x240.png ADDED
Binary file
img/ui-icons_555555_256x240.png ADDED
Binary file
js/emr_admin.js ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function($)
2
+ {
3
+ // interface for emr.
4
+ var emrIf = new function ()
5
+ {
6
+
7
+ this.init = function()
8
+ {
9
+ $('input[name="timestamp_replace"]').on('change', $.proxy(this.checkCustomDate, this));
10
+ this.checkCustomDate();
11
+ this.loadDatePicker();
12
+ },
13
+ this.loadDatePicker = function()
14
+ {
15
+ $('#emr_datepicker').datepicker({
16
+ dateFormat: emr_options.dateFormat,
17
+ onClose: function() {
18
+ var date = $(this).datepicker( 'getDate' );
19
+ if (date) {
20
+ var formattedDate = (date.getFullYear()) + "-" +
21
+ (date.getMonth()+1) + "-" +
22
+ date.getDate();
23
+ $('input[name="custom_date_formatted"]').val(formattedDate);
24
+ //$('input[name="custom_date"]').val($.datepicker.parseDate( emr_options.dateFormat, date));
25
+ }
26
+ },
27
+ });
28
+ },
29
+ this.checkCustomDate = function()
30
+ {
31
+ console.log('check');
32
+ if ($('input[name="timestamp_replace"]:checked').val() == 3)
33
+ this.showCustomDate();
34
+ else
35
+ this.hideCustomDate();
36
+ },
37
+ this.showCustomDate = function()
38
+ {
39
+ $('.custom_date').css('visibility', 'visible').fadeTo(100, 1);
40
+ },
41
+ this.hideCustomDate = function()
42
+ {
43
+ $('.custom_date').fadeTo(100,0,
44
+ function ()
45
+ {
46
+ $('.custom_date').css('visibility', 'hidden');
47
+ });
48
+ }
49
+ } // emrIf
50
+
51
+ /*emrIf.
52
+
53
+ $('input[name="timestamp_replace"]').on('change',function(e)
54
+ {
55
+ var target = e.target;
56
+ var value = $(e.target).val();
57
+ if (value == 3) // custom date
58
+ {
59
+ $('.custom_date').css('visibility', 'visible').fadeTo(100, 1);
60
+ }
61
+ else {
62
+ $('.custom_date').fadeTo(100,0,
63
+ function ()
64
+ {
65
+ $('.custom_date').css('visibility', 'hidden');
66
+ });
67
+ }
68
+ });*/
69
+
70
+ window.enableMediaReplace = emrIf;
71
+ window.enableMediaReplace.init();
72
+ });
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: ShortPixel
3
  Donate link: https://www.paypal.me/resizeImage
4
  Tags: replace, attachment, media, files, replace image, replace jpg, change media, replace media, image, file
5
  Requires at least: 4.0
6
- Tested up to: 5.1
7
  Requires PHP: 5.4
8
  Stable tag: trunk
9
 
@@ -47,6 +47,21 @@ If you want more control over the format used to display the time, you can use t
47
 
48
  == Changelog ==
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  = 3.2.9 =
51
  * properly replace thumbnails names in the content when the replaced image has a different aspect ratio, thus the new thumbnails have a different height in the name.
52
 
3
  Donate link: https://www.paypal.me/resizeImage
4
  Tags: replace, attachment, media, files, replace image, replace jpg, change media, replace media, image, file
5
  Requires at least: 4.0
6
+ Tested up to: 5.2
7
  Requires PHP: 5.4
8
  Stable tag: trunk
9
 
47
 
48
  == Changelog ==
49
 
50
+ = 3.3.0 =
51
+ * When replacing an image and changing the name, Search / Replace is now also done on the meta_value of postmeta.
52
+ * Replace PDF thumbnails too
53
+ * Copy title from EXIF
54
+ * RTL View incorporated into the CSS
55
+ * ‘wp_handle_upload’ filter should be treated as such (and not as action)
56
+ * Use wp_attached_file instead of the GUID
57
+ * Fix: replace missing file
58
+ * Fix: aphostrophe breaking the upload
59
+ * Fix: broken "before" image
60
+ * Fix: update properly the date
61
+ * Fix: errors for non-image items in Media Library
62
+ * Fix: empty admin menu item created
63
+ * Refactored all the code
64
+
65
  = 3.2.9 =
66
  * properly replace thumbnails names in the content when the replaced image has a different aspect ratio, thus the new thumbnails have a different height in the name.
67
 
scss/_datepicker.scss ADDED
@@ -0,0 +1,421 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Straight from jquery UI css
2
+
3
+ .ui-widget-content {
4
+ border: 1px solid #dddddd;
5
+ background: #ffffff;
6
+ color: #333333;
7
+ }
8
+
9
+
10
+ .ui-widget-overlay {
11
+ position: fixed;
12
+ top: 0;
13
+ left: 0;
14
+ width: 100%;
15
+ height: 100%;
16
+ }
17
+ .ui-datepicker {
18
+ width: 17em;
19
+ padding: .2em .2em 0;
20
+ display: none;
21
+ }
22
+ .ui-datepicker .ui-datepicker-header {
23
+ position: relative;
24
+ padding: .2em 0;
25
+ }
26
+ .ui-datepicker .ui-datepicker-prev,
27
+ .ui-datepicker .ui-datepicker-next {
28
+ position: absolute;
29
+ top: 2px;
30
+ width: 1.8em;
31
+ height: 1.8em;
32
+ }
33
+ .ui-datepicker .ui-datepicker-prev-hover,
34
+ .ui-datepicker .ui-datepicker-next-hover {
35
+ top: 1px;
36
+ }
37
+ .ui-datepicker .ui-datepicker-prev {
38
+ left: 2px;
39
+ }
40
+ .ui-datepicker .ui-datepicker-next {
41
+ right: 2px;
42
+ }
43
+ .ui-datepicker .ui-datepicker-prev-hover {
44
+ left: 1px;
45
+ }
46
+ .ui-datepicker .ui-datepicker-next-hover {
47
+ right: 1px;
48
+ }
49
+ .ui-datepicker .ui-datepicker-prev span,
50
+ .ui-datepicker .ui-datepicker-next span {
51
+ display: block;
52
+ position: absolute;
53
+ left: 50%;
54
+ margin-left: -8px;
55
+ top: 50%;
56
+ margin-top: -8px;
57
+ }
58
+ .ui-datepicker .ui-datepicker-title {
59
+ margin: 0 2.3em;
60
+ line-height: 1.8em;
61
+ text-align: center;
62
+ }
63
+ .ui-datepicker .ui-datepicker-title select {
64
+ font-size: 1em;
65
+ margin: 1px 0;
66
+ }
67
+ .ui-datepicker select.ui-datepicker-month,
68
+ .ui-datepicker select.ui-datepicker-year {
69
+ width: 45%;
70
+ }
71
+ .ui-datepicker table {
72
+ width: 100%;
73
+ font-size: .9em;
74
+ border-collapse: collapse;
75
+ margin: 0 0 .4em;
76
+ }
77
+ .ui-datepicker th {
78
+ padding: .7em .3em;
79
+ text-align: center;
80
+ font-weight: bold;
81
+ border: 0;
82
+ }
83
+ .ui-datepicker td {
84
+ border: 0;
85
+ padding: 1px;
86
+ }
87
+ .ui-datepicker td span,
88
+ .ui-datepicker td a {
89
+ display: block;
90
+ padding: .2em;
91
+ text-align: center;
92
+ text-decoration: none;
93
+ }
94
+ .ui-datepicker .ui-datepicker-buttonpane {
95
+ background-image: none;
96
+ margin: .7em 0 0 0;
97
+ padding: 0 .2em;
98
+ border-left: 0;
99
+ border-right: 0;
100
+ border-bottom: 0;
101
+ }
102
+ .ui-datepicker .ui-datepicker-buttonpane button {
103
+ float: right;
104
+ margin: .5em .2em .4em;
105
+ cursor: pointer;
106
+ padding: .2em .6em .3em .6em;
107
+ width: auto;
108
+ overflow: visible;
109
+ }
110
+ .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
111
+ float: left;
112
+ }
113
+
114
+ /* with multiple calendars */
115
+ .ui-datepicker.ui-datepicker-multi {
116
+ width: auto;
117
+ }
118
+ .ui-datepicker-multi .ui-datepicker-group {
119
+ float: left;
120
+ }
121
+ .ui-datepicker-multi .ui-datepicker-group table {
122
+ width: 95%;
123
+ margin: 0 auto .4em;
124
+ }
125
+ .ui-datepicker-multi-2 .ui-datepicker-group {
126
+ width: 50%;
127
+ }
128
+ .ui-datepicker-multi-3 .ui-datepicker-group {
129
+ width: 33.3%;
130
+ }
131
+ .ui-datepicker-multi-4 .ui-datepicker-group {
132
+ width: 25%;
133
+ }
134
+ .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
135
+ .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
136
+ border-left-width: 0;
137
+ }
138
+ .ui-datepicker-multi .ui-datepicker-buttonpane {
139
+ clear: left;
140
+ }
141
+ .ui-datepicker-row-break {
142
+ clear: both;
143
+ width: 100%;
144
+ font-size: 0;
145
+ }
146
+
147
+ /* RTL support */
148
+ .ui-datepicker-rtl {
149
+ direction: rtl;
150
+ }
151
+ .ui-datepicker-rtl .ui-datepicker-prev {
152
+ right: 2px;
153
+ left: auto;
154
+ }
155
+ .ui-datepicker-rtl .ui-datepicker-next {
156
+ left: 2px;
157
+ right: auto;
158
+ }
159
+ .ui-datepicker-rtl .ui-datepicker-prev:hover {
160
+ right: 1px;
161
+ left: auto;
162
+ }
163
+ .ui-datepicker-rtl .ui-datepicker-next:hover {
164
+ left: 1px;
165
+ right: auto;
166
+ }
167
+ .ui-datepicker-rtl .ui-datepicker-buttonpane {
168
+ clear: right;
169
+ }
170
+ .ui-datepicker-rtl .ui-datepicker-buttonpane button {
171
+ float: left;
172
+ }
173
+ .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
174
+ .ui-datepicker-rtl .ui-datepicker-group {
175
+ float: right;
176
+ }
177
+ .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
178
+ .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
179
+ border-right-width: 0;
180
+ border-left-width: 1px;
181
+ }
182
+
183
+ /* Icons */
184
+ .ui-datepicker .ui-icon {
185
+ display: block;
186
+ text-indent: -99999px;
187
+ overflow: hidden;
188
+ background-repeat: no-repeat;
189
+ left: .5em;
190
+ top: .3em;
191
+ }
192
+
193
+ .ui-icon {
194
+ width: 16px;
195
+ height: 16px;
196
+ }
197
+ .ui-icon,
198
+ .ui-widget-content .ui-icon {
199
+ background-image: url("../img/ui-icons_444444_256x240.png");
200
+ }
201
+ .ui-widget-header .ui-icon {
202
+ background-image: url("../img/ui-icons_444444_256x240.png");
203
+ }
204
+ .ui-state-hover .ui-icon,
205
+ .ui-state-focus .ui-icon,
206
+ .ui-button:hover .ui-icon,
207
+ .ui-button:focus .ui-icon {
208
+ background-image: url("../img/ui-icons_555555_256x240.png");
209
+ }
210
+ .ui-state-active .ui-icon,
211
+ .ui-button:active .ui-icon {
212
+ background-image: url("../img/ui-icons_ffffff_256x240.png");
213
+ }
214
+ .ui-state-highlight .ui-icon,
215
+ .ui-button .ui-state-highlight.ui-icon {
216
+ background-image: url("../img/ui-icons_777620_256x240.png");
217
+ }
218
+
219
+ /* positioning */
220
+ .ui-icon-blank { background-position: 16px 16px; }
221
+ .ui-icon-caret-1-n { background-position: 0 0; }
222
+ .ui-icon-caret-1-ne { background-position: -16px 0; }
223
+ .ui-icon-caret-1-e { background-position: -32px 0; }
224
+ .ui-icon-caret-1-se { background-position: -48px 0; }
225
+ .ui-icon-caret-1-s { background-position: -65px 0; }
226
+ .ui-icon-caret-1-sw { background-position: -80px 0; }
227
+ .ui-icon-caret-1-w { background-position: -96px 0; }
228
+ .ui-icon-caret-1-nw { background-position: -112px 0; }
229
+ .ui-icon-caret-2-n-s { background-position: -128px 0; }
230
+ .ui-icon-caret-2-e-w { background-position: -144px 0; }
231
+ .ui-icon-triangle-1-n { background-position: 0 -16px; }
232
+ .ui-icon-triangle-1-ne { background-position: -16px -16px; }
233
+ .ui-icon-triangle-1-e { background-position: -32px -16px; }
234
+ .ui-icon-triangle-1-se { background-position: -48px -16px; }
235
+ .ui-icon-triangle-1-s { background-position: -65px -16px; }
236
+ .ui-icon-triangle-1-sw { background-position: -80px -16px; }
237
+ .ui-icon-triangle-1-w { background-position: -96px -16px; }
238
+ .ui-icon-triangle-1-nw { background-position: -112px -16px; }
239
+ .ui-icon-triangle-2-n-s { background-position: -128px -16px; }
240
+ .ui-icon-triangle-2-e-w { background-position: -144px -16px; }
241
+ .ui-icon-arrow-1-n { background-position: 0 -32px; }
242
+ .ui-icon-arrow-1-ne { background-position: -16px -32px; }
243
+ .ui-icon-arrow-1-e { background-position: -32px -32px; }
244
+ .ui-icon-arrow-1-se { background-position: -48px -32px; }
245
+ .ui-icon-arrow-1-s { background-position: -65px -32px; }
246
+ .ui-icon-arrow-1-sw { background-position: -80px -32px; }
247
+ .ui-icon-arrow-1-w { background-position: -96px -32px; }
248
+ .ui-icon-arrow-1-nw { background-position: -112px -32px; }
249
+ .ui-icon-arrow-2-n-s { background-position: -128px -32px; }
250
+ .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
251
+ .ui-icon-arrow-2-e-w { background-position: -160px -32px; }
252
+ .ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
253
+ .ui-icon-arrowstop-1-n { background-position: -192px -32px; }
254
+ .ui-icon-arrowstop-1-e { background-position: -208px -32px; }
255
+ .ui-icon-arrowstop-1-s { background-position: -224px -32px; }
256
+ .ui-icon-arrowstop-1-w { background-position: -240px -32px; }
257
+ .ui-icon-arrowthick-1-n { background-position: 1px -48px; }
258
+ .ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
259
+ .ui-icon-arrowthick-1-e { background-position: -32px -48px; }
260
+ .ui-icon-arrowthick-1-se { background-position: -48px -48px; }
261
+ .ui-icon-arrowthick-1-s { background-position: -64px -48px; }
262
+ .ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
263
+ .ui-icon-arrowthick-1-w { background-position: -96px -48px; }
264
+ .ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
265
+ .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
266
+ .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
267
+ .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
268
+ .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
269
+ .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
270
+ .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
271
+ .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
272
+ .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
273
+ .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
274
+ .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
275
+ .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
276
+ .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
277
+ .ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
278
+ .ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
279
+ .ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
280
+ .ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
281
+ .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
282
+ .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
283
+ .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
284
+ .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
285
+ .ui-icon-arrow-4 { background-position: 0 -80px; }
286
+ .ui-icon-arrow-4-diag { background-position: -16px -80px; }
287
+ .ui-icon-extlink { background-position: -32px -80px; }
288
+ .ui-icon-newwin { background-position: -48px -80px; }
289
+ .ui-icon-refresh { background-position: -64px -80px; }
290
+ .ui-icon-shuffle { background-position: -80px -80px; }
291
+ .ui-icon-transfer-e-w { background-position: -96px -80px; }
292
+ .ui-icon-transferthick-e-w { background-position: -112px -80px; }
293
+ .ui-icon-folder-collapsed { background-position: 0 -96px; }
294
+ .ui-icon-folder-open { background-position: -16px -96px; }
295
+ .ui-icon-document { background-position: -32px -96px; }
296
+ .ui-icon-document-b { background-position: -48px -96px; }
297
+ .ui-icon-note { background-position: -64px -96px; }
298
+ .ui-icon-mail-closed { background-position: -80px -96px; }
299
+ .ui-icon-mail-open { background-position: -96px -96px; }
300
+ .ui-icon-suitcase { background-position: -112px -96px; }
301
+ .ui-icon-comment { background-position: -128px -96px; }
302
+ .ui-icon-person { background-position: -144px -96px; }
303
+ .ui-icon-print { background-position: -160px -96px; }
304
+ .ui-icon-trash { background-position: -176px -96px; }
305
+ .ui-icon-locked { background-position: -192px -96px; }
306
+ .ui-icon-unlocked { background-position: -208px -96px; }
307
+ .ui-icon-bookmark { background-position: -224px -96px; }
308
+ .ui-icon-tag { background-position: -240px -96px; }
309
+ .ui-icon-home { background-position: 0 -112px; }
310
+ .ui-icon-flag { background-position: -16px -112px; }
311
+ .ui-icon-calendar { background-position: -32px -112px; }
312
+ .ui-icon-cart { background-position: -48px -112px; }
313
+ .ui-icon-pencil { background-position: -64px -112px; }
314
+ .ui-icon-clock { background-position: -80px -112px; }
315
+ .ui-icon-disk { background-position: -96px -112px; }
316
+ .ui-icon-calculator { background-position: -112px -112px; }
317
+ .ui-icon-zoomin { background-position: -128px -112px; }
318
+ .ui-icon-zoomout { background-position: -144px -112px; }
319
+ .ui-icon-search { background-position: -160px -112px; }
320
+ .ui-icon-wrench { background-position: -176px -112px; }
321
+ .ui-icon-gear { background-position: -192px -112px; }
322
+ .ui-icon-heart { background-position: -208px -112px; }
323
+ .ui-icon-star { background-position: -224px -112px; }
324
+ .ui-icon-link { background-position: -240px -112px; }
325
+ .ui-icon-cancel { background-position: 0 -128px; }
326
+ .ui-icon-plus { background-position: -16px -128px; }
327
+ .ui-icon-plusthick { background-position: -32px -128px; }
328
+ .ui-icon-minus { background-position: -48px -128px; }
329
+ .ui-icon-minusthick { background-position: -64px -128px; }
330
+ .ui-icon-close { background-position: -80px -128px; }
331
+ .ui-icon-closethick { background-position: -96px -128px; }
332
+ .ui-icon-key { background-position: -112px -128px; }
333
+ .ui-icon-lightbulb { background-position: -128px -128px; }
334
+ .ui-icon-scissors { background-position: -144px -128px; }
335
+ .ui-icon-clipboard { background-position: -160px -128px; }
336
+ .ui-icon-copy { background-position: -176px -128px; }
337
+ .ui-icon-contact { background-position: -192px -128px; }
338
+ .ui-icon-image { background-position: -208px -128px; }
339
+ .ui-icon-video { background-position: -224px -128px; }
340
+ .ui-icon-script { background-position: -240px -128px; }
341
+ .ui-icon-alert { background-position: 0 -144px; }
342
+ .ui-icon-info { background-position: -16px -144px; }
343
+ .ui-icon-notice { background-position: -32px -144px; }
344
+ .ui-icon-help { background-position: -48px -144px; }
345
+ .ui-icon-check { background-position: -64px -144px; }
346
+ .ui-icon-bullet { background-position: -80px -144px; }
347
+ .ui-icon-radio-on { background-position: -96px -144px; }
348
+ .ui-icon-radio-off { background-position: -112px -144px; }
349
+ .ui-icon-pin-w { background-position: -128px -144px; }
350
+ .ui-icon-pin-s { background-position: -144px -144px; }
351
+ .ui-icon-play { background-position: 0 -160px; }
352
+ .ui-icon-pause { background-position: -16px -160px; }
353
+ .ui-icon-seek-next { background-position: -32px -160px; }
354
+ .ui-icon-seek-prev { background-position: -48px -160px; }
355
+ .ui-icon-seek-end { background-position: -64px -160px; }
356
+ .ui-icon-seek-start { background-position: -80px -160px; }
357
+ /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
358
+ .ui-icon-seek-first { background-position: -80px -160px; }
359
+ .ui-icon-stop { background-position: -96px -160px; }
360
+ .ui-icon-eject { background-position: -112px -160px; }
361
+ .ui-icon-volume-off { background-position: -128px -160px; }
362
+ .ui-icon-volume-on { background-position: -144px -160px; }
363
+ .ui-icon-power { background-position: 0 -176px; }
364
+ .ui-icon-signal-diag { background-position: -16px -176px; }
365
+ .ui-icon-signal { background-position: -32px -176px; }
366
+ .ui-icon-battery-0 { background-position: -48px -176px; }
367
+ .ui-icon-battery-1 { background-position: -64px -176px; }
368
+ .ui-icon-battery-2 { background-position: -80px -176px; }
369
+ .ui-icon-battery-3 { background-position: -96px -176px; }
370
+ .ui-icon-circle-plus { background-position: 0 -192px; }
371
+ .ui-icon-circle-minus { background-position: -16px -192px; }
372
+ .ui-icon-circle-close { background-position: -32px -192px; }
373
+ .ui-icon-circle-triangle-e { background-position: -48px -192px; }
374
+ .ui-icon-circle-triangle-s { background-position: -64px -192px; }
375
+ .ui-icon-circle-triangle-w { background-position: -80px -192px; }
376
+ .ui-icon-circle-triangle-n { background-position: -96px -192px; }
377
+ .ui-icon-circle-arrow-e { background-position: -112px -192px; }
378
+ .ui-icon-circle-arrow-s { background-position: -128px -192px; }
379
+ .ui-icon-circle-arrow-w { background-position: -144px -192px; }
380
+ .ui-icon-circle-arrow-n { background-position: -160px -192px; }
381
+ .ui-icon-circle-zoomin { background-position: -176px -192px; }
382
+ .ui-icon-circle-zoomout { background-position: -192px -192px; }
383
+ .ui-icon-circle-check { background-position: -208px -192px; }
384
+ .ui-icon-circlesmall-plus { background-position: 0 -208px; }
385
+ .ui-icon-circlesmall-minus { background-position: -16px -208px; }
386
+ .ui-icon-circlesmall-close { background-position: -32px -208px; }
387
+ .ui-icon-squaresmall-plus { background-position: -48px -208px; }
388
+ .ui-icon-squaresmall-minus { background-position: -64px -208px; }
389
+ .ui-icon-squaresmall-close { background-position: -80px -208px; }
390
+ .ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
391
+ .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
392
+ .ui-icon-grip-solid-vertical { background-position: -32px -224px; }
393
+ .ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
394
+ .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
395
+ .ui-icon-grip-diagonal-se { background-position: -80px -224px; }
396
+
397
+ /* Corner radius */
398
+ .ui-corner-all,
399
+ .ui-corner-top,
400
+ .ui-corner-left,
401
+ .ui-corner-tl {
402
+ border-top-left-radius: 3px;
403
+ }
404
+ .ui-corner-all,
405
+ .ui-corner-top,
406
+ .ui-corner-right,
407
+ .ui-corner-tr {
408
+ border-top-right-radius: 3px;
409
+ }
410
+ .ui-corner-all,
411
+ .ui-corner-bottom,
412
+ .ui-corner-left,
413
+ .ui-corner-bl {
414
+ border-bottom-left-radius: 3px;
415
+ }
416
+ .ui-corner-all,
417
+ .ui-corner-bottom,
418
+ .ui-corner-right,
419
+ .ui-corner-br {
420
+ border-bottom-right-radius: 3px;
421
+ }
scss/admin.scss ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import 'datepicker';
2
+
3
+ .emr_upload_form
4
+ {
5
+ .wrapper
6
+ {
7
+ margin: 15px 0;
8
+ padding: 18px;
9
+ border: 1px solid #ccc;
10
+
11
+ .section-header
12
+ {
13
+ font-size: 18px;
14
+ //text-align: center;
15
+ border-bottom: 1px solid #ccc;
16
+ padding: 6px 0;
17
+ margin: 0 0 15px 0;
18
+ }
19
+ }
20
+
21
+ .image_chooser.wrapper
22
+ {
23
+ min-height: 350px;
24
+ .image_previews
25
+ {
26
+ margin: 15px 0;
27
+ }
28
+ }
29
+
30
+ .option-flex-wrapper
31
+ {
32
+ display: flex;
33
+ }
34
+
35
+ .replace_type.wrapper
36
+ {
37
+ flex: 1;
38
+ border: 1px solid #ccc;
39
+ margin: 15px 0;
40
+ label
41
+ {
42
+ font-size: 1.2em;
43
+ }
44
+ }
45
+
46
+ .options.wrapper
47
+ {
48
+ flex: 1;
49
+ border: 1px solid #ccc;
50
+ padding: 15px;
51
+ margin: 15px 0 15px 35px;
52
+ .custom_date
53
+ {
54
+ .emr_datepicker {
55
+ width: 150px;
56
+ }
57
+ .emr_hour, .emr_minute
58
+ {
59
+ width: 45px;
60
+ }
61
+ }
62
+ ul
63
+ {
64
+ li
65
+ {
66
+ input
67
+ {
68
+ margin-right: 8px;
69
+ }
70
+ }
71
+ }
72
+ .option
73
+ {
74
+ label { vertical-align: top; }
75
+ }
76
+ .small
77
+ {
78
+ font-size: 10px;
79
+ vertical-align: top;
80
+ margin-left: 8px;
81
+ }
82
+ .custom_date
83
+ {
84
+ margin: 8px 0 0 25px;
85
+ visibility: hidden;
86
+ opacity: 0;
87
+ span.field-title {
88
+ display: inline-block;
89
+ margin-bottom: 4px;
90
+ color: #444;
91
+ //margin-left: 8px;
92
+ font-size: 12px;
93
+ width: 100%;
94
+ text-align: left;
95
+ vertical-align: middle;
96
+ line-height: 26px;
97
+ &::before
98
+ {
99
+ font-size: 20px;
100
+ vertical-align: top;
101
+ margin-right: 4px;
102
+ }
103
+ }
104
+ } // custom_date
105
+ }
106
+
107
+ .form_controls.wrapper
108
+ {
109
+ clear: both;
110
+ margin: 8px 0 15px 0;
111
+ border: 0;
112
+ padding: 0;
113
+ .button
114
+ {
115
+ padding-left: 20px;
116
+ padding-right: 20px;
117
+ }
118
+ }
119
+
120
+ .shortpixel-notice
121
+ {
122
+ background: #fff;
123
+ width: 250px;
124
+ min-height: 270px;
125
+ border: 1px solid #ccc;
126
+ padding: 15px;
127
+ margin: 0 0 10px;
128
+ float: right;
129
+ h3 {
130
+ line-height: 1.3em; // match size
131
+ }
132
+ }
133
+ }
thumbnail_updater.php CHANGED
@@ -40,6 +40,7 @@ class ThumbnailUpdater
40
  if (isset($metadata['sizes']))
41
  $this->newMeta = $metadata;
42
 
 
43
  // extract month prefix to prevent overwriting wrong images.
44
  $file = $metadata['file'];
45
  $pos = strrpos($metadata['file'], '/');
@@ -47,6 +48,7 @@ class ThumbnailUpdater
47
  $this->relPath = trailingslashit($month_path);
48
  }
49
 
 
50
  public function updateThumbnails()
51
  {
52
  if (count($this->oldMeta) == 0 || count($this->newMeta) == 0)
40
  if (isset($metadata['sizes']))
41
  $this->newMeta = $metadata;
42
 
43
+
44
  // extract month prefix to prevent overwriting wrong images.
45
  $file = $metadata['file'];
46
  $pos = strrpos($metadata['file'], '/');
48
  $this->relPath = trailingslashit($month_path);
49
  }
50
 
51
+
52
  public function updateThumbnails()
53
  {
54
  if (count($this->oldMeta) == 0 || count($this->newMeta) == 0)
views/notice.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class='notice' id='emr-news' style="padding-top: 7px">
2
+ <div style="float:<?php echo (is_rtl()) ? 'left' : 'right' ?>;"><a href="javascript:emrDismissNews()" class="button" style="margin-top:10px;"><?php _e('Dismiss', 'enable-media-replace');?></a></div>
3
+ <a href="https://shortpixel.com/wp/af/VKG6LYN28044" target="_blank" style="float: <?php echo (is_rtl()) ? 'right' : 'left' ?>;margin-<?php echo (is_rtl()) ? 'left' : 'right' ?>: 10px;">
4
+ <img src="<?php echo $this->plugin_url . 'img/sp.png' ?>" class="emr-sp"/>
5
+ </a>
6
+ <h3 style="margin:10px;"><?php echo esc_html__('Enable Media Replace is now compatible with ShortPixel!','enable-media-replace');?></h3>
7
+ <p style="margin-bottom:0px;">
8
+ <?php _e( '<a href="https://shortpixel.com/wp/af/VKG6LYN28044" target="_blank">ShortPixel</a> is an image optimization plugin and if you have it activated, upon replacing an image in Enable Media Replace, the image will be also automatically optimized.', 'enable-media-replace' ); ?>
9
+ </p>
10
+ <p style="text-align: <?php echo (is_rtl()) ? 'left' : 'right' ?>;margin-top: 0;">
11
+ <a href="https://shortpixel.com/wp/af/VKG6LYN28044" target="_blank">&gt;&gt; <?php _e( 'More info', 'enable-media-replace' ); ?></a>
12
+ </p>
13
+ </div>
14
+ <script>
15
+ function emrDismissNews() {
16
+ jQuery("#emr-news").hide();
17
+ var data = { action : 'emr_dismiss_notices'};
18
+ jQuery.get('<?php echo admin_url('admin-ajax.php'); ?>', data, function(response) {
19
+ data = JSON.parse(response);
20
+ if(data["Status"] == 0) {
21
+ console.log("dismissed");
22
+ }
23
+ });
24
+ }
25
+ </script>
views/popup.php ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Uploadscreen for selecting and uploading new media file
4
+ *
5
+ * @author Måns Jonasson <http://www.mansjonasson.se>
6
+ * @copyright Måns Jonasson 13 sep 2010
7
+ * @version $Revision: 2303 $ | $Date: 2010-09-13 11:12:35 +0200 (ma, 13 sep 2010) $
8
+ * @package wordpress
9
+ * @subpackage enable-media-replace
10
+ *
11
+ */
12
+
13
+ if ( ! defined( 'ABSPATH' ) )
14
+ exit; // Exit if accessed directly.
15
+
16
+ if (!current_user_can('upload_files'))
17
+ wp_die( esc_html__('You do not have permission to upload files.', 'enable-media-replace') );
18
+
19
+ global $wpdb;
20
+
21
+ $table_name = $wpdb->prefix . "posts";
22
+
23
+
24
+ //$sql = "SELECT guid, post_mime_type FROM $table_name WHERE ID = " . (int) $_GET["attachment_id"];
25
+ //list($current_filename, $current_filetype) = $wpdb->get_row($sql, ARRAY_N);
26
+
27
+ $attachment_id = intval($_GET['attachment_id']);
28
+ $attachment = get_post($attachment_id);
29
+
30
+ $filepath = get_attached_file($attachment_id); // fullpath
31
+ $fileurl = wp_get_attachment_url($attachment_id); //full url
32
+
33
+ $filetype = $attachment->post_mime_type;
34
+ $filename = basename($filepath);
35
+
36
+ ?>
37
+ <style>
38
+ .emr-plugin-button.emr-updating:before {
39
+ font: 400 20px/1 dashicons;
40
+ display: inline-block;
41
+ content: "\f463";
42
+ -webkit-animation: rotation 2s infinite linear;
43
+ animation: rotation 2s infinite linear;
44
+ margin: 3px 5px 0 -2px;
45
+ vertical-align: top
46
+ }
47
+ </style>
48
+ <div class="wrap emr_upload_form">
49
+ <h1><?php echo esc_html__("Replace Media Upload", "enable-media-replace"); ?></h1>
50
+
51
+ <?php
52
+ $url = admin_url( "upload.php?page=enable-media-replace/enable-media-replace.php&noheader=true&action=media_replace_upload&attachment_id=" . $attachment_id );
53
+
54
+ $formurl = wp_nonce_url( $url, "media_replace_upload" );
55
+ if (FORCE_SSL_ADMIN) {
56
+ $formurl = str_replace("http:", "https:", $formurl);
57
+ }
58
+ ?>
59
+
60
+ <form enctype="multipart/form-data" method="post" action="<?php echo $formurl; ?>">
61
+ <section class='image_chooser wrapper'>
62
+ <div class='section-header'> <?php _e('Choose Replacement Image', 'enable-replace-media'); ?></div>
63
+
64
+ <?php
65
+ #wp_nonce_field('enable-media-replace');
66
+ $plugins = get_plugins();
67
+ $spInstalled = isset($plugins['shortpixel-image-optimiser/wp-shortpixel.php']);
68
+ $spActive = is_plugin_active('shortpixel-image-optimiser/wp-shortpixel.php');
69
+ ?>
70
+ <input type="hidden" name="ID" value="<?php echo $attachment_id ?>" />
71
+ <div id="message" class="updated notice notice-success is-dismissible"><p><?php printf( esc_html__('NOTE: You are about to replace the media file "%s". There is no undo. Think about it!', "enable-media-replace"), $filename ); ?></p></div>
72
+
73
+ <?php if(!$spInstalled) {?>
74
+ <div class='shortpixel-notice'>
75
+ <h3 class="" style="margin-top: 0;text-align: center;">
76
+ <a href="https://shortpixel.com/wp/af/VKG6LYN28044" target="_blank">
77
+ <?php echo esc_html__("Optimize your images with ShortPixel, get +50% credits!", "enable-media-replace"); ?>
78
+ </a>
79
+ </h3>
80
+ <div class="" style="text-align: center;">
81
+ <a href="https://shortpixel.com/wp/af/VKG6LYN28044" target="_blank">
82
+ <img src="https://optimizingmattersblog.files.wordpress.com/2016/10/shortpixel.png">
83
+ </a>
84
+ </div>
85
+ <div class="" style="margin-bottom: 10px;">
86
+ <?php echo esc_html__("Get more Google love by compressing your site's images! Check out how much ShortPixel can save your site and get +50% credits when signing up as an Enable Media Replace user! Forever!", "enable-media-replace"); ?>
87
+ </div>
88
+ <div class=""><div style="text-align: <?php echo (is_rtl()) ? 'left' : 'right' ?>;">
89
+ <a class="button button-primary" id="shortpixel-image-optimiser-info" href="https://shortpixel.com/wp/af/VKG6LYN28044" target="_blank">
90
+ <?php echo esc_html__("More info", "enable-media-replace"); ?></p>
91
+ </a>
92
+ </div>
93
+ </div>
94
+ </div>
95
+ <?php } ?>
96
+
97
+ <p><?php echo esc_html__("Choose a file to upload from your computer", "enable-media-replace"); ?></p>
98
+
99
+ <input type="file" name="userfile" id="userfile" onchange="imageHandle(event);" />
100
+ <div class='image_previews'>
101
+ <img src="<?php echo $fileurl ?>" width="150px" height="150px" style="object-fit: cover"/>
102
+ <img id="previewImage" src="https://via.placeholder.com/150x150" width="150px" height="150px"/>
103
+ </div>
104
+
105
+ </section>
106
+ <div class='option-flex-wrapper'>
107
+ <section class='replace_type wrapper'>
108
+ <div class='section-header'> <?php _e('Replacement Options', 'enable-replace-media'); ?></div>
109
+
110
+ <?php do_action( 'emr_before_replace_type_options' ); ?>
111
+
112
+
113
+ <?php $s3pluginExist = class_exists('S3_Uploads'); ?>
114
+ <?php if ( apply_filters( 'emr_display_replace_type_options', true ) ) : ?>
115
+ <?php if ( ! $s3pluginExist) : ?>
116
+
117
+
118
+ <label for="replace_type_1"><input CHECKED id="replace_type_1" type="radio" name="replace_type" value="replace"> <?php echo esc_html__("Just replace the file", "enable-media-replace"); ?></label>
119
+ <p class="howto"><?php printf( esc_html__("Note: This option requires you to upload a file of the same type (%s) as the one you are replacing. The name of the attachment will stay the same (%s) no matter what the file you upload is called.", "enable-media-replace"), $filetype, $filename ); ?></p>
120
+
121
+ <?php endif; ?>
122
+ <?php if ( apply_filters( 'emr_enable_replace_and_search', true ) ) : ?>
123
+ <label for="replace_type_2"><input <?php echo $s3pluginExist ? 'CHECKED' : '' ?> id="replace_type_2" type="radio" name="replace_type" value="replace_and_search"> <?php echo __("Replace the file, use new file name and update all links", "enable-media-replace"); ?></label>
124
+ <p class="howto"><?php printf( esc_html__("Note: If you check this option, the name and type of the file you are about to upload will replace the old file. All links pointing to the current file (%s) will be updated to point to the new file name.", "enable-media-replace"), $filename ); ?></p>
125
+ <p class="howto"><?php echo esc_html__("Please note that if you upload a new image, only embeds/links of the original size image will be replaced in your posts.", "enable-media-replace"); ?></p>
126
+ <?php endif; ?>
127
+ <?php else : ?>
128
+ <?php if ( ! $s3pluginExist) : ?>
129
+ <input type="hidden" name="replace_type" value="replace" />
130
+ <?php else : ?>
131
+ <input type="hidden" name="replace_type" value="replace_and_search" />
132
+ <?php endif; ?>
133
+ <?php endif; ?>
134
+ </section>
135
+ <section class='options wrapper'>
136
+ <div class='section-header'> <?php _e('Date Options', 'enable-media-replace'); ?></div>
137
+ <div class='option timestamp'>
138
+ <?php
139
+ $attachment_current_date = date_i18n('d/M/Y H:i', strtotime($attachment->post_date) );
140
+ $time = current_time('mysql');
141
+ $date = new dateTime($time);
142
+ ?>
143
+ <p><?php _e('When replacing the media, do you want to:', 'enable-media-replace'); ?></p>
144
+ <ul>
145
+ <li><label><input type='radio' name='timestamp_replace' value='1' checked /><?php _e('Replace the date', 'enable-media-replace'); ?></label></li>
146
+ <li><label><input type='radio' name='timestamp_replace' value='2' /><?php printf(__('Keep the date %s(%s)%s', 'enable-media-replace'), "<span class='small'>", $attachment_current_date, "</span>"); ?></label></li>
147
+ <li><label><input type='radio' name='timestamp_replace' value='3' /><?php _e('Set a Custom Date', 'enable-media-replace'); ?></label></li>
148
+ </ul>
149
+ <div class='custom_date'>
150
+
151
+ <span class='field-title dashicons dashicons-calendar'><?php _e('Custom Date', 'enable-media-replace'); ?></span>
152
+ <input type='text' name="custom_date" value="<?php echo $date->format(get_option('date_format')); ?>" id='emr_datepicker'
153
+ class='emr_datepicker' />
154
+
155
+ @ <input type='text' name="custom_hour" class='emr_hour' value="<?php echo $date->format('H') ?>" /> &nbsp;
156
+ <input type="text" name="custom_minute" class='emr_minute' value="<?php echo $date->format('i'); ?>" />
157
+ <input type="hidden" name="custom_date_formatted" value="" />
158
+ </div>
159
+ </div>
160
+ </section>
161
+ </div>
162
+ <section class='form_controls wrapper'>
163
+ <input id="submit" type="submit" class="button button-primary" disabled="disabled" value="<?php echo esc_attr__("Upload", "enable-media-replace"); ?>" />
164
+ <a href="#" class="button" onclick="history.back();"><?php echo esc_html__("Cancel", "enable-media-replace"); ?></a>
165
+ </section>
166
+ </form>
167
+ </div>
168
+ <script>
169
+ function imageHandle(event) {
170
+ var file = document.getElementById("userfile");
171
+ var submit = document.getElementById("submit");
172
+ var preview = document.getElementById("previewImage");
173
+
174
+ appendPreview(file, preview, event);
175
+ enableSubmitButton(file, submit);
176
+ }
177
+
178
+ function appendPreview(fileSource, preview, event) {
179
+ if (fileSource.value) {
180
+ var file = fileSource.files[0];
181
+ if (file.type.match("image/*")) {
182
+ preview.setAttribute("src", window.URL.createObjectURL(file));
183
+ preview.setAttribute("style", "object-fit: cover");
184
+ } else {
185
+ preview.setAttribute("src", "https://dummyimage.com/150x150/ccc/969696.gif&text=File");
186
+ preview.removeAttribute("style");
187
+ }
188
+ } else {
189
+ preview.setAttribute("src", "https://via.placeholder.com/150x150");
190
+ }
191
+ }
192
+ function enableSubmitButton(file, submit)
193
+ {
194
+ if (file.value) {
195
+ submit.disabled = false;
196
+ submit.removeAttribute("disabled");
197
+ } else {
198
+ submit.setAttribute("disabled", true);
199
+ }
200
+ }
201
+ </script>
views/upload.php ADDED
@@ -0,0 +1,314 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( ! defined( 'ABSPATH' ) )
3
+ exit; // Exit if accessed directly.
4
+
5
+ if (!current_user_can('upload_files'))
6
+ wp_die( esc_html__('You do not have permission to upload files.', 'enable-media-replace') );
7
+
8
+
9
+ /*require_once('classes/replacer.php');
10
+ require_once('classes/file.php'); */
11
+
12
+ use \EnableMediaReplace\Replacer as Replacer;
13
+
14
+ // Define DB table names
15
+ global $wpdb;
16
+ $table_name = $wpdb->prefix . "posts";
17
+ $postmeta_table_name = $wpdb->prefix . "postmeta";
18
+
19
+ /**
20
+ * Delete a media file and its thumbnails.
21
+ *
22
+ * @param string $current_file
23
+ * @param array|null $metadta
24
+ */
25
+ function emr_delete_current_files( $current_file, $metadta = null ) {
26
+ // Delete old file
27
+
28
+ // Find path of current file
29
+ $current_path = substr($current_file, 0, (strrpos($current_file, "/")));
30
+
31
+ // Check if old file exists first
32
+ if (file_exists($current_file)) {
33
+ // Now check for correct file permissions for old file
34
+ clearstatcache();
35
+ if (is_writable($current_file)) {
36
+ // Everything OK; delete the file
37
+ unlink($current_file);
38
+ }
39
+ else {
40
+ // File exists, but has wrong permissions. Let the user know.
41
+ printf( esc_html__('The file %1$s can not be deleted by the web server, most likely because the permissions on the file are wrong.', "enable-media-replace"), $current_file);
42
+ exit;
43
+ }
44
+ }
45
+
46
+ // Delete old resized versions if this was an image
47
+ $suffix = substr($current_file, (strlen($current_file)-4));
48
+ $prefix = substr($current_file, 0, (strlen($current_file)-4));
49
+
50
+ if (strtolower($suffix) === ".pdf") {
51
+ $prefix .= "-pdf";
52
+ $suffix = ".jpg";
53
+ }
54
+
55
+ $imgAr = array(".png", ".gif", ".jpg");
56
+ if (in_array($suffix, $imgAr)) {
57
+ // It's a png/gif/jpg based on file name
58
+ // Get thumbnail filenames from metadata
59
+ if ( empty( $metadata ) ) {
60
+ $metadata = wp_get_attachment_metadata( $_POST["ID"] );
61
+ }
62
+
63
+ if (is_array($metadata)) { // Added fix for error messages when there is no metadata (but WHY would there not be? I don't know…)
64
+ foreach($metadata["sizes"] AS $thissize) {
65
+ // Get all filenames and do an unlink() on each one;
66
+ $thisfile = $thissize["file"];
67
+ // Create array with all old sizes for replacing in posts later
68
+ $oldfilesAr[] = $thisfile;
69
+ // Look for files and delete them
70
+ if (strlen($thisfile)) {
71
+ $thisfile = $current_path . "/" . $thissize["file"];
72
+ if (file_exists($thisfile)) {
73
+ unlink($thisfile);
74
+ }
75
+ }
76
+ }
77
+ }
78
+ // Old (brutal) method, left here for now
79
+ //$mask = $prefix . "-*x*" . $suffix;
80
+ //array_map( "unlink", glob( $mask ) );
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Maybe remove query string from URL.
86
+ *
87
+ * @param string $url
88
+ *
89
+ * @return string
90
+ */
91
+ function emr_maybe_remove_query_string( $url ) {
92
+ $parts = explode( '?', $url );
93
+
94
+ return reset( $parts );
95
+ }
96
+
97
+ /**
98
+ * Remove scheme from URL.
99
+ *
100
+ * @param string $url
101
+ *
102
+ * @return string
103
+ */
104
+ function emr_remove_scheme( $url ) {
105
+ return preg_replace( '/^(?:http|https):/', '', $url );
106
+ }
107
+
108
+ /**
109
+ * Remove size from filename (image[-100x100].jpeg).
110
+ *
111
+ * @param string $url
112
+ * @param bool $remove_extension
113
+ *
114
+ * @return string
115
+ */
116
+ function emr_remove_size_from_filename( $url, $remove_extension = false ) {
117
+ $url = preg_replace( '/^(\S+)-[0-9]{1,4}x[0-9]{1,4}(\.[a-zA-Z0-9\.]{2,})?/', '$1$2', $url );
118
+
119
+ if ( $remove_extension ) {
120
+ $ext = pathinfo( $url, PATHINFO_EXTENSION );
121
+ $url = str_replace( ".$ext", '', $url );
122
+ }
123
+
124
+ return $url;
125
+ }
126
+
127
+ /**
128
+ * Strip an image URL down to bare minimum for matching.
129
+ *
130
+ * @param string $url
131
+ *
132
+ * @return string
133
+ */
134
+ function emr_get_match_url($url) {
135
+ $url = emr_remove_scheme($url);
136
+ $url = emr_maybe_remove_query_string($url);
137
+ $url = emr_remove_size_from_filename($url, true);
138
+ $url = emr_remove_domain_from_filename($url);
139
+ return $url;
140
+ }
141
+
142
+
143
+ function emr_remove_domain_from_filename($url) {
144
+ // Holding place for possible future function
145
+ $url = str_replace(emr_remove_scheme(get_bloginfo('url')), '', $url);
146
+ return $url;
147
+ }
148
+
149
+ /**
150
+ * Build an array of search or replace URLs for given attachment GUID and its metadata.
151
+ *
152
+ * @param string $guid
153
+ * @param array $metadata
154
+ *
155
+ * @return array
156
+ */
157
+ function emr_get_file_urls( $guid, $metadata ) {
158
+ $urls = array();
159
+
160
+ $guid = emr_remove_scheme( $guid );
161
+ $guid= emr_remove_domain_from_filename($guid);
162
+
163
+ $urls['guid'] = $guid;
164
+
165
+ if ( empty( $metadata ) ) {
166
+ return $urls;
167
+ }
168
+
169
+ $base_url = dirname( $guid );
170
+
171
+ if ( ! empty( $metadata['file'] ) ) {
172
+ $urls['file'] = trailingslashit( $base_url ) . wp_basename( $metadata['file'] );
173
+ }
174
+
175
+ if ( ! empty( $metadata['sizes'] ) ) {
176
+ foreach ( $metadata['sizes'] as $key => $value ) {
177
+ $urls[ $key ] = trailingslashit( $base_url ) . wp_basename( $value['file'] );
178
+ }
179
+ }
180
+
181
+ return $urls;
182
+ }
183
+
184
+ /**
185
+ * Ensure new search URLs cover known sizes for old attachment.
186
+ * Falls back to full URL if size not covered (srcset or width/height attributes should compensate).
187
+ *
188
+ * @param array $old
189
+ * @param array $new
190
+ *
191
+ * @return array
192
+ */
193
+ function emr_normalize_file_urls( $old, $new ) {
194
+ $result = array();
195
+
196
+ if ( empty( $new['guid'] ) ) {
197
+ return $result;
198
+ }
199
+
200
+ $guid = $new['guid'];
201
+
202
+ foreach ( $old as $key => $value ) {
203
+ $result[ $key ] = empty( $new[ $key ] ) ? $guid : $new[ $key ];
204
+ }
205
+
206
+ return $result;
207
+ }
208
+
209
+ // Starts processing.
210
+
211
+ // Get old guid and filetype from DB
212
+ $post_id = intval($_POST['ID']); // sanitize, post_id.
213
+
214
+ $replacer = new replacer($post_id);
215
+
216
+ /*$sql = "SELECT post_mime_type FROM $table_name WHERE ID = '%d'";
217
+ $sql = $wpdb->prepare($sql, array($post_id) );
218
+ list($current_filetype) = $wpdb->get_row($sql, ARRAY_N); // seems unused as well.
219
+ */
220
+ // Massage a bunch of vars
221
+ //$current_guid = wp_get_attachment_url($post_id); // this is used for search / replace
222
+
223
+ $ID = intval($_POST["ID"]); // legacy
224
+ $replace_type = isset($_POST["replace_type"]) ? sanitize_text_field($_POST["replace_type"]) : false;
225
+ $timestamp_replace = intval($_POST['timestamp_replace']);
226
+
227
+ $current_file = get_attached_file($post_id, apply_filters( 'emr_unfiltered_get_attached_file', true ));
228
+ $current_path = substr($current_file, 0, (strrpos($current_file, "/")));
229
+ $current_file = preg_replace("|(?<!:)/{2,}|", "/", $current_file); // @todo what does this mean?
230
+ $current_filename = wp_basename($current_file);
231
+ $current_metadata = wp_get_attachment_metadata( $post_id );
232
+
233
+ switch($timestamp_replace)
234
+ {
235
+ case \EnableMediaReplace\Replacer::TIME_UPDATEALL:
236
+ case \EnableMediaReplace\Replacer::TIME_UPDATEMODIFIED:
237
+ $datetime = current_time('mysql');
238
+ break;
239
+ case \EnableMediaReplace\Replacer::TIME_CUSTOM:
240
+ $custom_date = $_POST['custom_date_formatted'];
241
+ $custom_hour = $_POST['custom_hour'];
242
+ $custom_minute = $_POST['custom_minute'];
243
+
244
+ // create a mysql time representation from what we have.
245
+ $custom_date = DateTime::createFromFormat('Y-m-d H:i', $custom_date . ' ' . $custom_hour . ':' . $custom_minute );
246
+ $datetime = $custom_date->format("Y-m-d H:i:s");
247
+ break;
248
+ }
249
+
250
+
251
+
252
+ // We have two types: replace / replace_and_search
253
+ if ($replace_type == 'replace')
254
+ {
255
+ $replacer->setMode(\EnableMediaReplace\Replacer::MODE_REPLACE);
256
+ }
257
+ elseif ( 'replace_and_search' == $replace_type && apply_filters( 'emr_enable_replace_and_search', true ) )
258
+ {
259
+ $replacer->setMode(\EnableMediaReplace\Replacer::MODE_SEARCHREPLACE);
260
+ }
261
+
262
+ $replacer->setTimeMode($timestamp_replace, $datetime);
263
+
264
+
265
+
266
+ if (is_uploaded_file($_FILES["userfile"]["tmp_name"])) {
267
+
268
+ // New method for validating that the uploaded file is allowed, using WP:s internal wp_check_filetype_and_ext() function.
269
+ $filedata = wp_check_filetype_and_ext($_FILES["userfile"]["tmp_name"], $_FILES["userfile"]["name"]);
270
+
271
+ if ($filedata["ext"] == "") {
272
+ echo esc_html__("File type does not meet security guidelines. Try another.", 'enable-media-replace');
273
+ exit;
274
+ }
275
+
276
+ // Here we have the uploaded file
277
+
278
+ $thumbUpdater = new ThumbnailUpdater($ID);
279
+ $thumbUpdater->setOldMetadata($current_metadata);
280
+
281
+ $new_filename = $_FILES["userfile"]["name"];
282
+ //$new_filesize = $_FILES["userfile"]["size"]; // Seems not to be in use.
283
+ $new_filetype = $filedata["type"];
284
+
285
+ // save original file permissions
286
+ //$original_file_perms = fileperms($current_file) & 0777;
287
+
288
+ // Gather all functions that both options do.
289
+ do_action('wp_handle_replace', array('post_id' => $post_id));
290
+
291
+ $replacer->replaceWith($_FILES["userfile"]["tmp_name"], $new_filename);
292
+
293
+ #echo "Updated: " . $number_of_updates;
294
+
295
+ $returnurl = admin_url("/post.php?post={$_POST["ID"]}&action=edit&message=1");
296
+
297
+ // Execute hook actions - thanks rubious for the suggestion!
298
+ //if (isset($new_guid)) { do_action("enable-media-replace-upload-done", $new_guid, $current_guid); }
299
+
300
+ } else {
301
+ //TODO Better error handling when no file is selected.
302
+ //For now just go back to media management
303
+ $returnurl = admin_url("upload.php");
304
+ }
305
+
306
+ if (FORCE_SSL_ADMIN) {
307
+ $returnurl = str_replace("http:", "https:", $returnurl);
308
+ }
309
+
310
+ // Allow developers to override $returnurl
311
+ $returnurl = apply_filters('emr_returnurl', $returnurl);
312
+
313
+ wp_redirect($returnurl);
314
+ ?>