diff --git a/e107_admin/image.php b/e107_admin/image.php index ef39b25e5..b1f5b2d76 100644 --- a/e107_admin/image.php +++ b/e107_admin/image.php @@ -37,7 +37,7 @@ if($_GET['action'] == 'youtube' ) } // TODO use library manager -e107::js('core', 'plupload/plupload.full.js', 'jquery', 2); +e107::js('core', 'plupload/plupload.full.min.js', 'jquery', 2); e107::css('core', 'plupload/jquery.plupload.queue/css/jquery.plupload.queue.css', 'jquery'); e107::js('core', 'plupload/jquery.plupload.queue/jquery.plupload.queue.min.js', 'jquery', 2); e107::js('core', 'core/mediaManager.js',"jquery",5); diff --git a/e107_web/js/core/mediaManager.js b/e107_web/js/core/mediaManager.js index 6e7b72a06..967f88f88 100644 --- a/e107_web/js/core/mediaManager.js +++ b/e107_web/js/core/mediaManager.js @@ -911,6 +911,16 @@ console.log('Bbcode: '+bbcode); } }, init: { + BeforeUpload: function(e,file) + { + + + }, + BeforeChunkUpload: function(uploader, file, post, currentBlob, currentOffset) + { + //console.log(file); + // currentBlob.name=file.name; + }, FilesAdded: function (up, files) { diff --git a/e107_web/js/plupload/Moxie.swf b/e107_web/js/plupload/Moxie.swf index 937085f26..ca29775a5 100644 Binary files a/e107_web/js/plupload/Moxie.swf and b/e107_web/js/plupload/Moxie.swf differ diff --git a/e107_web/js/plupload/Moxie.xap b/e107_web/js/plupload/Moxie.xap index fc7fbfe4b..70ef069da 100644 Binary files a/e107_web/js/plupload/Moxie.xap and b/e107_web/js/plupload/Moxie.xap differ diff --git a/e107_web/js/plupload/jquery.plupload.queue/img/buttons-disabled.png b/e107_web/js/plupload/jquery.plupload.queue/img/buttons-disabled.png index afa11af9b..c759e402f 100644 Binary files a/e107_web/js/plupload/jquery.plupload.queue/img/buttons-disabled.png and b/e107_web/js/plupload/jquery.plupload.queue/img/buttons-disabled.png differ diff --git a/e107_web/js/plupload/jquery.plupload.queue/img/buttons.png b/e107_web/js/plupload/jquery.plupload.queue/img/buttons.png index 153e73885..02a612221 100644 Binary files a/e107_web/js/plupload/jquery.plupload.queue/img/buttons.png and b/e107_web/js/plupload/jquery.plupload.queue/img/buttons.png differ diff --git a/e107_web/js/plupload/jquery.plupload.queue/img/transp50.png b/e107_web/js/plupload/jquery.plupload.queue/img/transp50.png index eb0efe104..61e6b217c 100644 Binary files a/e107_web/js/plupload/jquery.plupload.queue/img/transp50.png and b/e107_web/js/plupload/jquery.plupload.queue/img/transp50.png differ diff --git a/e107_web/js/plupload/jquery.plupload.queue/jquery.plupload.queue.js b/e107_web/js/plupload/jquery.plupload.queue/jquery.plupload.queue.js index 6894ecde9..f3f46288f 100644 --- a/e107_web/js/plupload/jquery.plupload.queue/jquery.plupload.queue.js +++ b/e107_web/js/plupload/jquery.plupload.queue/jquery.plupload.queue.js @@ -39,7 +39,7 @@ used as it is. var uploader = $('#uploader').pluploadQueue(); uploader.bind('FilesAdded', function() { - + // Autostart setTimeout(uploader.start, 1); // "detach" from the main thread }); @@ -73,7 +73,7 @@ used as it is. @param {Boolean} [settings.rename=false] Enable ability to rename files in the queue. @param {Boolean} [settings.multiple_queues=true] Re-activate the widget after each upload procedure. */ -;(function($, o) { +;(function($, plupload) { var uploaders = {}; function _(str) { @@ -190,7 +190,7 @@ used as it is. var icon = $('#' + file.id).attr('class', actionClass).find('a').css('display', 'block'); if (file.hint) { - icon.attr('title', file.hint); + icon.attr('title', file.hint); } } @@ -198,7 +198,7 @@ used as it is. $('span.plupload_total_status', target).html(uploader.total.percent + '%'); $('div.plupload_progress_bar', target).css('width', uploader.total.percent + '%'); $('span.plupload_upload_status', target).html( - o.sprintf(_('Uploaded %d/%d files'), uploader.total.uploaded, uploader.files.length) + plupload.sprintf(_('Uploaded %d/%d files'), uploader.total.uploaded, uploader.files.length) ); } @@ -215,7 +215,7 @@ used as it is. inputHTML += ''; inputHTML += ''; - + inputCount++; $('#' + id + '_count').val(inputCount); @@ -247,7 +247,7 @@ used as it is. if (uploader.total.queued === 0) { $('span.plupload_add_text', target).html(_('Add Files')); } else { - $('span.plupload_add_text', target).html(o.sprintf(_('%d files queued'), uploader.total.queued)); + $('span.plupload_add_text', target).html(plupload.sprintf(_('%d files queued'), uploader.total.queued)); } $('a.plupload_start', target).toggleClass('plupload_disabled', uploader.files.length == (uploader.total.uploaded + uploader.total.failed)); @@ -279,6 +279,11 @@ used as it is. if (!settings.unique_names && settings.rename) { target.on('click', '#' + id + '_filelist div.plupload_file_name span', function(e) { var targetSpan = $(e.target), file, parts, name, ext = ""; + var fileContainer = targetSpan.closest('li'); + + if (!fileContainer.hasClass('plupload_delete')) { + return; + } // Get file name and split out name and extension file = up.getFile(targetSpan.parents('li')[0].id); @@ -343,7 +348,7 @@ used as it is. if (err.code == plupload.FILE_EXTENSION_ERROR) { alert(_("Error: Invalid file extension:") + " " + file.name); } - + file.hint = message; $('#' + file.id).attr('class', 'plupload_failed').find('a').css('display', 'block').attr('title', message); } @@ -425,4 +430,4 @@ used as it is. return uploaders[$(this[0]).attr('id')]; } }; -})(jQuery, mOxie); +})(jQuery, plupload); diff --git a/e107_web/js/plupload/jquery.plupload.queue/jquery.plupload.queue.min.js b/e107_web/js/plupload/jquery.plupload.queue/jquery.plupload.queue.min.js index d7f7b9636..aaa71d9d4 100644 --- a/e107_web/js/plupload/jquery.plupload.queue/jquery.plupload.queue.min.js +++ b/e107_web/js/plupload/jquery.plupload.queue/jquery.plupload.queue.min.js @@ -1 +1 @@ -;(function(e,t){function r(e){return plupload.translate(e)||e}function i(t,n){n.contents().each(function(t,n){n=e(n),n.is(".plupload")||n.remove()}),n.prepend('
' +
@@ -272,22 +272,22 @@ function renderUI(obj) {
$.widget("ui.plupload", {
widgetEventPrefix: '',
-
+
contents_bak: '',
-
+
options: {
browse_button_hover: 'ui-state-hover',
browse_button_active: 'ui-state-active',
filters: {},
-
+
// widget specific
buttons: {
browse: true,
start: true,
- stop: true
+ stop: true
},
-
+
views: {
list: true,
thumbs: false,
@@ -299,14 +299,14 @@ $.widget("ui.plupload", {
thumb_height: 60,
multiple_queues: true, // re-use widget by default
- dragdrop : true,
+ dragdrop : true,
autostart: false,
sortable: false,
rename: false
},
-
+
FILE_COUNT_ERROR: -9001,
-
+
_create: function() {
var id = this.element.attr('id');
if (!id) {
@@ -314,30 +314,30 @@ $.widget("ui.plupload", {
this.element.attr('id', id);
}
this.id = id;
-
+
// backup the elements initial state
this.contents_bak = this.element.html();
renderUI(this.element);
-
+
// container, just in case
- this.container = $('.plupload_container', this.element).attr('id', id + '_container');
+ this.container = $('.plupload_container', this.element).attr('id', id + '_container');
this.content = $('.plupload_content', this.element);
-
+
if ($.fn.resizable) {
- this.container.resizable({
+ this.container.resizable({
handles: 's',
minHeight: 300
});
}
-
+
// list of files, may become sortable
this.filelist = $('.plupload_filelist_content', this.container)
.attr({
id: id + '_filelist',
unselectable: 'on'
});
-
+
// buttons
this.browse_button = $('.plupload_add', this.container).attr('id', id + '_browse');
@@ -345,22 +345,22 @@ $.widget("ui.plupload", {
this.stop_button = $('.plupload_stop', this.container).attr('id', id + '_stop');
this.thumbs_switcher = $('#' + id + '_view_thumbs');
this.list_switcher = $('#' + id + '_view_list');
-
+
if ($.ui.button) {
this.browse_button.button({
icons: { primary: 'ui-icon-circle-plus' },
disabled: true
});
-
+
this.start_button.button({
icons: { primary: 'ui-icon-circle-arrow-e' },
disabled: true
});
-
+
this.stop_button.button({
icons: { primary: 'ui-icon-circle-close' }
});
-
+
this.list_switcher.button({
text: false,
icons: { secondary: "ui-icon-grip-dotted-horizontal" }
@@ -371,21 +371,21 @@ $.widget("ui.plupload", {
icons: { secondary: "ui-icon-image" }
});
}
-
+
// progressbar
- this.progressbar = $('.plupload_progress_container', this.container);
-
+ this.progressbar = $('.plupload_progress_container', this.container);
+
if ($.ui.progressbar) {
this.progressbar.progressbar();
}
-
+
// counter
this.counter = $('.plupload_count', this.element)
.attr({
id: id + '_count',
name: id + '_count'
});
-
+
// initialize uploader instance
this._initUploader();
},
@@ -394,7 +394,7 @@ $.widget("ui.plupload", {
var self = this
, id = this.id
, uploader
- , options = {
+ , options = {
container: id + '_buttons',
browse_button: id + '_browse'
}
@@ -408,9 +408,13 @@ $.widget("ui.plupload", {
}
this.filelist.on('click', function(e) {
- if ($(e.target).hasClass('plupload_action_icon')) {
- self.removeFile($(e.target).closest('.plupload_file').attr('id'));
- e.preventDefault();
+ var me = $(e.target), fileContainer;
+ if (me.hasClass('plupload_action_icon')) {
+ fileContainer = me.closest('.plupload_file');
+ if (fileContainer.hasClass('plupload_delete')) {
+ self.removeFile(fileContainer.attr('id'));
+ e.preventDefault();
+ }
}
});
@@ -434,7 +438,7 @@ $.widget("ui.plupload", {
if (maxCount <= this.files.length - (this.total.uploaded + this.total.failed)) {
self.browse_button.button('disable');
this.disableBrowse();
-
+
this.trigger('Error', {
code : self.FILE_COUNT_ERROR,
message : _("File count error."),
@@ -447,41 +451,41 @@ $.widget("ui.plupload", {
});
- uploader.bind('Error', function(up, err) {
+ uploader.bind('Error', function(up, err) {
var message, details = "";
message = '' + err.message + '';
-
+
switch (err.code) {
case plupload.FILE_EXTENSION_ERROR:
- details = o.sprintf(_("File: %s"), err.file.name);
+ details = plupload.sprintf(_("File: %s"), err.file.name);
break;
-
+
case plupload.FILE_SIZE_ERROR:
- details = o.sprintf(_("File: %s, size: %d, max file size: %d"), err.file.name, plupload.formatSize(err.file.size), plupload.formatSize(plupload.parseSize(up.getOption('filters').max_file_size)));
+ details = plupload.sprintf(_("File: %s, size: %d, max file size: %d"), err.file.name, plupload.formatSize(err.file.size), plupload.formatSize(plupload.parseSize(up.getOption('filters').max_file_size)));
break;
case plupload.FILE_DUPLICATE_ERROR:
- details = o.sprintf(_("%s already present in the queue."), err.file.name);
+ details = plupload.sprintf(_("%s already present in the queue."), err.file.name);
break;
-
+
case self.FILE_COUNT_ERROR:
- details = o.sprintf(_("Upload element accepts only %d file(s) at a time. Extra files were stripped."), up.getOption('filters').max_file_count || 0);
+ details = plupload.sprintf(_("Upload element accepts only %d file(s) at a time. Extra files were stripped."), up.getOption('filters').max_file_count || 0);
break;
-
+
case plupload.IMAGE_FORMAT_ERROR :
details = _("Image format either wrong or not supported.");
- break;
-
+ break;
+
case plupload.IMAGE_MEMORY_ERROR :
details = _("Runtime ran out of available memory.");
break;
-
+
/* // This needs a review
case plupload.IMAGE_DIMENSIONS_ERROR :
- details = o.sprintf(_('Resoultion out of boundaries! %s runtime supports images only up to %wx%hpx.'), up.runtime, up.features.maxWidth, up.features.maxHeight);
+ details = plupload.sprintf(_('Resoultion out of boundaries! %s runtime supports images only up to %wx%hpx.'), up.runtime, up.features.maxWidth, up.features.maxHeight);
break; */
-
+
case plupload.HTTP_ERROR:
details = _("Upload URL might be wrong or doesn't exist.");
break;
@@ -501,8 +505,8 @@ $.widget("ui.plupload", {
}
});
-
- uploader.bind('PostInit', function(up) {
+
+ uploader.bind('PostInit', function(up) {
// all buttons are optional, so they can be disabled and hidden
if (!self.options.buttons.browse) {
self.browse_button.button('disable').hide();
@@ -510,17 +514,17 @@ $.widget("ui.plupload", {
} else {
self.browse_button.button('enable');
}
-
+
if (!self.options.buttons.start) {
self.start_button.button('disable').hide();
- }
-
+ }
+
if (!self.options.buttons.stop) {
self.stop_button.button('disable').hide();
}
-
+
if (!self.options.unique_names && self.options.rename) {
- self._enableRenaming();
+ self._enableRenaming();
}
if (self.options.dragdrop && up.features.dragdrop) {
@@ -528,7 +532,7 @@ $.widget("ui.plupload", {
}
self._enableViewSwitcher();
-
+
self.start_button.click(function(e) {
if (!$(this).button('option', 'disabled')) {
self.start();
@@ -543,24 +547,24 @@ $.widget("ui.plupload", {
self._trigger('ready', null, { up: up });
});
-
- // uploader internal events must run first
+
+ // uploader internal events must run first
uploader.init();
uploader.bind('FileFiltered', function(up, file) {
self._addFiles(file);
});
-
+
uploader.bind('FilesAdded', function(up, files) {
self._trigger('selected', null, { up: up, files: files } );
// re-enable sortable
if (self.options.sortable && $.ui.sortable) {
- self._enableSortingList();
+ self._enableSortingList();
}
self._trigger('updatelist', null, { filelist: self.filelist });
-
+
if (self.options.autostart) {
// set a little delay to make sure that QueueChanged triggered by the core has time to complete
setTimeout(function() {
@@ -568,11 +572,11 @@ $.widget("ui.plupload", {
}, 10);
}
});
-
+
uploader.bind('FilesRemoved', function(up, files) {
// destroy sortable if enabled
if ($.ui.sortable && self.options.sortable) {
- $('tbody', self.filelist).sortable('destroy');
+ $('tbody', self.filelist).sortable('destroy');
}
$.each(files, function(i, file) {
@@ -580,18 +584,18 @@ $.widget("ui.plupload", {
$(this).remove();
});
});
-
+
if (up.files.length) {
// re-initialize sortable
if (self.options.sortable && $.ui.sortable) {
- self._enableSortingList();
+ self._enableSortingList();
}
}
self._trigger('updatelist', null, { filelist: self.filelist });
self._trigger('removed', null, { up: up, files: files } );
});
-
+
uploader.bind('QueueChanged', function() {
self._handleState();
});
@@ -604,35 +608,35 @@ $.widget("ui.plupload", {
self._trigger('stopped', null, { up: this.uploader });
}
});
-
+
uploader.bind('UploadFile', function(up, file) {
self._handleFileStatus(file);
});
-
+
uploader.bind('FileUploaded', function(up, file, result) {
self._handleFileStatus(file);
self._trigger('uploaded', null, { up: up, file: file, result: result } );
});
-
+
uploader.bind('UploadProgress', function(up, file) {
self._handleFileStatus(file);
self._updateTotalProgress();
self._trigger('progress', null, { up: up, file: file } );
});
-
+
uploader.bind('UploadComplete', function(up, files) {
- self._addFormFields();
+ self._addFormFields();
self._trigger('complete', null, { up: up, files: files } );
});
},
-
+
_setOption: function(key, value) {
var self = this;
- if (key == 'buttons' && typeof(value) == 'object') {
+ if (key == 'buttons' && typeof(value) == 'object') {
value = $.extend(self.options.buttons, value);
-
+
if (!value.browse) {
self.browse_button.button('disable').hide();
self.uploader.disableBrowse(true);
@@ -640,24 +644,24 @@ $.widget("ui.plupload", {
self.browse_button.button('enable').show();
self.uploader.disableBrowse(false);
}
-
+
if (!value.start) {
self.start_button.button('disable').hide();
} else {
self.start_button.button('enable').show();
}
-
+
if (!value.stop) {
self.stop_button.button('disable').hide();
} else {
- self.start_button.button('enable').show();
+ self.start_button.button('enable').show();
}
}
-
- self.uploader.setOption(key, value);
+
+ self.uploader.setOption(key, value);
},
-
+
/**
Start upload. Triggers `start` event.
@@ -667,7 +671,7 @@ $.widget("ui.plupload", {
this.uploader.start();
},
-
+
/**
Stop upload. Triggers `stop` event.
@@ -699,7 +703,7 @@ $.widget("ui.plupload", {
this.uploader.disableBrowse(true);
},
-
+
/**
Retrieve file by its unique id.
@@ -709,18 +713,18 @@ $.widget("ui.plupload", {
*/
getFile: function(id) {
var file;
-
+
if (typeof id === 'number') {
- file = this.uploader.files[id];
+ file = this.uploader.files[id];
} else {
- file = this.uploader.getFile(id);
+ file = this.uploader.getFile(id);
}
return file;
},
/**
Return array of files currently in the queue.
-
+
@method getFiles
@return {Array} Array of files in the queue represented by plupload.File objects
*/
@@ -728,7 +732,7 @@ $.widget("ui.plupload", {
return this.uploader.files;
},
-
+
/**
Remove the file from the queue.
@@ -742,7 +746,7 @@ $.widget("ui.plupload", {
this.uploader.removeFile(file);
},
-
+
/**
Clear the file queue.
@@ -786,12 +790,12 @@ $.widget("ui.plupload", {
*/
notify: function(type, message) {
var popup = $(
- ' ' +
- '{percent} ' +
' ' +
' ' +
+ ' ' +
'' +
'{name} ' +
- ' ' +
+ '' +
'' +
' ' +
@@ -1143,14 +1152,14 @@ $.widget("ui.plupload", {
}
$.each(files, function(i, file) {
- var ext = o.Mime.getFileExtension(file.name) || 'none';
+ var ext = o.core.utils.Mime.getFileExtension(file.name) || 'none';
html += file_html.replace(/\{(\w+)\}/g, function($0, $1) {
switch ($1) {
case 'thumb_width':
case 'thumb_height':
return self.options[$1];
-
+
case 'size':
return plupload.formatSize(file.size);
@@ -1189,20 +1198,20 @@ $.widget("ui.plupload", {
this.counter.val(this.uploader.files.length);
},
-
+
_viewChanged: function(view) {
// update or write a new cookie
if (this.options.views.remember && $.cookie) {
$.cookie('plupload_ui_view', view, { expires: 7, path: '/' });
- }
-
+ }
+
// ugly fix for IE6 - make content area stretchable
- if (o.Env.browser === 'IE' && o.Env.version < 7) {
+ if (plupload.ua.browser === 'IE' && plupload.ua.version < 7) {
this.content.attr('style', 'height:expression(document.getElementById("' + this.id + '_container' + '").clientHeight - ' + (view === 'list' ? 132 : 102) + ')');
}
- this.container.removeClass('plupload_view_list plupload_view_thumbs').addClass('plupload_view_' + view);
+ this.container.removeClass('plupload_view_list plupload_view_thumbs').addClass('plupload_view_' + view);
this.view_mode = view;
this._trigger('viewchanged', null, { view: view });
},
@@ -1264,20 +1273,26 @@ $.widget("ui.plupload", {
this._displayThumbs();
}
},
-
-
+
+
_enableRenaming: function() {
var self = this;
this.filelist.dblclick(function(e) {
- var nameSpan = $(e.target), nameInput, file, parts, name, ext = "";
+ var nameInput, fileContainer, file, parts, name, ext = "";
+ var nameSpan = $(e.target);
if (!nameSpan.hasClass('plupload_file_name_wrapper')) {
return;
}
-
+
+ fileContainer = nameSpan.closest('.plupload_file');
+ if (!fileContainer.hasClass('plupload_delete')) {
+ return;
+ }
+
// Get file name and split out name and extension
- file = self.uploader.getFile(nameSpan.closest('.plupload_file')[0].id);
+ file = self.uploader.getFile(fileContainer[0].id);
name = file.name;
parts = /^(.+)(\.[^.]+)$/.exec(name);
if (parts) {
@@ -1305,39 +1320,39 @@ $.widget("ui.plupload", {
})[0].focus();
});
},
-
-
+
+
_enableSortingList: function() {
var self = this;
-
+
if ($('.plupload_file', this.filelist).length < 2) {
- return;
+ return;
}
// destroy sortable if enabled
- $('tbody', this.filelist).sortable('destroy');
-
- // enable
+ $('tbody', this.filelist).sortable('destroy');
+
+ // enable
this.filelist.sortable({
items: '.plupload_delete',
-
+
cancel: 'object, .plupload_clearer',
stop: function() {
var files = [];
-
+
$.each($(this).sortable('toArray'), function(i, id) {
files[files.length] = self.uploader.getFile(id);
- });
-
+ });
+
files.unshift(files.length);
files.unshift(0);
-
- // re-populate files array
- Array.prototype.splice.apply(self.uploader.files, files);
+
+ // re-populate files array
+ Array.prototype.splice.apply(self.uploader.files, files);
}
- });
+ });
}
});
-} (window, document, plupload, mOxie, jQuery));
+} (window, document, plupload, moxie, jQuery));
diff --git a/e107_web/js/plupload/moxie.js b/e107_web/js/plupload/moxie.js
index f9fe69f39..65f33166c 100644
--- a/e107_web/js/plupload/moxie.js
+++ b/e107_web/js/plupload/moxie.js
@@ -1,7 +1,7 @@
;var MXI_DEBUG = true;
/**
* mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill
- * v1.3.5
+ * v1.5.7
*
* Copyright 2013, Moxiecode Systems AB
* Released under GPL License.
@@ -9,8 +9,23 @@
* License: http://www.plupload.com/license
* Contributing: http://www.plupload.com/contributing
*
- * Date: 2016-05-15
+ * Date: 2017-11-03
*/
+;(function (global, factory) {
+ var extract = function() {
+ var ctx = {};
+ factory.apply(ctx, arguments);
+ return ctx.moxie;
+ };
+
+ if (typeof define === "function" && define.amd) {
+ define("moxie", [], extract);
+ } else if (typeof module === "object" && module.exports) {
+ module.exports = extract();
+ } else {
+ global.moxie = extract();
+ }
+}(this || window, function() {
/**
* Compiled inline version. (Library mode)
*/
@@ -105,18 +120,23 @@
* Contributing: http://www.plupload.com/contributing
*/
+/**
+@class moxie/core/utils/Basic
+@public
+@static
+*/
+
define('moxie/core/utils/Basic', [], function() {
/**
Gets the true type of the built-in object (better version of typeof).
@author Angus Croll (http://javascriptweblog.wordpress.com/)
@method typeOf
- @for Utils
@static
@param {Object} o Object to check.
@return {String} Object [[Class]]
*/
- var typeOf = function(o) {
+ function typeOf(o) {
var undef;
if (o === undef) {
@@ -129,10 +149,10 @@ define('moxie/core/utils/Basic', [], function() {
// the snippet below is awesome, however it fails to detect null, undefined and arguments types in IE lte 8
return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
- };
-
+ }
+
/**
- Extends the specified object with another object.
+ Extends the specified object with another object(s).
@method extend
@static
@@ -140,25 +160,131 @@ define('moxie/core/utils/Basic', [], function() {
@param {Object} [obj]* Multiple objects to extend with.
@return {Object} Same as target, the extended object.
*/
- var extend = function(target) {
- var undef;
+ function extend() {
+ return merge(false, false, arguments);
+ }
- each(arguments, function(arg, i) {
+
+ /**
+ Extends the specified object with another object(s), but only if the property exists in the target.
+
+ @method extendIf
+ @static
+ @param {Object} target Object to extend.
+ @param {Object} [obj]* Multiple objects to extend with.
+ @return {Object} Same as target, the extended object.
+ */
+ function extendIf() {
+ return merge(true, false, arguments);
+ }
+
+
+ function extendImmutable() {
+ return merge(false, true, arguments);
+ }
+
+
+ function extendImmutableIf() {
+ return merge(true, true, arguments);
+ }
+
+
+ function clone(value) {
+ switch (typeOf(value)) {
+ case 'array':
+ return merge(false, true, [[], value]);
+
+ case 'object':
+ return merge(false, true, [{}, value]);
+
+ default:
+ return value;
+ }
+ }
+
+
+ function shallowCopy(obj) {
+ switch (typeOf(obj)) {
+ case 'array':
+ return Array.prototype.slice.call(obj);
+
+ case 'object':
+ return extend({}, obj);
+ }
+ return obj;
+ }
+
+
+ function merge(strict, immutable, args) {
+ var undef;
+ var target = args[0];
+
+ each(args, function(arg, i) {
if (i > 0) {
each(arg, function(value, key) {
- if (value !== undef) {
- if (typeOf(target[key]) === typeOf(value) && !!~inArray(typeOf(value), ['array', 'object'])) {
- extend(target[key], value);
- } else {
- target[key] = value;
- }
+ var isComplex = inArray(typeOf(value), ['array', 'object']) !== -1;
+
+ if (value === undef || strict && target[key] === undef) {
+ return true;
+ }
+
+ if (isComplex && immutable) {
+ value = shallowCopy(value);
+ }
+
+ if (typeOf(target[key]) === typeOf(value) && isComplex) {
+ merge(strict, immutable, [target[key], value]);
+ } else {
+ target[key] = value;
}
});
}
});
+
return target;
- };
-
+ }
+
+
+ /**
+ A way to inherit one `class` from another in a consisstent way (more or less)
+
+ @method inherit
+ @static
+ @since >1.4.1
+ @param {Function} child
+ @param {Function} parent
+ @return {Function} Prepared constructor
+ */
+ function inherit(child, parent) {
+ // copy over all parent properties
+ for (var key in parent) {
+ if ({}.hasOwnProperty.call(parent, key)) {
+ child[key] = parent[key];
+ }
+ }
+
+ // give child `class` a place to define its own methods
+ function ctor() {
+ this.constructor = child;
+
+ if (MXI_DEBUG) {
+ var getCtorName = function(fn) {
+ var m = fn.toString().match(/^function\s([^\(\s]+)/);
+ return m ? m[1] : false;
+ };
+
+ this.ctorName = getCtorName(child);
+ }
+ }
+ ctor.prototype = parent.prototype;
+ child.prototype = new ctor();
+
+ // keep a way to reference parent methods
+ child.parent = parent.prototype;
+ return child;
+ }
+
+
/**
Executes the callback function for each item in array/object. If you return false in the
callback it will break the loop.
@@ -168,18 +294,17 @@ define('moxie/core/utils/Basic', [], function() {
@param {Object} obj Object to iterate.
@param {function} callback Callback function to execute for each item.
*/
- var each = function(obj, callback) {
+ function each(obj, callback) {
var length, key, i, undef;
if (obj) {
- if (typeOf(obj.length) === 'number') { // it might be Array, FileList or even arguments object
- // Loop array items
- for (i = 0, length = obj.length; i < length; i++) {
- if (callback(obj[i], i) === false) {
- return;
- }
- }
- } else if (typeOf(obj) === 'object') {
+ try {
+ length = obj.length;
+ } catch(ex) {
+ length = undef;
+ }
+
+ if (length === undef || typeof(length) !== 'number') {
// Loop object items
for (key in obj) {
if (obj.hasOwnProperty(key)) {
@@ -188,19 +313,26 @@ define('moxie/core/utils/Basic', [], function() {
}
}
}
+ } else {
+ // Loop array items
+ for (i = 0; i < length; i++) {
+ if (callback(obj[i], i) === false) {
+ return;
+ }
+ }
}
}
- };
+ }
/**
Checks if object is empty.
-
+
@method isEmptyObj
@static
@param {Object} o Object to check.
@return {Boolean}
*/
- var isEmptyObj = function(obj) {
+ function isEmptyObj(obj) {
var prop;
if (!obj || typeOf(obj) !== 'object') {
@@ -212,7 +344,7 @@ define('moxie/core/utils/Basic', [], function() {
}
return true;
- };
+ }
/**
Recieve an array of functions (usually async) to call in sequence, each function
@@ -226,7 +358,7 @@ define('moxie/core/utils/Basic', [], function() {
@param {Array} queue Array of functions to call in sequence
@param {Function} cb Main callback that is called in the end, or in case of error
*/
- var inSeries = function(queue, cb) {
+ function inSeries(queue, cb) {
var i = 0, length = queue.length;
if (typeOf(cb) !== 'function') {
@@ -246,12 +378,12 @@ define('moxie/core/utils/Basic', [], function() {
}
}
callNext(i);
- };
+ }
/**
Recieve an array of functions (usually async) to call in parallel, each function
- receives a callback as first argument that it should call, when it completes. After
+ receives a callback as first argument that it should call, when it completes. After
everything is complete, main callback is called. Passing truthy value to the
callback as a first argument will interrupt the process and invoke main callback
immediately.
@@ -259,9 +391,9 @@ define('moxie/core/utils/Basic', [], function() {
@method inParallel
@static
@param {Array} queue Array of functions to call in sequence
- @param {Function} cb Main callback that is called in the end, or in case of error
+ @param {Function} cb Main callback that is called in the end, or in case of erro
*/
- var inParallel = function(queue, cb) {
+ function inParallel(queue, cb) {
var count = 0, num = queue.length, cbArgs = new Array(num);
each(queue, function(fn, i) {
@@ -269,7 +401,7 @@ define('moxie/core/utils/Basic', [], function() {
if (error) {
return cb(error);
}
-
+
var args = [].slice.call(arguments);
args.shift(); // strip error - undefined or not
@@ -279,27 +411,27 @@ define('moxie/core/utils/Basic', [], function() {
if (count === num) {
cbArgs.unshift(null);
cb.apply(this, cbArgs);
- }
+ }
});
});
- };
-
-
+ }
+
+
/**
Find an element in array and return it's index if present, otherwise return -1.
-
+
@method inArray
@static
@param {Mixed} needle Element to find
@param {Array} array
@return {Int} Index of the element, or -1 if not found
*/
- var inArray = function(needle, array) {
+ function inArray(needle, array) {
if (array) {
if (Array.prototype.indexOf) {
return Array.prototype.indexOf.call(array, needle);
}
-
+
for (var i = 0, length = array.length; i < length; i++) {
if (array[i] === needle) {
return i;
@@ -307,7 +439,7 @@ define('moxie/core/utils/Basic', [], function() {
}
}
return -1;
- };
+ }
/**
@@ -319,7 +451,7 @@ define('moxie/core/utils/Basic', [], function() {
@param {Array} array
@return {Array|Boolean}
*/
- var arrayDiff = function(needles, array) {
+ function arrayDiff(needles, array) {
var diff = [];
if (typeOf(needles) !== 'array') {
@@ -333,10 +465,10 @@ define('moxie/core/utils/Basic', [], function() {
for (var i in needles) {
if (inArray(needles[i], array) === -1) {
diff.push(needles[i]);
- }
+ }
}
return diff.length ? diff : false;
- };
+ }
/**
@@ -348,7 +480,7 @@ define('moxie/core/utils/Basic', [], function() {
@param {Array} array2
@return {Array} Intersection of two arrays or null if there is none
*/
- var arrayIntersect = function(array1, array2) {
+ function arrayIntersect(array1, array2) {
var result = [];
each(array1, function(item) {
if (inArray(item, array2) !== -1) {
@@ -356,18 +488,18 @@ define('moxie/core/utils/Basic', [], function() {
}
});
return result.length ? result : null;
- };
-
-
+ }
+
+
/**
Forces anything into an array.
-
+
@method toArray
@static
@param {Object} obj Object with length field.
@return {Array} Array object containing all items.
*/
- var toArray = function(obj) {
+ function toArray(obj) {
var i, arr = [];
for (i = 0; i < obj.length; i++) {
@@ -375,15 +507,15 @@ define('moxie/core/utils/Basic', [], function() {
}
return arr;
- };
-
-
+ }
+
+
/**
Generates an unique ID. The only way a user would be able to get the same ID is if the two persons
- at the same exact millisecond manage to get the same 5 random numbers between 0-65535; it also uses
- a counter so each ID is guaranteed to be unique for the given page. It is more probable for the earth
+ at the same exact millisecond manage to get the same 5 random numbers between 0-65535; it also uses
+ a counter so each ID is guaranteed to be unique for the given page. It is more probable for the earth
to be hit with an asteroid.
-
+
@method guid
@static
@param {String} prefix to prepend (by default 'o' will be prepended).
@@ -392,48 +524,48 @@ define('moxie/core/utils/Basic', [], function() {
*/
var guid = (function() {
var counter = 0;
-
+
return function(prefix) {
var guid = new Date().getTime().toString(32), i;
for (i = 0; i < 5; i++) {
guid += Math.floor(Math.random() * 65535).toString(32);
}
-
+
return (prefix || 'o_') + guid + (counter++).toString(32);
};
}());
-
+
/**
Trims white spaces around the string
-
+
@method trim
@static
@param {String} str
@return {String}
*/
- var trim = function(str) {
+ function trim(str) {
if (!str) {
return str;
}
return String.prototype.trim ? String.prototype.trim.call(str) : str.toString().replace(/^\s*/, '').replace(/\s*$/, '');
- };
+ }
/**
Parses the specified size string into a byte value. For example 10kb becomes 10240.
-
+
@method parseSizeStr
@static
@param {String/Number} size String to parse or number to just pass through.
@return {Number} Size in bytes.
*/
- var parseSizeStr = function(size) {
+ function parseSizeStr(size) {
if (typeof(size) !== 'string') {
return size;
}
-
+
var muls = {
t: 1099511627776,
g: 1073741824,
@@ -442,16 +574,15 @@ define('moxie/core/utils/Basic', [], function() {
},
mul;
-
size = /^([0-9\.]+)([tmgk]?)$/.exec(size.toLowerCase().replace(/[^0-9\.tmkg]/g, ''));
mul = size[2];
size = +size[1];
-
+
if (muls.hasOwnProperty(mul)) {
size *= muls[mul];
}
return Math.floor(size);
- };
+ }
/**
@@ -460,20 +591,50 @@ define('moxie/core/utils/Basic', [], function() {
* @param {String} str String with tokens
* @return {String} String with replaced tokens
*/
- var sprintf = function(str) {
+ function sprintf(str) {
var args = [].slice.call(arguments, 1);
- return str.replace(/%[a-z]/g, function() {
+ return str.replace(/%([a-z])/g, function($0, $1) {
var value = args.shift();
- return typeOf(value) !== 'undefined' ? value : '';
+
+ switch ($1) {
+ case 's':
+ return value + '';
+
+ case 'd':
+ return parseInt(value, 10);
+
+ case 'f':
+ return parseFloat(value);
+
+ case 'c':
+ return '';
+
+ default:
+ return value;
+ }
});
- };
-
+ }
+
+
+
+ function delay(cb, timeout) {
+ var self = this;
+ setTimeout(function() {
+ cb.call(self);
+ }, timeout || 1);
+ }
+
return {
guid: guid,
typeOf: typeOf,
extend: extend,
+ extendIf: extendIf,
+ extendImmutable: extendImmutable,
+ extendImmutableIf: extendImmutableIf,
+ clone: clone,
+ inherit: inherit,
each: each,
isEmptyObj: isEmptyObj,
inSeries: inSeries,
@@ -484,7 +645,193 @@ define('moxie/core/utils/Basic', [], function() {
toArray: toArray,
trim: trim,
sprintf: sprintf,
- parseSizeStr: parseSizeStr
+ parseSizeStr: parseSizeStr,
+ delay: delay
+ };
+});
+
+// Included from: src/javascript/core/utils/Encode.js
+
+/**
+ * Encode.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/core/utils/Encode
+@public
+@static
+*/
+
+define('moxie/core/utils/Encode', [], function() {
+
+ /**
+ Encode string with UTF-8
+
+ @method utf8_encode
+ @static
+ @param {String} str String to encode
+ @return {String} UTF-8 encoded string
+ */
+ var utf8_encode = function(str) {
+ return unescape(encodeURIComponent(str));
+ };
+
+ /**
+ Decode UTF-8 encoded string
+
+ @method utf8_decode
+ @static
+ @param {String} str String to decode
+ @return {String} Decoded string
+ */
+ var utf8_decode = function(str_data) {
+ return decodeURIComponent(escape(str_data));
+ };
+
+ /**
+ Decode Base64 encoded string (uses browser's default method if available),
+ from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_decode.js
+
+ @method atob
+ @static
+ @param {String} data String to decode
+ @return {String} Decoded string
+ */
+ var atob = function(data, utf8) {
+ if (typeof(window.atob) === 'function') {
+ return utf8 ? utf8_decode(window.atob(data)) : window.atob(data);
+ }
+
+ // http://kevin.vanzonneveld.net
+ // + original by: Tyler Akins (http://rumkin.com)
+ // + improved by: Thunder.m
+ // + input by: Aman Gupta
+ // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+ // + bugfixed by: Onno Marsman
+ // + bugfixed by: Pellentesque Malesuada
+ // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+ // + input by: Brett Zamir (http://brett-zamir.me)
+ // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+ // * example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
+ // * returns 1: 'Kevin van Zonneveld'
+ // mozilla has this native
+ // - but breaks in 2.0.0.12!
+ //if (typeof this.window.atob == 'function') {
+ // return atob(data);
+ //}
+ var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+ var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
+ ac = 0,
+ dec = "",
+ tmp_arr = [];
+
+ if (!data) {
+ return data;
+ }
+
+ data += '';
+
+ do { // unpack four hexets into three octets using index points in b64
+ h1 = b64.indexOf(data.charAt(i++));
+ h2 = b64.indexOf(data.charAt(i++));
+ h3 = b64.indexOf(data.charAt(i++));
+ h4 = b64.indexOf(data.charAt(i++));
+
+ bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
+
+ o1 = bits >> 16 & 0xff;
+ o2 = bits >> 8 & 0xff;
+ o3 = bits & 0xff;
+
+ if (h3 == 64) {
+ tmp_arr[ac++] = String.fromCharCode(o1);
+ } else if (h4 == 64) {
+ tmp_arr[ac++] = String.fromCharCode(o1, o2);
+ } else {
+ tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
+ }
+ } while (i < data.length);
+
+ dec = tmp_arr.join('');
+
+ return utf8 ? utf8_decode(dec) : dec;
+ };
+
+ /**
+ Base64 encode string (uses browser's default method if available),
+ from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_encode.js
+
+ @method btoa
+ @static
+ @param {String} data String to encode
+ @return {String} Base64 encoded string
+ */
+ var btoa = function(data, utf8) {
+ if (utf8) {
+ data = utf8_encode(data);
+ }
+
+ if (typeof(window.btoa) === 'function') {
+ return window.btoa(data);
+ }
+
+ // http://kevin.vanzonneveld.net
+ // + original by: Tyler Akins (http://rumkin.com)
+ // + improved by: Bayron Guevara
+ // + improved by: Thunder.m
+ // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+ // + bugfixed by: Pellentesque Malesuada
+ // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+ // + improved by: Rafał Kukawski (http://kukawski.pl)
+ // * example 1: base64_encode('Kevin van Zonneveld');
+ // * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
+ // mozilla has this native
+ // - but breaks in 2.0.0.12!
+ var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+ var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
+ ac = 0,
+ enc = "",
+ tmp_arr = [];
+
+ if (!data) {
+ return data;
+ }
+
+ do { // pack three octets into four hexets
+ o1 = data.charCodeAt(i++);
+ o2 = data.charCodeAt(i++);
+ o3 = data.charCodeAt(i++);
+
+ bits = o1 << 16 | o2 << 8 | o3;
+
+ h1 = bits >> 18 & 0x3f;
+ h2 = bits >> 12 & 0x3f;
+ h3 = bits >> 6 & 0x3f;
+ h4 = bits & 0x3f;
+
+ // use hexets to index into b64, and append result to encoded string
+ tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
+ } while (i < data.length);
+
+ enc = tmp_arr.join('');
+
+ var r = data.length % 3;
+
+ return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
+ };
+
+
+ return {
+ utf8_encode: utf8_encode,
+ utf8_decode: utf8_decode,
+ atob: atob,
+ btoa: btoa
};
});
@@ -500,10 +847,16 @@ define('moxie/core/utils/Basic', [], function() {
* Contributing: http://www.plupload.com/contributing
*/
+/**
+@class moxie/core/utils/Env
+@public
+@static
+*/
+
define("moxie/core/utils/Env", [
"moxie/core/utils/Basic"
], function(Basic) {
-
+
/**
* UAParser.js v0.7.7
* Lightweight JavaScript-based User-Agent string parser
@@ -706,7 +1059,7 @@ define("moxie/core/utils/Env", [
var regexes = {
browser : [[
-
+
// Presto based
/(opera\smini)\/([\w\.-]+)/i, // Opera Mini
/(opera\s[mobiletab]+).+version\/([\w\.-]+)/i, // Opera Mobi/Tablet
@@ -1041,85 +1394,119 @@ define("moxie/core/utils/Env", [
var can = (function() {
var caps = {
- define_property: (function() {
- /* // currently too much extra code required, not exactly worth it
- try { // as of IE8, getters/setters are supported only on DOM elements
- var obj = {};
- if (Object.defineProperty) {
- Object.defineProperty(obj, 'prop', {
- enumerable: true,
- configurable: true
- });
- return true;
- }
- } catch(ex) {}
+ access_global_ns: function () {
+ return !!window.moxie;
+ },
- if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) {
+ define_property: (function() {
+ /* // currently too much extra code required, not exactly worth it
+ try { // as of IE8, getters/setters are supported only on DOM elements
+ var obj = {};
+ if (Object.defineProperty) {
+ Object.defineProperty(obj, 'prop', {
+ enumerable: true,
+ configurable: true
+ });
return true;
- }*/
- return false;
- }()),
-
- create_canvas: (function() {
- // On the S60 and BB Storm, getContext exists, but always returns undefined
- // so we actually have to call getContext() to verify
- // github.com/Modernizr/Modernizr/issues/issue/97/
- var el = document.createElement('canvas');
- return !!(el.getContext && el.getContext('2d'));
- }()),
-
- return_response_type: function(responseType) {
- try {
- if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) {
- return true;
- } else if (window.XMLHttpRequest) {
- var xhr = new XMLHttpRequest();
- xhr.open('get', '/'); // otherwise Gecko throws an exception
- if ('responseType' in xhr) {
- xhr.responseType = responseType;
- // as of 23.0.1271.64, Chrome switched from throwing exception to merely logging it to the console (why? o why?)
- if (xhr.responseType !== responseType) {
- return false;
- }
- return true;
- }
- }
- } catch (ex) {}
- return false;
- },
-
- // ideas for this heavily come from Modernizr (http://modernizr.com/)
- use_data_uri: (function() {
- var du = new Image();
-
- du.onload = function() {
- caps.use_data_uri = (du.width === 1 && du.height === 1);
- };
-
- setTimeout(function() {
- du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";
- }, 1);
- return false;
- }()),
-
- use_data_uri_over32kb: function() { // IE8
- return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9);
- },
-
- use_data_uri_of: function(bytes) {
- return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb());
- },
-
- use_fileinput: function() {
- if (navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/)) {
- return false;
}
+ } catch(ex) {}
- var el = document.createElement('input');
- el.setAttribute('type', 'file');
- return !el.disabled;
+ if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) {
+ return true;
+ }*/
+ return false;
+ }()),
+
+ create_canvas: function() {
+ // On the S60 and BB Storm, getContext exists, but always returns undefined
+ // so we actually have to call getContext() to verify
+ // github.com/Modernizr/Modernizr/issues/issue/97/
+ var el = document.createElement('canvas');
+ var isSupported = !!(el.getContext && el.getContext('2d'));
+ caps.create_canvas = isSupported;
+ return isSupported;
+ },
+
+ return_response_type: function(responseType) {
+ try {
+ if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) {
+ return true;
+ } else if (window.XMLHttpRequest) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('get', '/'); // otherwise Gecko throws an exception
+ if ('responseType' in xhr) {
+ xhr.responseType = responseType;
+ // as of 23.0.1271.64, Chrome switched from throwing exception to merely logging it to the console (why? o why?)
+ if (xhr.responseType !== responseType) {
+ return false;
+ }
+ return true;
+ }
+ }
+ } catch (ex) {}
+ return false;
+ },
+
+ use_blob_uri: function() {
+ var URL = window.URL;
+ caps.use_blob_uri = (URL &&
+ 'createObjectURL' in URL &&
+ 'revokeObjectURL' in URL &&
+ (Env.browser !== 'IE' || Env.verComp(Env.version, '11.0.46', '>=')) // IE supports createObjectURL, but not fully, for example it fails to use it as a src for the image
+ );
+ return caps.use_blob_uri;
+ },
+
+ // ideas for this heavily come from Modernizr (http://modernizr.com/)
+ use_data_uri: (function() {
+ var du = new Image();
+
+ du.onload = function() {
+ caps.use_data_uri = (du.width === 1 && du.height === 1);
+ };
+
+ setTimeout(function() {
+ du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";
+ }, 1);
+ return false;
+ }()),
+
+ use_data_uri_over32kb: function() { // IE8
+ return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9);
+ },
+
+ use_data_uri_of: function(bytes) {
+ return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb());
+ },
+
+ use_fileinput: function() {
+ if (navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/)) {
+ return false;
}
- };
+
+ var el = document.createElement('input');
+ el.setAttribute('type', 'file');
+ return caps.use_fileinput = !el.disabled;
+ },
+
+ use_webgl: function() {
+ var canvas = document.createElement('canvas');
+ var gl = null, isSupported;
+ try {
+ gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+ }
+ catch(e) {}
+
+ if (!gl) { // it seems that sometimes it doesn't throw exception, but still fails to get context
+ gl = null;
+ }
+
+ isSupported = !!gl;
+ caps.use_webgl = isSupported; // save result of our check
+ canvas = undefined;
+ return isSupported;
+ }
+ };
return function(cap) {
var args = [].slice.call(arguments);
@@ -1136,14 +1523,14 @@ define("moxie/core/utils/Env", [
can: can,
uaParser: UAParser,
-
+
browser: uaResult.browser.name,
version: uaResult.browser.version,
os: uaResult.os.name, // everybody intuitively types it in a lowercase for some reason
osVersion: uaResult.os.version,
verComp: version_compare,
-
+
swf_url: "../flash/Moxie.swf",
xap_url: "../silverlight/Moxie.xap",
global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent"
@@ -1160,20 +1547,15 @@ define("moxie/core/utils/Env", [
};
Env.log = function() {
-
+
function logObj(data) {
// TODO: this should recursively print out the object in a pretty way
console.appendChild(document.createTextNode(data + "\n"));
}
- var data = arguments[0];
-
- if (Basic.typeOf(data) === 'string') {
- data = Basic.sprintf.apply(this, arguments);
- }
-
- if (window && window.console && window.console.log) {
- window.console.log(data);
+ // if debugger present, IE8 might have window.console.log method, but not be able to apply on it (why...)
+ if (window && window.console && window.console.log && window.console.log.apply) {
+ window.console.log.apply(window.console, arguments);
} else if (document) {
var console = document.getElementById('moxie-console');
if (!console) {
@@ -1183,11 +1565,15 @@ define("moxie/core/utils/Env", [
document.body.appendChild(console);
}
- if (Basic.inArray(Basic.typeOf(data), ['object', 'array']) !== -1) {
+ var data = arguments[0];
+ if (Basic.typeOf(data) === 'string') {
+ data = Basic.sprintf.apply(this, arguments);
+ } else if (Basic.inArray(Basic.typeOf(data), ['object', 'array']) !== -1) {
logObj(data);
- } else {
- console.appendChild(document.createTextNode(data + "\n"));
+ return;
}
+
+ console.appendChild(document.createTextNode(data + "\n"));
}
};
}
@@ -1195,10 +1581,10 @@ define("moxie/core/utils/Env", [
return Env;
});
-// Included from: src/javascript/core/I18n.js
+// Included from: src/javascript/core/Exceptions.js
/**
- * I18n.js
+ * Exceptions.js
*
* Copyright 2013, Moxiecode Systems AB
* Released under GPL License.
@@ -1207,254 +1593,158 @@ define("moxie/core/utils/Env", [
* Contributing: http://www.plupload.com/contributing
*/
-define("moxie/core/I18n", [
- "moxie/core/utils/Basic"
+define('moxie/core/Exceptions', [
+ 'moxie/core/utils/Basic'
], function(Basic) {
- var i18n = {};
+
+ function _findKey(obj, value) {
+ var key;
+ for (key in obj) {
+ if (obj[key] === value) {
+ return key;
+ }
+ }
+ return null;
+ }
+ /**
+ @class moxie/core/Exception
+ */
return {
- /**
- * Extends the language pack object with new items.
- *
- * @param {Object} pack Language pack items to add.
- * @return {Object} Extended language pack object.
- */
- addI18n: function(pack) {
- return Basic.extend(i18n, pack);
- },
+ RuntimeError: (function() {
+ var namecodes = {
+ NOT_INIT_ERR: 1,
+ EXCEPTION_ERR: 3,
+ NOT_SUPPORTED_ERR: 9,
+ JS_ERR: 4
+ };
- /**
- * Translates the specified string by checking for the english string in the language pack lookup.
- *
- * @param {String} str String to look for.
- * @return {String} Translated string or the input string if it wasn't found.
- */
- translate: function(str) {
- return i18n[str] || str;
- },
-
- /**
- * Shortcut for translate function
- *
- * @param {String} str String to look for.
- * @return {String} Translated string or the input string if it wasn't found.
- */
- _: function(str) {
- return this.translate(str);
- },
-
- /**
- * Pseudo sprintf implementation - simple way to replace tokens with specified values.
- *
- * @param {String} str String with tokens
- * @return {String} String with replaced tokens
- */
- sprintf: function(str) {
- var args = [].slice.call(arguments, 1);
-
- return str.replace(/%[a-z]/g, function() {
- var value = args.shift();
- return Basic.typeOf(value) !== 'undefined' ? value : '';
+ function RuntimeError(code, message) {
+ this.code = code;
+ this.name = _findKey(namecodes, code);
+ this.message = this.name + (message || ": RuntimeError " + this.code);
+ }
+
+ Basic.extend(RuntimeError, namecodes);
+ RuntimeError.prototype = Error.prototype;
+ return RuntimeError;
+ }()),
+
+ OperationNotAllowedException: (function() {
+
+ function OperationNotAllowedException(code) {
+ this.code = code;
+ this.name = 'OperationNotAllowedException';
+ }
+
+ Basic.extend(OperationNotAllowedException, {
+ NOT_ALLOWED_ERR: 1
});
- }
+
+ OperationNotAllowedException.prototype = Error.prototype;
+
+ return OperationNotAllowedException;
+ }()),
+
+ ImageError: (function() {
+ var namecodes = {
+ WRONG_FORMAT: 1,
+ MAX_RESOLUTION_ERR: 2,
+ INVALID_META_ERR: 3
+ };
+
+ function ImageError(code) {
+ this.code = code;
+ this.name = _findKey(namecodes, code);
+ this.message = this.name + ": ImageError " + this.code;
+ }
+
+ Basic.extend(ImageError, namecodes);
+ ImageError.prototype = Error.prototype;
+
+ return ImageError;
+ }()),
+
+ FileException: (function() {
+ var namecodes = {
+ NOT_FOUND_ERR: 1,
+ SECURITY_ERR: 2,
+ ABORT_ERR: 3,
+ NOT_READABLE_ERR: 4,
+ ENCODING_ERR: 5,
+ NO_MODIFICATION_ALLOWED_ERR: 6,
+ INVALID_STATE_ERR: 7,
+ SYNTAX_ERR: 8
+ };
+
+ function FileException(code) {
+ this.code = code;
+ this.name = _findKey(namecodes, code);
+ this.message = this.name + ": FileException " + this.code;
+ }
+
+ Basic.extend(FileException, namecodes);
+ FileException.prototype = Error.prototype;
+ return FileException;
+ }()),
+
+ DOMException: (function() {
+ var namecodes = {
+ INDEX_SIZE_ERR: 1,
+ DOMSTRING_SIZE_ERR: 2,
+ HIERARCHY_REQUEST_ERR: 3,
+ WRONG_DOCUMENT_ERR: 4,
+ INVALID_CHARACTER_ERR: 5,
+ NO_DATA_ALLOWED_ERR: 6,
+ NO_MODIFICATION_ALLOWED_ERR: 7,
+ NOT_FOUND_ERR: 8,
+ NOT_SUPPORTED_ERR: 9,
+ INUSE_ATTRIBUTE_ERR: 10,
+ INVALID_STATE_ERR: 11,
+ SYNTAX_ERR: 12,
+ INVALID_MODIFICATION_ERR: 13,
+ NAMESPACE_ERR: 14,
+ INVALID_ACCESS_ERR: 15,
+ VALIDATION_ERR: 16,
+ TYPE_MISMATCH_ERR: 17,
+ SECURITY_ERR: 18,
+ NETWORK_ERR: 19,
+ ABORT_ERR: 20,
+ URL_MISMATCH_ERR: 21,
+ QUOTA_EXCEEDED_ERR: 22,
+ TIMEOUT_ERR: 23,
+ INVALID_NODE_TYPE_ERR: 24,
+ DATA_CLONE_ERR: 25
+ };
+
+ function DOMException(code) {
+ this.code = code;
+ this.name = _findKey(namecodes, code);
+ this.message = this.name + ": DOMException " + this.code;
+ }
+
+ Basic.extend(DOMException, namecodes);
+ DOMException.prototype = Error.prototype;
+ return DOMException;
+ }()),
+
+ EventException: (function() {
+ function EventException(code) {
+ this.code = code;
+ this.name = 'EventException';
+ }
+
+ Basic.extend(EventException, {
+ UNSPECIFIED_EVENT_TYPE_ERR: 0
+ });
+
+ EventException.prototype = Error.prototype;
+
+ return EventException;
+ }())
};
});
-// Included from: src/javascript/core/utils/Mime.js
-
-/**
- * Mime.js
- *
- * Copyright 2013, Moxiecode Systems AB
- * Released under GPL License.
- *
- * License: http://www.plupload.com/license
- * Contributing: http://www.plupload.com/contributing
- */
-
-define("moxie/core/utils/Mime", [
- "moxie/core/utils/Basic",
- "moxie/core/I18n"
-], function(Basic, I18n) {
-
- var mimeData = "" +
- "application/msword,doc dot," +
- "application/pdf,pdf," +
- "application/pgp-signature,pgp," +
- "application/postscript,ps ai eps," +
- "application/rtf,rtf," +
- "application/vnd.ms-excel,xls xlb," +
- "application/vnd.ms-powerpoint,ppt pps pot," +
- "application/zip,zip," +
- "application/x-shockwave-flash,swf swfl," +
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," +
- "application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," +
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," +
- "application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," +
- "application/vnd.openxmlformats-officedocument.presentationml.template,potx," +
- "application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," +
- "application/x-javascript,js," +
- "application/json,json," +
- "audio/mpeg,mp3 mpga mpega mp2," +
- "audio/x-wav,wav," +
- "audio/x-m4a,m4a," +
- "audio/ogg,oga ogg," +
- "audio/aiff,aiff aif," +
- "audio/flac,flac," +
- "audio/aac,aac," +
- "audio/ac3,ac3," +
- "audio/x-ms-wma,wma," +
- "image/bmp,bmp," +
- "image/gif,gif," +
- "image/jpeg,jpg jpeg jpe," +
- "image/photoshop,psd," +
- "image/png,png," +
- "image/svg+xml,svg svgz," +
- "image/tiff,tiff tif," +
- "text/plain,asc txt text diff log," +
- "text/html,htm html xhtml," +
- "text/css,css," +
- "text/csv,csv," +
- "text/rtf,rtf," +
- "video/mpeg,mpeg mpg mpe m2v," +
- "video/quicktime,qt mov," +
- "video/mp4,mp4," +
- "video/x-m4v,m4v," +
- "video/x-flv,flv," +
- "video/x-ms-wmv,wmv," +
- "video/avi,avi," +
- "video/webm,webm," +
- "video/3gpp,3gpp 3gp," +
- "video/3gpp2,3g2," +
- "video/vnd.rn-realvideo,rv," +
- "video/ogg,ogv," +
- "video/x-matroska,mkv," +
- "application/vnd.oasis.opendocument.formula-template,otf," +
- "application/octet-stream,exe";
-
-
- var Mime = {
-
- mimes: {},
-
- extensions: {},
-
- // Parses the default mime types string into a mimes and extensions lookup maps
- addMimeType: function (mimeData) {
- var items = mimeData.split(/,/), i, ii, ext;
-
- for (i = 0; i < items.length; i += 2) {
- ext = items[i + 1].split(/ /);
-
- // extension to mime lookup
- for (ii = 0; ii < ext.length; ii++) {
- this.mimes[ext[ii]] = items[i];
- }
- // mime to extension lookup
- this.extensions[items[i]] = ext;
- }
- },
-
-
- extList2mimes: function (filters, addMissingExtensions) {
- var self = this, ext, i, ii, type, mimes = [];
-
- // convert extensions to mime types list
- for (i = 0; i < filters.length; i++) {
- ext = filters[i].extensions.split(/\s*,\s*/);
-
- for (ii = 0; ii < ext.length; ii++) {
-
- // if there's an asterisk in the list, then accept attribute is not required
- if (ext[ii] === '*') {
- return [];
- }
-
- type = self.mimes[ext[ii]];
- if (type && Basic.inArray(type, mimes) === -1) {
- mimes.push(type);
- }
-
- // future browsers should filter by extension, finally
- if (addMissingExtensions && /^\w+$/.test(ext[ii])) {
- mimes.push('.' + ext[ii]);
- } else if (!type) {
- // if we have no type in our map, then accept all
- return [];
- }
- }
- }
- return mimes;
- },
-
-
- mimes2exts: function(mimes) {
- var self = this, exts = [];
-
- Basic.each(mimes, function(mime) {
- if (mime === '*') {
- exts = [];
- return false;
- }
-
- // check if this thing looks like mime type
- var m = mime.match(/^(\w+)\/(\*|\w+)$/);
- if (m) {
- if (m[2] === '*') {
- // wildcard mime type detected
- Basic.each(self.extensions, function(arr, mime) {
- if ((new RegExp('^' + m[1] + '/')).test(mime)) {
- [].push.apply(exts, self.extensions[mime]);
- }
- });
- } else if (self.extensions[mime]) {
- [].push.apply(exts, self.extensions[mime]);
- }
- }
- });
- return exts;
- },
-
-
- mimes2extList: function(mimes) {
- var accept = [], exts = [];
-
- if (Basic.typeOf(mimes) === 'string') {
- mimes = Basic.trim(mimes).split(/\s*,\s*/);
- }
-
- exts = this.mimes2exts(mimes);
-
- accept.push({
- title: I18n.translate('Files'),
- extensions: exts.length ? exts.join(',') : '*'
- });
-
- // save original mimes string
- accept.mimes = mimes;
-
- return accept;
- },
-
-
- getFileExtension: function(fileName) {
- var matches = fileName && fileName.match(/\.([^.]+)$/);
- if (matches) {
- return matches[1].toLowerCase();
- }
- return '';
- },
-
- getFileMime: function(fileName) {
- return this.mimes[this.getFileExtension(fileName)] || '';
- }
- };
-
- Mime.addMimeType(mimeData);
-
- return Mime;
-});
-
// Included from: src/javascript/core/utils/Dom.js
/**
@@ -1467,13 +1757,18 @@ define("moxie/core/utils/Mime", [
* Contributing: http://www.plupload.com/contributing
*/
+/**
+@class moxie/core/utils/Dom
+@public
+@static
+*/
+
define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) {
/**
Get DOM Element by it's id.
@method get
- @for Utils
@param {String} id Identifier of the DOM Element
@return {DOMElement}
*/
@@ -1638,165 +1933,6 @@ define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) {
};
});
-// Included from: src/javascript/core/Exceptions.js
-
-/**
- * Exceptions.js
- *
- * Copyright 2013, Moxiecode Systems AB
- * Released under GPL License.
- *
- * License: http://www.plupload.com/license
- * Contributing: http://www.plupload.com/contributing
- */
-
-define('moxie/core/Exceptions', [
- 'moxie/core/utils/Basic'
-], function(Basic) {
- function _findKey(obj, value) {
- var key;
- for (key in obj) {
- if (obj[key] === value) {
- return key;
- }
- }
- return null;
- }
-
- return {
- RuntimeError: (function() {
- var namecodes = {
- NOT_INIT_ERR: 1,
- NOT_SUPPORTED_ERR: 9,
- JS_ERR: 4
- };
-
- function RuntimeError(code) {
- this.code = code;
- this.name = _findKey(namecodes, code);
- this.message = this.name + ": RuntimeError " + this.code;
- }
-
- Basic.extend(RuntimeError, namecodes);
- RuntimeError.prototype = Error.prototype;
- return RuntimeError;
- }()),
-
- OperationNotAllowedException: (function() {
-
- function OperationNotAllowedException(code) {
- this.code = code;
- this.name = 'OperationNotAllowedException';
- }
-
- Basic.extend(OperationNotAllowedException, {
- NOT_ALLOWED_ERR: 1
- });
-
- OperationNotAllowedException.prototype = Error.prototype;
-
- return OperationNotAllowedException;
- }()),
-
- ImageError: (function() {
- var namecodes = {
- WRONG_FORMAT: 1,
- MAX_RESOLUTION_ERR: 2,
- INVALID_META_ERR: 3
- };
-
- function ImageError(code) {
- this.code = code;
- this.name = _findKey(namecodes, code);
- this.message = this.name + ": ImageError " + this.code;
- }
-
- Basic.extend(ImageError, namecodes);
- ImageError.prototype = Error.prototype;
-
- return ImageError;
- }()),
-
- FileException: (function() {
- var namecodes = {
- NOT_FOUND_ERR: 1,
- SECURITY_ERR: 2,
- ABORT_ERR: 3,
- NOT_READABLE_ERR: 4,
- ENCODING_ERR: 5,
- NO_MODIFICATION_ALLOWED_ERR: 6,
- INVALID_STATE_ERR: 7,
- SYNTAX_ERR: 8
- };
-
- function FileException(code) {
- this.code = code;
- this.name = _findKey(namecodes, code);
- this.message = this.name + ": FileException " + this.code;
- }
-
- Basic.extend(FileException, namecodes);
- FileException.prototype = Error.prototype;
- return FileException;
- }()),
-
- DOMException: (function() {
- var namecodes = {
- INDEX_SIZE_ERR: 1,
- DOMSTRING_SIZE_ERR: 2,
- HIERARCHY_REQUEST_ERR: 3,
- WRONG_DOCUMENT_ERR: 4,
- INVALID_CHARACTER_ERR: 5,
- NO_DATA_ALLOWED_ERR: 6,
- NO_MODIFICATION_ALLOWED_ERR: 7,
- NOT_FOUND_ERR: 8,
- NOT_SUPPORTED_ERR: 9,
- INUSE_ATTRIBUTE_ERR: 10,
- INVALID_STATE_ERR: 11,
- SYNTAX_ERR: 12,
- INVALID_MODIFICATION_ERR: 13,
- NAMESPACE_ERR: 14,
- INVALID_ACCESS_ERR: 15,
- VALIDATION_ERR: 16,
- TYPE_MISMATCH_ERR: 17,
- SECURITY_ERR: 18,
- NETWORK_ERR: 19,
- ABORT_ERR: 20,
- URL_MISMATCH_ERR: 21,
- QUOTA_EXCEEDED_ERR: 22,
- TIMEOUT_ERR: 23,
- INVALID_NODE_TYPE_ERR: 24,
- DATA_CLONE_ERR: 25
- };
-
- function DOMException(code) {
- this.code = code;
- this.name = _findKey(namecodes, code);
- this.message = this.name + ": DOMException " + this.code;
- }
-
- Basic.extend(DOMException, namecodes);
- DOMException.prototype = Error.prototype;
- return DOMException;
- }()),
-
- EventException: (function() {
- function EventException(code) {
- this.code = code;
- this.name = 'EventException';
- }
-
- Basic.extend(EventException, {
- UNSPECIFIED_EVENT_TYPE_ERR: 0
- });
-
- EventException.prototype = Error.prototype;
-
- return EventException;
- }())
- };
-});
-
// Included from: src/javascript/core/EventTarget.js
/**
@@ -1814,289 +1950,326 @@ define('moxie/core/EventTarget', [
'moxie/core/Exceptions',
'moxie/core/utils/Basic'
], function(Env, x, Basic) {
+
+ // hash of event listeners by object uid
+ var eventpool = {};
+
/**
Parent object for all event dispatching components and objects
- @class EventTarget
+ @class moxie/core/EventTarget
@constructor EventTarget
*/
function EventTarget() {
- // hash of event listeners by object uid
- var eventpool = {};
-
- Basic.extend(this, {
-
- /**
- Unique id of the event dispatcher, usually overriden by children
+ /**
+ Unique id of the event dispatcher, usually overriden by children
- @property uid
- @type String
- */
- uid: null,
-
- /**
- Can be called from within a child in order to acquire uniqie id in automated manner
-
- @method init
- */
- init: function() {
- if (!this.uid) {
- this.uid = Basic.guid('uid_');
- }
- },
-
- /**
- Register a handler to a specific event dispatched by the object
-
- @method addEventListener
- @param {String} type Type or basically a name of the event to subscribe to
- @param {Function} fn Callback function that will be called when event happens
- @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
- @param {Object} [scope=this] A scope to invoke event handler in
- */
- addEventListener: function(type, fn, priority, scope) {
- var self = this, list;
-
- // without uid no event handlers can be added, so make sure we got one
- if (!this.hasOwnProperty('uid')) {
- this.uid = Basic.guid('uid_');
- }
-
- type = Basic.trim(type);
-
- if (/\s/.test(type)) {
- // multiple event types were passed for one handler
- Basic.each(type.split(/\s+/), function(type) {
- self.addEventListener(type, fn, priority, scope);
- });
- return;
- }
-
- type = type.toLowerCase();
- priority = parseInt(priority, 10) || 0;
-
- list = eventpool[this.uid] && eventpool[this.uid][type] || [];
- list.push({fn : fn, priority : priority, scope : scope || this});
-
- if (!eventpool[this.uid]) {
- eventpool[this.uid] = {};
- }
- eventpool[this.uid][type] = list;
- },
-
- /**
- Check if any handlers were registered to the specified event
-
- @method hasEventListener
- @param {String} type Type or basically a name of the event to check
- @return {Mixed} Returns a handler if it was found and false, if - not
- */
- hasEventListener: function(type) {
- var list = type ? eventpool[this.uid] && eventpool[this.uid][type] : eventpool[this.uid];
- return list ? list : false;
- },
-
- /**
- Unregister the handler from the event, or if former was not specified - unregister all handlers
-
- @method removeEventListener
- @param {String} type Type or basically a name of the event
- @param {Function} [fn] Handler to unregister
- */
- removeEventListener: function(type, fn) {
- type = type.toLowerCase();
-
- var list = eventpool[this.uid] && eventpool[this.uid][type], i;
-
- if (list) {
- if (fn) {
- for (i = list.length - 1; i >= 0; i--) {
- if (list[i].fn === fn) {
- list.splice(i, 1);
- break;
- }
- }
- } else {
- list = [];
- }
-
- // delete event list if it has become empty
- if (!list.length) {
- delete eventpool[this.uid][type];
-
- // and object specific entry in a hash if it has no more listeners attached
- if (Basic.isEmptyObj(eventpool[this.uid])) {
- delete eventpool[this.uid];
- }
- }
- }
- },
-
- /**
- Remove all event handlers from the object
-
- @method removeAllEventListeners
- */
- removeAllEventListeners: function() {
- if (eventpool[this.uid]) {
- delete eventpool[this.uid];
- }
- },
-
- /**
- Dispatch the event
-
- @method dispatchEvent
- @param {String/Object} Type of event or event object to dispatch
- @param {Mixed} [...] Variable number of arguments to be passed to a handlers
- @return {Boolean} true by default and false if any handler returned false
- */
- dispatchEvent: function(type) {
- var uid, list, args, tmpEvt, evt = {}, result = true, undef;
-
- if (Basic.typeOf(type) !== 'string') {
- // we can't use original object directly (because of Silverlight)
- tmpEvt = type;
-
- if (Basic.typeOf(tmpEvt.type) === 'string') {
- type = tmpEvt.type;
-
- if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event
- evt.total = tmpEvt.total;
- evt.loaded = tmpEvt.loaded;
- }
- evt.async = tmpEvt.async || false;
- } else {
- throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR);
- }
- }
-
- // check if event is meant to be dispatched on an object having specific uid
- if (type.indexOf('::') !== -1) {
- (function(arr) {
- uid = arr[0];
- type = arr[1];
- }(type.split('::')));
- } else {
- uid = this.uid;
- }
-
- type = type.toLowerCase();
-
- list = eventpool[uid] && eventpool[uid][type];
-
- if (list) {
- // sort event list by prority
- list.sort(function(a, b) { return b.priority - a.priority; });
-
- args = [].slice.call(arguments);
-
- // first argument will be pseudo-event object
- args.shift();
- evt.type = type;
- args.unshift(evt);
-
- if (MXI_DEBUG && Env.debug.events) {
- Env.log("Event '%s' fired on %u", evt.type, uid);
- }
-
- // Dispatch event to all listeners
- var queue = [];
- Basic.each(list, function(handler) {
- // explicitly set the target, otherwise events fired from shims do not get it
- args[0].target = handler.scope;
- // if event is marked as async, detach the handler
- if (evt.async) {
- queue.push(function(cb) {
- setTimeout(function() {
- cb(handler.fn.apply(handler.scope, args) === false);
- }, 1);
- });
- } else {
- queue.push(function(cb) {
- cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation
- });
- }
- });
- if (queue.length) {
- Basic.inSeries(queue, function(err) {
- result = !err;
- });
- }
- }
- return result;
- },
-
- /**
- Alias for addEventListener
-
- @method bind
- @protected
- */
- bind: function() {
- this.addEventListener.apply(this, arguments);
- },
-
- /**
- Alias for removeEventListener
-
- @method unbind
- @protected
- */
- unbind: function() {
- this.removeEventListener.apply(this, arguments);
- },
-
- /**
- Alias for removeAllEventListeners
-
- @method unbindAll
- @protected
- */
- unbindAll: function() {
- this.removeAllEventListeners.apply(this, arguments);
- },
-
- /**
- Alias for dispatchEvent
-
- @method trigger
- @protected
- */
- trigger: function() {
- return this.dispatchEvent.apply(this, arguments);
- },
-
-
- /**
- Handle properties of on[event] type.
-
- @method handleEventProps
- @private
- */
- handleEventProps: function(dispatches) {
- var self = this;
-
- this.bind(dispatches.join(' '), function(e) {
- var prop = 'on' + e.type.toLowerCase();
- if (Basic.typeOf(this[prop]) === 'function') {
- this[prop].apply(this, arguments);
- }
- });
-
- // object must have defined event properties, even if it doesn't make use of them
- Basic.each(dispatches, function(prop) {
- prop = 'on' + prop.toLowerCase(prop);
- if (Basic.typeOf(self[prop]) === 'undefined') {
- self[prop] = null;
- }
- });
- }
-
- });
+ @property uid
+ @type String
+ */
+ this.uid = Basic.guid();
}
- EventTarget.instance = new EventTarget();
+
+ Basic.extend(EventTarget.prototype, {
+
+ /**
+ Can be called from within a child in order to acquire uniqie id in automated manner
+
+ @method init
+ */
+ init: function() {
+ if (!this.uid) {
+ this.uid = Basic.guid('uid_');
+ }
+ },
+
+ /**
+ Register a handler to a specific event dispatched by the object
+
+ @method addEventListener
+ @param {String} type Type or basically a name of the event to subscribe to
+ @param {Function} fn Callback function that will be called when event happens
+ @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
+ @param {Object} [scope=this] A scope to invoke event handler in
+ */
+ addEventListener: function(type, fn, priority, scope) {
+ var self = this, list;
+
+ // without uid no event handlers can be added, so make sure we got one
+ if (!this.hasOwnProperty('uid')) {
+ this.uid = Basic.guid('uid_');
+ }
+
+ type = Basic.trim(type);
+
+ if (/\s/.test(type)) {
+ // multiple event types were passed for one handler
+ Basic.each(type.split(/\s+/), function(type) {
+ self.addEventListener(type, fn, priority, scope);
+ });
+ return;
+ }
+
+ type = type.toLowerCase();
+ priority = parseInt(priority, 10) || 0;
+
+ list = eventpool[this.uid] && eventpool[this.uid][type] || [];
+ list.push({fn : fn, priority : priority, scope : scope || this});
+
+ if (!eventpool[this.uid]) {
+ eventpool[this.uid] = {};
+ }
+ eventpool[this.uid][type] = list;
+ },
+
+ /**
+ Check if any handlers were registered to the specified event
+
+ @method hasEventListener
+ @param {String} [type] Type or basically a name of the event to check
+ @return {Mixed} Returns a handler if it was found and false, if - not
+ */
+ hasEventListener: function(type) {
+ var list;
+ if (type) {
+ type = type.toLowerCase();
+ list = eventpool[this.uid] && eventpool[this.uid][type];
+ } else {
+ list = eventpool[this.uid];
+ }
+ return list ? list : false;
+ },
+
+ /**
+ Unregister the handler from the event, or if former was not specified - unregister all handlers
+
+ @method removeEventListener
+ @param {String} type Type or basically a name of the event
+ @param {Function} [fn] Handler to unregister
+ */
+ removeEventListener: function(type, fn) {
+ var self = this, list, i;
+
+ type = type.toLowerCase();
+
+ if (/\s/.test(type)) {
+ // multiple event types were passed for one handler
+ Basic.each(type.split(/\s+/), function(type) {
+ self.removeEventListener(type, fn);
+ });
+ return;
+ }
+
+ list = eventpool[this.uid] && eventpool[this.uid][type];
+
+ if (list) {
+ if (fn) {
+ for (i = list.length - 1; i >= 0; i--) {
+ if (list[i].fn === fn) {
+ list.splice(i, 1);
+ break;
+ }
+ }
+ } else {
+ list = [];
+ }
+
+ // delete event list if it has become empty
+ if (!list.length) {
+ delete eventpool[this.uid][type];
+
+ // and object specific entry in a hash if it has no more listeners attached
+ if (Basic.isEmptyObj(eventpool[this.uid])) {
+ delete eventpool[this.uid];
+ }
+ }
+ }
+ },
+
+ /**
+ Remove all event handlers from the object
+
+ @method removeAllEventListeners
+ */
+ removeAllEventListeners: function() {
+ if (eventpool[this.uid]) {
+ delete eventpool[this.uid];
+ }
+ },
+
+ /**
+ Dispatch the event
+
+ @method dispatchEvent
+ @param {String/Object} Type of event or event object to dispatch
+ @param {Mixed} [...] Variable number of arguments to be passed to a handlers
+ @return {Boolean} true by default and false if any handler returned false
+ */
+ dispatchEvent: function(type) {
+ var uid, list, args, tmpEvt, evt = {}, result = true, undef;
+
+ if (Basic.typeOf(type) !== 'string') {
+ // we can't use original object directly (because of Silverlight)
+ tmpEvt = type;
+
+ if (Basic.typeOf(tmpEvt.type) === 'string') {
+ type = tmpEvt.type;
+
+ if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event
+ evt.total = tmpEvt.total;
+ evt.loaded = tmpEvt.loaded;
+ }
+ evt.async = tmpEvt.async || false;
+ } else {
+ throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR);
+ }
+ }
+
+ // check if event is meant to be dispatched on an object having specific uid
+ if (type.indexOf('::') !== -1) {
+ (function(arr) {
+ uid = arr[0];
+ type = arr[1];
+ }(type.split('::')));
+ } else {
+ uid = this.uid;
+ }
+
+ type = type.toLowerCase();
+
+ list = eventpool[uid] && eventpool[uid][type];
+
+ if (list) {
+ // sort event list by prority
+ list.sort(function(a, b) { return b.priority - a.priority; });
+
+ args = [].slice.call(arguments);
+
+ // first argument will be pseudo-event object
+ args.shift();
+ evt.type = type;
+ args.unshift(evt);
+
+ if (MXI_DEBUG && Env.debug.events) {
+ Env.log("%cEvent '%s' fired on %s", 'color: #999;', evt.type, (this.ctorName ? this.ctorName + '::' : '') + uid);
+ }
+
+ // Dispatch event to all listeners
+ var queue = [];
+ Basic.each(list, function(handler) {
+ // explicitly set the target, otherwise events fired from shims do not get it
+ args[0].target = handler.scope;
+ // if event is marked as async, detach the handler
+ if (evt.async) {
+ queue.push(function(cb) {
+ setTimeout(function() {
+ cb(handler.fn.apply(handler.scope, args) === false);
+ }, 1);
+ });
+ } else {
+ queue.push(function(cb) {
+ cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation
+ });
+ }
+ });
+ if (queue.length) {
+ Basic.inSeries(queue, function(err) {
+ result = !err;
+ });
+ }
+ }
+ return result;
+ },
+
+ /**
+ Register a handler to the event type that will run only once
+
+ @method bindOnce
+ @since >1.4.1
+ @param {String} type Type or basically a name of the event to subscribe to
+ @param {Function} fn Callback function that will be called when event happens
+ @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
+ @param {Object} [scope=this] A scope to invoke event handler in
+ */
+ bindOnce: function(type, fn, priority, scope) {
+ var self = this;
+ self.bind.call(this, type, function cb() {
+ self.unbind(type, cb);
+ return fn.apply(this, arguments);
+ }, priority, scope);
+ },
+
+ /**
+ Alias for addEventListener
+
+ @method bind
+ @protected
+ */
+ bind: function() {
+ this.addEventListener.apply(this, arguments);
+ },
+
+ /**
+ Alias for removeEventListener
+
+ @method unbind
+ @protected
+ */
+ unbind: function() {
+ this.removeEventListener.apply(this, arguments);
+ },
+
+ /**
+ Alias for removeAllEventListeners
+
+ @method unbindAll
+ @protected
+ */
+ unbindAll: function() {
+ this.removeAllEventListeners.apply(this, arguments);
+ },
+
+ /**
+ Alias for dispatchEvent
+
+ @method trigger
+ @protected
+ */
+ trigger: function() {
+ return this.dispatchEvent.apply(this, arguments);
+ },
+
+
+ /**
+ Handle properties of on[event] type.
+
+ @method handleEventProps
+ @private
+ */
+ handleEventProps: function(dispatches) {
+ var self = this;
+
+ this.bind(dispatches.join(' '), function(e) {
+ var prop = 'on' + e.type.toLowerCase();
+ if (Basic.typeOf(this[prop]) === 'function') {
+ this[prop].apply(this, arguments);
+ }
+ });
+
+ // object must have defined event properties, even if it doesn't make use of them
+ Basic.each(dispatches, function(prop) {
+ prop = 'on' + prop.toLowerCase(prop);
+ if (Basic.typeOf(self[prop]) === 'undefined') {
+ self[prop] = null;
+ }
+ });
+ }
+
+ });
+
+
+ EventTarget.instance = new EventTarget();
return EventTarget;
});
@@ -2124,7 +2297,7 @@ define('moxie/runtime/Runtime', [
/**
Common set of methods and properties for every runtime instance
- @class Runtime
+ @class moxie/runtime/Runtime
@param {Object} options
@param {String} type Sanitized name of the runtime
@@ -2368,7 +2541,7 @@ define('moxie/runtime/Runtime', [
// if no container for shim, create one
if (!shimContainer) {
- container = this.options.container ? Dom.get(this.options.container) : document.body;
+ container = Dom.get(this.options.container) || document.body;
// create shim container and insert it at an absolute position into the outer container
shimContainer = document.createElement('div');
@@ -2643,7 +2816,7 @@ define('moxie/runtime/Runtime', [
// if cap requires conflicting mode - runtime cannot fulfill required caps
if (MXI_DEBUG && Env.debug.runtime) {
- Env.log("\t\t%c: %v (conflicting mode requested: %s)", cap, value, capMode);
+ Env.log("\t\t%s: %s (conflicting mode requested: %s)", cap, value, capMode);
}
return (mode = false);
@@ -2651,7 +2824,7 @@ define('moxie/runtime/Runtime', [
}
if (MXI_DEBUG && Env.debug.runtime) {
- Env.log("\t\t%c: %v (compatible modes: %s)", cap, value, mode);
+ Env.log("\t\t%s: %s (compatible modes: %s)", cap, value, mode);
}
});
@@ -2665,6 +2838,30 @@ define('moxie/runtime/Runtime', [
};
+ /**
+ * Third party shims (Flash and Silverlight) require global event target against which they
+ * will fire their events. However when moxie is not loaded to global namespace, default
+ * event target is not accessible and we have to create artificial ones.
+ *
+ * @method getGlobalEventTarget
+ * @static
+ * @return {String} Name of the global event target
+ */
+ Runtime.getGlobalEventTarget = function() {
+ if (/^moxie\./.test(Env.global_event_dispatcher) && !Env.can('access_global_ns')) {
+ var uniqueCallbackName = Basic.guid('moxie_event_target_');
+
+ window[uniqueCallbackName] = function(e, data) {
+ EventTarget.instance.dispatchEvent(e, data);
+ };
+
+ Env.global_event_dispatcher = uniqueCallbackName;
+ }
+
+ return Env.global_event_dispatcher;
+ };
+
+
/**
Capability check that always returns true
@@ -2725,7 +2922,7 @@ define('moxie/runtime/RuntimeClient', [
/**
Set of methods and properties, required by a component to acquire ability to connect to a runtime
- @class RuntimeClient
+ @class moxie/runtime/RuntimeClient
*/
return function RuntimeClient() {
var runtime;
@@ -2755,6 +2952,9 @@ define('moxie/runtime/RuntimeClient', [
type = items.shift().toLowerCase();
constructor = Runtime.getConstructor(type);
if (!constructor) {
+ if (MXI_DEBUG && Env.debug.runtime) {
+ Env.log("Constructor for '%s' runtime is not available.", type);
+ }
initialize(items);
return;
}
@@ -2778,6 +2978,7 @@ define('moxie/runtime/RuntimeClient', [
// jailbreak ...
setTimeout(function() {
runtime.clients++;
+ comp.ruid = runtime.uid;
// this will be triggered on component
comp.trigger('RuntimeInit', runtime);
}, 1);
@@ -2792,7 +2993,14 @@ define('moxie/runtime/RuntimeClient', [
initialize(items);
});
- /*runtime.bind('Exception', function() { });*/
+ runtime.bind('Exception', function(e, err) {
+ var message = err.name + "(#" + err.code + ")" + (err.message ? ", from: " + err.message : '');
+
+ if (MXI_DEBUG && Env.debug.runtime) {
+ Env.log("Runtime '%s' has thrown an exception: %s", this.type, message);
+ }
+ comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.EXCEPTION_ERR, message));
+ });
if (MXI_DEBUG && Env.debug.runtime) {
Env.log("\tselected mode: %s", runtime.mode);
@@ -2817,6 +3025,7 @@ define('moxie/runtime/RuntimeClient', [
if (ruid) {
runtime = Runtime.getRuntime(ruid);
if (runtime) {
+ comp.ruid = ruid;
runtime.clients++;
return runtime;
} else {
@@ -2868,10 +3077,19 @@ define('moxie/runtime/RuntimeClient', [
@return {Mixed} Whatever runtime extension method returns
*/
exec: function() {
- if (runtime) {
- return runtime.exec.apply(this, arguments);
- }
- return null;
+ return runtime ? runtime.exec.apply(this, arguments) : null;
+ },
+
+
+ /**
+ Test runtime client for specific capability
+
+ @method can
+ @param {String} cap
+ @return {Bool}
+ */
+ can: function(cap) {
+ return runtime ? runtime.can(cap) : false;
}
});
@@ -2880,515 +3098,6 @@ define('moxie/runtime/RuntimeClient', [
});
-// Included from: src/javascript/file/FileInput.js
-
-/**
- * FileInput.js
- *
- * Copyright 2013, Moxiecode Systems AB
- * Released under GPL License.
- *
- * License: http://www.plupload.com/license
- * Contributing: http://www.plupload.com/contributing
- */
-
-define('moxie/file/FileInput', [
- 'moxie/core/utils/Basic',
- 'moxie/core/utils/Env',
- 'moxie/core/utils/Mime',
- 'moxie/core/utils/Dom',
- 'moxie/core/Exceptions',
- 'moxie/core/EventTarget',
- 'moxie/core/I18n',
- 'moxie/runtime/Runtime',
- 'moxie/runtime/RuntimeClient'
-], function(Basic, Env, Mime, Dom, x, EventTarget, I18n, Runtime, RuntimeClient) {
- /**
- Provides a convenient way to create cross-browser file-picker. Generates file selection dialog on click,
- converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory
- with _FileReader_ or uploaded to a server through _XMLHttpRequest_.
-
- @class FileInput
- @constructor
- @extends EventTarget
- @uses RuntimeClient
- @param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_.
- @param {String|DOMElement} options.browse_button DOM Element to turn into file picker.
- @param {Array} [options.accept] Array of mime types to accept. By default accepts all.
- @param {String} [options.file='file'] Name of the file field (not the filename).
- @param {Boolean} [options.multiple=false] Enable selection of multiple files.
- @param {Boolean} [options.directory=false] Turn file input into the folder input (cannot be both at the same time).
- @param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode
- for _browse\_button_.
- @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support.
-
- @example
- ' +
'
- Browse...
-
-
-
- */
- var dispatches = [
- /**
- Dispatched when runtime is connected and file-picker is ready to be used.
-
- @event ready
- @param {Object} event
- */
- 'ready',
-
- /**
- Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked.
- Check [corresponding documentation entry](#method_refresh) for more info.
-
- @event refresh
- @param {Object} event
- */
-
- /**
- Dispatched when selection of files in the dialog is complete.
-
- @event change
- @param {Object} event
- */
- 'change',
-
- 'cancel', // TODO: might be useful
-
- /**
- Dispatched when mouse cursor enters file-picker area. Can be used to style element
- accordingly.
-
- @event mouseenter
- @param {Object} event
- */
- 'mouseenter',
-
- /**
- Dispatched when mouse cursor leaves file-picker area. Can be used to style element
- accordingly.
-
- @event mouseleave
- @param {Object} event
- */
- 'mouseleave',
-
- /**
- Dispatched when functional mouse button is pressed on top of file-picker area.
-
- @event mousedown
- @param {Object} event
- */
- 'mousedown',
-
- /**
- Dispatched when functional mouse button is released on top of file-picker area.
-
- @event mouseup
- @param {Object} event
- */
- 'mouseup'
- ];
-
- function FileInput(options) {
- if (MXI_DEBUG) {
- Env.log("Instantiating FileInput...");
- }
-
- var self = this,
- container, browseButton, defaults;
-
- // if flat argument passed it should be browse_button id
- if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) {
- options = { browse_button : options };
- }
-
- // this will help us to find proper default container
- browseButton = Dom.get(options.browse_button);
- if (!browseButton) {
- // browse button is required
- throw new x.DOMException(x.DOMException.NOT_FOUND_ERR);
- }
-
- // figure out the options
- defaults = {
- accept: [{
- title: I18n.translate('All Files'),
- extensions: '*'
- }],
- name: 'file',
- multiple: false,
- required_caps: false,
- container: browseButton.parentNode || document.body
- };
-
- options = Basic.extend({}, defaults, options);
-
- // convert to object representation
- if (typeof(options.required_caps) === 'string') {
- options.required_caps = Runtime.parseCaps(options.required_caps);
- }
-
- // normalize accept option (could be list of mime types or array of title/extensions pairs)
- if (typeof(options.accept) === 'string') {
- options.accept = Mime.mimes2extList(options.accept);
- }
-
- container = Dom.get(options.container);
- // make sure we have container
- if (!container) {
- container = document.body;
- }
-
- // make container relative, if it's not
- if (Dom.getStyle(container, 'position') === 'static') {
- container.style.position = 'relative';
- }
-
- container = browseButton = null; // IE
-
- RuntimeClient.call(self);
-
- Basic.extend(self, {
- /**
- Unique id of the component
-
- @property uid
- @protected
- @readOnly
- @type {String}
- @default UID
- */
- uid: Basic.guid('uid_'),
-
- /**
- Unique id of the connected runtime, if any.
-
- @property ruid
- @protected
- @type {String}
- */
- ruid: null,
-
- /**
- Unique id of the runtime container. Useful to get hold of it for various manipulations.
-
- @property shimid
- @protected
- @type {String}
- */
- shimid: null,
-
- /**
- Array of selected mOxie.File objects
-
- @property files
- @type {Array}
- @default null
- */
- files: null,
-
- /**
- Initializes the file-picker, connects it to runtime and dispatches event ready when done.
-
- @method init
- */
- init: function() {
- self.bind('RuntimeInit', function(e, runtime) {
- self.ruid = runtime.uid;
- self.shimid = runtime.shimid;
-
- self.bind("Ready", function() {
- self.trigger("Refresh");
- }, 999);
-
- // re-position and resize shim container
- self.bind('Refresh', function() {
- var pos, size, browseButton, shimContainer;
-
- browseButton = Dom.get(options.browse_button);
- shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist
-
- if (browseButton) {
- pos = Dom.getPos(browseButton, Dom.get(options.container));
- size = Dom.getSize(browseButton);
-
- if (shimContainer) {
- Basic.extend(shimContainer.style, {
- top : pos.y + 'px',
- left : pos.x + 'px',
- width : size.w + 'px',
- height : size.h + 'px'
- });
- }
- }
- shimContainer = browseButton = null;
- });
-
- runtime.exec.call(self, 'FileInput', 'init', options);
- });
-
- // runtime needs: options.required_features, options.runtime_order and options.container
- self.connectRuntime(Basic.extend({}, options, {
- required_caps: {
- select_file: true
- }
- }));
- },
-
- /**
- Disables file-picker element, so that it doesn't react to mouse clicks.
-
- @method disable
- @param {Boolean} [state=true] Disable component if - true, enable if - false
- */
- disable: function(state) {
- var runtime = this.getRuntime();
- if (runtime) {
- runtime.exec.call(this, 'FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state);
- }
- },
-
-
- /**
- Reposition and resize dialog trigger to match the position and size of browse_button element.
-
- @method refresh
- */
- refresh: function() {
- self.trigger("Refresh");
- },
-
-
- /**
- Destroy component.
-
- @method destroy
- */
- destroy: function() {
- var runtime = this.getRuntime();
- if (runtime) {
- runtime.exec.call(this, 'FileInput', 'destroy');
- this.disconnectRuntime();
- }
-
- if (Basic.typeOf(this.files) === 'array') {
- // no sense in leaving associated files behind
- Basic.each(this.files, function(file) {
- file.destroy();
- });
- }
- this.files = null;
-
- this.unbindAll();
- }
- });
-
- this.handleEventProps(dispatches);
- }
-
- FileInput.prototype = EventTarget.instance;
-
- return FileInput;
-});
-
-// Included from: src/javascript/core/utils/Encode.js
-
-/**
- * Encode.js
- *
- * Copyright 2013, Moxiecode Systems AB
- * Released under GPL License.
- *
- * License: http://www.plupload.com/license
- * Contributing: http://www.plupload.com/contributing
- */
-
-define('moxie/core/utils/Encode', [], function() {
-
- /**
- Encode string with UTF-8
-
- @method utf8_encode
- @for Utils
- @static
- @param {String} str String to encode
- @return {String} UTF-8 encoded string
- */
- var utf8_encode = function(str) {
- return unescape(encodeURIComponent(str));
- };
-
- /**
- Decode UTF-8 encoded string
-
- @method utf8_decode
- @static
- @param {String} str String to decode
- @return {String} Decoded string
- */
- var utf8_decode = function(str_data) {
- return decodeURIComponent(escape(str_data));
- };
-
- /**
- Decode Base64 encoded string (uses browser's default method if available),
- from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_decode.js
-
- @method atob
- @static
- @param {String} data String to decode
- @return {String} Decoded string
- */
- var atob = function(data, utf8) {
- if (typeof(window.atob) === 'function') {
- return utf8 ? utf8_decode(window.atob(data)) : window.atob(data);
- }
-
- // http://kevin.vanzonneveld.net
- // + original by: Tyler Akins (http://rumkin.com)
- // + improved by: Thunder.m
- // + input by: Aman Gupta
- // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
- // + bugfixed by: Onno Marsman
- // + bugfixed by: Pellentesque Malesuada
- // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
- // + input by: Brett Zamir (http://brett-zamir.me)
- // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
- // * example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
- // * returns 1: 'Kevin van Zonneveld'
- // mozilla has this native
- // - but breaks in 2.0.0.12!
- //if (typeof this.window.atob == 'function') {
- // return atob(data);
- //}
- var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
- var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
- ac = 0,
- dec = "",
- tmp_arr = [];
-
- if (!data) {
- return data;
- }
-
- data += '';
-
- do { // unpack four hexets into three octets using index points in b64
- h1 = b64.indexOf(data.charAt(i++));
- h2 = b64.indexOf(data.charAt(i++));
- h3 = b64.indexOf(data.charAt(i++));
- h4 = b64.indexOf(data.charAt(i++));
-
- bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
-
- o1 = bits >> 16 & 0xff;
- o2 = bits >> 8 & 0xff;
- o3 = bits & 0xff;
-
- if (h3 == 64) {
- tmp_arr[ac++] = String.fromCharCode(o1);
- } else if (h4 == 64) {
- tmp_arr[ac++] = String.fromCharCode(o1, o2);
- } else {
- tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
- }
- } while (i < data.length);
-
- dec = tmp_arr.join('');
-
- return utf8 ? utf8_decode(dec) : dec;
- };
-
- /**
- Base64 encode string (uses browser's default method if available),
- from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_encode.js
-
- @method btoa
- @static
- @param {String} data String to encode
- @return {String} Base64 encoded string
- */
- var btoa = function(data, utf8) {
- if (utf8) {
- data = utf8_encode(data);
- }
-
- if (typeof(window.btoa) === 'function') {
- return window.btoa(data);
- }
-
- // http://kevin.vanzonneveld.net
- // + original by: Tyler Akins (http://rumkin.com)
- // + improved by: Bayron Guevara
- // + improved by: Thunder.m
- // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
- // + bugfixed by: Pellentesque Malesuada
- // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
- // + improved by: Rafał Kukawski (http://kukawski.pl)
- // * example 1: base64_encode('Kevin van Zonneveld');
- // * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
- // mozilla has this native
- // - but breaks in 2.0.0.12!
- var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
- var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
- ac = 0,
- enc = "",
- tmp_arr = [];
-
- if (!data) {
- return data;
- }
-
- do { // pack three octets into four hexets
- o1 = data.charCodeAt(i++);
- o2 = data.charCodeAt(i++);
- o3 = data.charCodeAt(i++);
-
- bits = o1 << 16 | o2 << 8 | o3;
-
- h1 = bits >> 18 & 0x3f;
- h2 = bits >> 12 & 0x3f;
- h3 = bits >> 6 & 0x3f;
- h4 = bits & 0x3f;
-
- // use hexets to index into b64, and append result to encoded string
- tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
- } while (i < data.length);
-
- enc = tmp_arr.join('');
-
- var r = data.length % 3;
-
- return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
- };
-
-
- return {
- utf8_encode: utf8_encode,
- utf8_decode: utf8_decode,
- atob: atob,
- btoa: btoa
- };
-});
-
// Included from: src/javascript/file/Blob.js
/**
@@ -3410,7 +3119,7 @@ define('moxie/file/Blob', [
var blobpool = {};
/**
- @class Blob
+ @class moxie/file/Blob
@constructor
@param {String} ruid Unique id of the runtime, to which this blob belongs to
@param {Object} blob Object "Native" blob object, as it is represented in the runtime
@@ -3567,6 +3276,696 @@ define('moxie/file/Blob', [
return Blob;
});
+// Included from: src/javascript/core/I18n.js
+
+/**
+ * I18n.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define("moxie/core/I18n", [
+ "moxie/core/utils/Basic"
+], function(Basic) {
+ var i18n = {};
+
+ /**
+ @class moxie/core/I18n
+ */
+ return {
+ /**
+ * Extends the language pack object with new items.
+ *
+ * @param {Object} pack Language pack items to add.
+ * @return {Object} Extended language pack object.
+ */
+ addI18n: function(pack) {
+ return Basic.extend(i18n, pack);
+ },
+
+ /**
+ * Translates the specified string by checking for the english string in the language pack lookup.
+ *
+ * @param {String} str String to look for.
+ * @return {String} Translated string or the input string if it wasn't found.
+ */
+ translate: function(str) {
+ return i18n[str] || str;
+ },
+
+ /**
+ * Shortcut for translate function
+ *
+ * @param {String} str String to look for.
+ * @return {String} Translated string or the input string if it wasn't found.
+ */
+ _: function(str) {
+ return this.translate(str);
+ },
+
+ /**
+ * Pseudo sprintf implementation - simple way to replace tokens with specified values.
+ *
+ * @param {String} str String with tokens
+ * @return {String} String with replaced tokens
+ */
+ sprintf: function(str) {
+ var args = [].slice.call(arguments, 1);
+
+ return str.replace(/%[a-z]/g, function() {
+ var value = args.shift();
+ return Basic.typeOf(value) !== 'undefined' ? value : '';
+ });
+ }
+ };
+});
+
+// Included from: src/javascript/core/utils/Mime.js
+
+/**
+ * Mime.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+/**
+@class moxie/core/utils/Mime
+@public
+@static
+*/
+
+define("moxie/core/utils/Mime", [
+ "moxie/core/utils/Basic",
+ "moxie/core/I18n"
+], function(Basic, I18n) {
+
+ var mimeData = "" +
+ "application/msword,doc dot," +
+ "application/pdf,pdf," +
+ "application/pgp-signature,pgp," +
+ "application/postscript,ps ai eps," +
+ "application/rtf,rtf," +
+ "application/vnd.ms-excel,xls xlb xlt xla," +
+ "application/vnd.ms-powerpoint,ppt pps pot ppa," +
+ "application/zip,zip," +
+ "application/x-shockwave-flash,swf swfl," +
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," +
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," +
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," +
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," +
+ "application/vnd.openxmlformats-officedocument.presentationml.template,potx," +
+ "application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," +
+ "application/x-javascript,js," +
+ "application/json,json," +
+ "audio/mpeg,mp3 mpga mpega mp2," +
+ "audio/x-wav,wav," +
+ "audio/x-m4a,m4a," +
+ "audio/ogg,oga ogg," +
+ "audio/aiff,aiff aif," +
+ "audio/flac,flac," +
+ "audio/aac,aac," +
+ "audio/ac3,ac3," +
+ "audio/x-ms-wma,wma," +
+ "image/bmp,bmp," +
+ "image/gif,gif," +
+ "image/jpeg,jpg jpeg jpe," +
+ "image/photoshop,psd," +
+ "image/png,png," +
+ "image/svg+xml,svg svgz," +
+ "image/tiff,tiff tif," +
+ "text/plain,asc txt text diff log," +
+ "text/html,htm html xhtml," +
+ "text/css,css," +
+ "text/csv,csv," +
+ "text/rtf,rtf," +
+ "video/mpeg,mpeg mpg mpe m2v," +
+ "video/quicktime,qt mov," +
+ "video/mp4,mp4," +
+ "video/x-m4v,m4v," +
+ "video/x-flv,flv," +
+ "video/x-ms-wmv,wmv," +
+ "video/avi,avi," +
+ "video/webm,webm," +
+ "video/3gpp,3gpp 3gp," +
+ "video/3gpp2,3g2," +
+ "video/vnd.rn-realvideo,rv," +
+ "video/ogg,ogv," +
+ "video/x-matroska,mkv," +
+ "application/vnd.oasis.opendocument.formula-template,otf," +
+ "application/octet-stream,exe";
+
+
+ /**
+ * Map of mimes to extensions
+ *
+ * @property mimes
+ * @type {Object}
+ */
+ var mimes = {};
+
+ /**
+ * Map of extensions to mimes
+ *
+ * @property extensions
+ * @type {Object}
+ */
+ var extensions = {};
+
+
+ /**
+ * Parses mimeData string into a mimes and extensions lookup maps. String should have the
+ * following format:
+ *
+ * application/msword,doc dot,application/pdf,pdf, ...
+ *
+ * so mime-type followed by comma and followed by space-separated list of associated extensions,
+ * then comma again and then another mime-type, etc.
+ *
+ * If invoked externally will replace override internal lookup maps with user-provided data.
+ *
+ * @method addMimeType
+ * @param {String} mimeData
+ */
+ var addMimeType = function (mimeData) {
+ var items = mimeData.split(/,/), i, ii, ext;
+
+ for (i = 0; i < items.length; i += 2) {
+ ext = items[i + 1].split(/ /);
+
+ // extension to mime lookup
+ for (ii = 0; ii < ext.length; ii++) {
+ mimes[ext[ii]] = items[i];
+ }
+ // mime to extension lookup
+ extensions[items[i]] = ext;
+ }
+ };
+
+
+ var extList2mimes = function (filters, addMissingExtensions) {
+ var ext, i, ii, type, mimes = [];
+
+ // convert extensions to mime types list
+ for (i = 0; i < filters.length; i++) {
+ ext = filters[i].extensions.toLowerCase().split(/\s*,\s*/);
+
+ for (ii = 0; ii < ext.length; ii++) {
+
+ // if there's an asterisk in the list, then accept attribute is not required
+ if (ext[ii] === '*') {
+ return [];
+ }
+
+ type = mimes[ext[ii]];
+
+ // future browsers should filter by extension, finally
+ if (addMissingExtensions && /^\w+$/.test(ext[ii])) {
+ mimes.push('.' + ext[ii]);
+ } else if (type && Basic.inArray(type, mimes) === -1) {
+ mimes.push(type);
+ } else if (!type) {
+ // if we have no type in our map, then accept all
+ return [];
+ }
+ }
+ }
+ return mimes;
+ };
+
+
+ var mimes2exts = function(mimes) {
+ var exts = [];
+
+ Basic.each(mimes, function(mime) {
+ mime = mime.toLowerCase();
+
+ if (mime === '*') {
+ exts = [];
+ return false;
+ }
+
+ // check if this thing looks like mime type
+ var m = mime.match(/^(\w+)\/(\*|\w+)$/);
+ if (m) {
+ if (m[2] === '*') {
+ // wildcard mime type detected
+ Basic.each(extensions, function(arr, mime) {
+ if ((new RegExp('^' + m[1] + '/')).test(mime)) {
+ [].push.apply(exts, extensions[mime]);
+ }
+ });
+ } else if (extensions[mime]) {
+ [].push.apply(exts, extensions[mime]);
+ }
+ }
+ });
+ return exts;
+ };
+
+
+ var mimes2extList = function(mimes) {
+ var accept = [], exts = [];
+
+ if (Basic.typeOf(mimes) === 'string') {
+ mimes = Basic.trim(mimes).split(/\s*,\s*/);
+ }
+
+ exts = mimes2exts(mimes);
+
+ accept.push({
+ title: I18n.translate('Files'),
+ extensions: exts.length ? exts.join(',') : '*'
+ });
+
+ return accept;
+ };
+
+ /**
+ * Extract extension from the given filename
+ *
+ * @method getFileExtension
+ * @param {String} fileName
+ * @return {String} File extension
+ */
+ var getFileExtension = function(fileName) {
+ var matches = fileName && fileName.match(/\.([^.]+)$/);
+ if (matches) {
+ return matches[1].toLowerCase();
+ }
+ return '';
+ };
+
+
+ /**
+ * Get file mime-type from it's filename - will try to match the extension
+ * against internal mime-type lookup map
+ *
+ * @method getFileMime
+ * @param {String} fileName
+ * @return File mime-type if found or an empty string if not
+ */
+ var getFileMime = function(fileName) {
+ return mimes[getFileExtension(fileName)] || '';
+ };
+
+
+ addMimeType(mimeData);
+
+ return {
+ mimes: mimes,
+ extensions: extensions,
+ addMimeType: addMimeType,
+ extList2mimes: extList2mimes,
+ mimes2exts: mimes2exts,
+ mimes2extList: mimes2extList,
+ getFileExtension: getFileExtension,
+ getFileMime: getFileMime
+ }
+});
+
+// Included from: src/javascript/file/FileInput.js
+
+/**
+ * FileInput.js
+ *
+ * Copyright 2013, Moxiecode Systems AB
+ * Released under GPL License.
+ *
+ * License: http://www.plupload.com/license
+ * Contributing: http://www.plupload.com/contributing
+ */
+
+define('moxie/file/FileInput', [
+ 'moxie/core/utils/Basic',
+ 'moxie/core/utils/Env',
+ 'moxie/core/utils/Mime',
+ 'moxie/core/utils/Dom',
+ 'moxie/core/Exceptions',
+ 'moxie/core/EventTarget',
+ 'moxie/core/I18n',
+ 'moxie/runtime/Runtime',
+ 'moxie/runtime/RuntimeClient'
+], function(Basic, Env, Mime, Dom, x, EventTarget, I18n, Runtime, RuntimeClient) {
+ /**
+ Provides a convenient way to create cross-browser file-picker. Generates file selection dialog on click,
+ converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory
+ with _FileReader_ or uploaded to a server through _XMLHttpRequest_.
+
+ @class moxie/file/FileInput
+ @constructor
+ @extends EventTarget
+ @uses RuntimeClient
+ @param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_.
+ @param {String|DOMElement} options.browse_button DOM Element to turn into file picker.
+ @param {Array} [options.accept] Array of mime types to accept. By default accepts all.
+ @param {Boolean} [options.multiple=false] Enable selection of multiple files.
+ @param {Boolean} [options.directory=false] Turn file input into the folder input (cannot be both at the same time).
+ @param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode
+ for _browse\_button_.
+ @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support.
+
+ @example
+
+ Browse...
+
+
+
+ */
+ var dispatches = [
+ /**
+ Dispatched when runtime is connected and file-picker is ready to be used.
+
+ @event ready
+ @param {Object} event
+ */
+ 'ready',
+
+ /**
+ Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked.
+ Check [corresponding documentation entry](#method_refresh) for more info.
+
+ @event refresh
+ @param {Object} event
+ */
+
+ /**
+ Dispatched when selection of files in the dialog is complete.
+
+ @event change
+ @param {Object} event
+ */
+ 'change',
+
+ 'cancel', // TODO: might be useful
+
+ /**
+ Dispatched when mouse cursor enters file-picker area. Can be used to style element
+ accordingly.
+
+ @event mouseenter
+ @param {Object} event
+ */
+ 'mouseenter',
+
+ /**
+ Dispatched when mouse cursor leaves file-picker area. Can be used to style element
+ accordingly.
+
+ @event mouseleave
+ @param {Object} event
+ */
+ 'mouseleave',
+
+ /**
+ Dispatched when functional mouse button is pressed on top of file-picker area.
+
+ @event mousedown
+ @param {Object} event
+ */
+ 'mousedown',
+
+ /**
+ Dispatched when functional mouse button is released on top of file-picker area.
+
+ @event mouseup
+ @param {Object} event
+ */
+ 'mouseup'
+ ];
+
+ function FileInput(options) {
+ if (MXI_DEBUG) {
+ Env.log("Instantiating FileInput...");
+ }
+
+ var container, browseButton, defaults;
+
+ // if flat argument passed it should be browse_button id
+ if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) {
+ options = { browse_button : options };
+ }
+
+ // this will help us to find proper default container
+ browseButton = Dom.get(options.browse_button);
+ if (!browseButton) {
+ // browse button is required
+ throw new x.DOMException(x.DOMException.NOT_FOUND_ERR);
+ }
+
+ // figure out the options
+ defaults = {
+ accept: [{
+ title: I18n.translate('All Files'),
+ extensions: '*'
+ }],
+ multiple: false,
+ required_caps: false,
+ container: browseButton.parentNode || document.body
+ };
+
+ options = Basic.extend({}, defaults, options);
+
+ // convert to object representation
+ if (typeof(options.required_caps) === 'string') {
+ options.required_caps = Runtime.parseCaps(options.required_caps);
+ }
+
+ // normalize accept option (could be list of mime types or array of title/extensions pairs)
+ if (typeof(options.accept) === 'string') {
+ options.accept = Mime.mimes2extList(options.accept);
+ }
+
+ container = Dom.get(options.container);
+ // make sure we have container
+ if (!container) {
+ container = document.body;
+ }
+
+ // make container relative, if it's not
+ if (Dom.getStyle(container, 'position') === 'static') {
+ container.style.position = 'relative';
+ }
+
+ container = browseButton = null; // IE
+
+ RuntimeClient.call(this);
+
+ Basic.extend(this, {
+ /**
+ Unique id of the component
+
+ @property uid
+ @protected
+ @readOnly
+ @type {String}
+ @default UID
+ */
+ uid: Basic.guid('uid_'),
+
+ /**
+ Unique id of the connected runtime, if any.
+
+ @property ruid
+ @protected
+ @type {String}
+ */
+ ruid: null,
+
+ /**
+ Unique id of the runtime container. Useful to get hold of it for various manipulations.
+
+ @property shimid
+ @protected
+ @type {String}
+ */
+ shimid: null,
+
+ /**
+ Array of selected moxie.file.File objects
+
+ @property files
+ @type {Array}
+ @default null
+ */
+ files: null,
+
+ /**
+ Initializes the file-picker, connects it to runtime and dispatches event ready when done.
+
+ @method init
+ */
+ init: function() {
+ var self = this;
+
+ self.bind('RuntimeInit', function(e, runtime) {
+ self.ruid = runtime.uid;
+ self.shimid = runtime.shimid;
+
+ self.bind("Ready", function() {
+ self.trigger("Refresh");
+ }, 999);
+
+ // re-position and resize shim container
+ self.bind('Refresh', function() {
+ var pos, size, browseButton, shimContainer, zIndex;
+
+ browseButton = Dom.get(options.browse_button);
+ shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist
+
+ if (browseButton) {
+ pos = Dom.getPos(browseButton, Dom.get(options.container));
+ size = Dom.getSize(browseButton);
+ zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 0;
+
+ if (shimContainer) {
+ Basic.extend(shimContainer.style, {
+ top: pos.y + 'px',
+ left: pos.x + 'px',
+ width: size.w + 'px',
+ height: size.h + 'px',
+ zIndex: zIndex + 1
+ });
+ }
+ }
+ shimContainer = browseButton = null;
+ });
+
+ runtime.exec.call(self, 'FileInput', 'init', options);
+ });
+
+ // runtime needs: options.required_features, options.runtime_order and options.container
+ self.connectRuntime(Basic.extend({}, options, {
+ required_caps: {
+ select_file: true
+ }
+ }));
+ },
+
+
+ /**
+ * Get current option value by its name
+ *
+ * @method getOption
+ * @param name
+ * @return {Mixed}
+ */
+ getOption: function(name) {
+ return options[name];
+ },
+
+
+ /**
+ * Sets a new value for the option specified by name
+ *
+ * @method setOption
+ * @param name
+ * @param value
+ */
+ setOption: function(name, value) {
+ if (!options.hasOwnProperty(name)) {
+ return;
+ }
+
+ var oldValue = options[name];
+
+ switch (name) {
+ case 'accept':
+ if (typeof(value) === 'string') {
+ value = Mime.mimes2extList(value);
+ }
+ break;
+
+ case 'container':
+ case 'required_caps':
+ throw new x.FileException(x.FileException.NO_MODIFICATION_ALLOWED_ERR);
+ }
+
+ options[name] = value;
+ this.exec('FileInput', 'setOption', name, value);
+
+ this.trigger('OptionChanged', name, value, oldValue);
+ },
+
+ /**
+ Disables file-picker element, so that it doesn't react to mouse clicks.
+
+ @method disable
+ @param {Boolean} [state=true] Disable component if - true, enable if - false
+ */
+ disable: function(state) {
+ var runtime = this.getRuntime();
+ if (runtime) {
+ this.exec('FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state);
+ }
+ },
+
+
+ /**
+ Reposition and resize dialog trigger to match the position and size of browse_button element.
+
+ @method refresh
+ */
+ refresh: function() {
+ this.trigger("Refresh");
+ },
+
+
+ /**
+ Destroy component.
+
+ @method destroy
+ */
+ destroy: function() {
+ var runtime = this.getRuntime();
+ if (runtime) {
+ runtime.exec.call(this, 'FileInput', 'destroy');
+ this.disconnectRuntime();
+ }
+
+ if (Basic.typeOf(this.files) === 'array') {
+ // no sense in leaving associated files behind
+ Basic.each(this.files, function(file) {
+ file.destroy();
+ });
+ }
+ this.files = null;
+
+ this.unbindAll();
+ }
+ });
+
+ this.handleEventProps(dispatches);
+ }
+
+ FileInput.prototype = EventTarget.instance;
+
+ return FileInput;
+});
+
// Included from: src/javascript/file/File.js
/**
@@ -3585,7 +3984,7 @@ define('moxie/file/File', [
'moxie/file/Blob'
], function(Basic, Mime, Blob) {
/**
- @class File
+ @class moxie/file/File
@extends Blob
@constructor
@param {String} ruid Unique id of the runtime, to which this blob belongs to
@@ -3688,10 +4087,10 @@ define('moxie/file/FileDrop', [
- @class FileDrop
+ @class moxie/file/FileDrop
@constructor
@extends EventTarget
@uses RuntimeClient
@@ -3852,7 +4251,7 @@ define('moxie/file/FileReader', [
Utility for preloading o.Blob/o.File objects in memory. By design closely follows [W3C FileReader](http://www.w3.org/TR/FileAPI/#dfn-filereader)
interface. Where possible uses native FileReader, where - not falls back to shims.
- @class FileReader
+ @class moxie/file/FileReader
@constructor FileReader
@extends EventTarget
@uses RuntimeClient
@@ -4115,13 +4514,20 @@ define('moxie/file/FileReader', [
* Contributing: http://www.plupload.com/contributing
*/
-define('moxie/core/utils/Url', [], function() {
+/**
+@class moxie/core/utils/Url
+@public
+@static
+*/
+
+define('moxie/core/utils/Url', [
+ 'moxie/core/utils/Basic'
+], function(Basic) {
/**
Parse url into separate components and fill in absent parts with parts from current url,
based on https://raw.github.com/kvz/phpjs/master/functions/url/parse_url.js
@method parseUrl
- @for Utils
@static
@param {String} url Url to parse (defaults to empty string if undefined)
@return {Object} Hash containing extracted uri components
@@ -4134,24 +4540,36 @@ define('moxie/core/utils/Url', [], function() {
https: 443
}
, uri = {}
- , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/
+ , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?(\[[\da-fA-F:]+\]|[^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/
, m = regex.exec(url || '')
+ , isRelative
+ , isSchemeLess = /^\/\/\w/.test(url)
;
-
+
+ switch (Basic.typeOf(currentUrl)) {
+ case 'undefined':
+ currentUrl = parseUrl(document.location.href, false);
+ break;
+
+ case 'string':
+ currentUrl = parseUrl(currentUrl, false);
+ break;
+ }
+
while (i--) {
if (m[i]) {
uri[key[i]] = m[i];
}
}
- // when url is relative, we set the origin and the path ourselves
- if (!uri.scheme) {
- // come up with defaults
- if (!currentUrl || typeof(currentUrl) === 'string') {
- currentUrl = parseUrl(currentUrl || document.location.href);
- }
+ isRelative = !isSchemeLess && !uri.scheme;
+ if (isSchemeLess || isRelative) {
uri.scheme = currentUrl.scheme;
+ }
+
+ // when url is relative, we set the origin and the path ourselves
+ if (isRelative) {
uri.host = currentUrl.host;
uri.port = currentUrl.port;
@@ -4172,8 +4590,8 @@ define('moxie/core/utils/Url', [], function() {
if (!uri.port) {
uri.port = ports[uri.scheme] || 80;
- }
-
+ }
+
uri.port = parseInt(uri.port, 10);
if (!uri.path) {
@@ -4208,6 +4626,7 @@ define('moxie/core/utils/Url', [], function() {
Check if specified url has the same origin as the current document
@method hasSameOrigin
+ @static
@param {String|Object} url
@return {Boolean}
*/
@@ -4215,11 +4634,11 @@ define('moxie/core/utils/Url', [], function() {
function origin(url) {
return [url.scheme, url.host, url.port].join('/');
}
-
+
if (typeof url === 'string') {
url = parseUrl(url);
- }
-
+ }
+
return origin(parseUrl()) === origin(url);
};
@@ -4251,7 +4670,7 @@ define('moxie/runtime/RuntimeTarget', [
Instance of this class can be used as a target for the events dispatched by shims,
when allowing them onto components is for either reason inappropriate
- @class RuntimeTarget
+ @class moxie/runtime/RuntimeTarget
@constructor
@protected
@extends EventTarget
@@ -4294,7 +4713,7 @@ define('moxie/file/FileReaderSync', [
it can be used to read only preloaded blobs/files and only below certain size (not yet sure what that'd be,
but probably < 1mb). Not meant to be used directly by user.
- @class FileReaderSync
+ @class moxie/file/FileReaderSync
@private
@constructor
*/
@@ -4365,7 +4784,7 @@ define("moxie/xhr/FormData", [
/**
FormData
- @class FormData
+ @class moxie/xhr/FormData
@constructor
*/
function FormData() {
@@ -4552,13 +4971,13 @@ define("moxie/xhr/XMLHttpRequest", [
function XMLHttpRequestUpload() {
this.uid = Basic.guid('uid_');
}
-
+
XMLHttpRequestUpload.prototype = EventTarget.instance;
/**
Implementation of XMLHttpRequest
- @class XMLHttpRequest
+ @class moxie/xhr/XMLHttpRequest
@constructor
@uses RuntimeClient
@extends EventTarget
@@ -4579,10 +4998,10 @@ define("moxie/xhr/XMLHttpRequest", [
'loadend'
// readystatechange (for historical reasons)
- ];
-
+ ];
+
var NATIVE = 1, RUNTIME = 2;
-
+
function XMLHttpRequest() {
var self = this,
// this (together with _p() @see below) is here to gracefully upgrade to setter/getter syntax where possible
@@ -4648,7 +5067,7 @@ define("moxie/xhr/XMLHttpRequest", [
/**
Returns the response type. Can be set to change the response type. Values are:
the empty string (default), "arraybuffer", "blob", "document", "json", and "text".
-
+
@property responseType
@type String
*/
@@ -4656,7 +5075,7 @@ define("moxie/xhr/XMLHttpRequest", [
/**
Returns the document response entity body.
-
+
Throws an "InvalidStateError" exception if responseType is not the empty string or "document".
@property responseXML
@@ -4666,7 +5085,7 @@ define("moxie/xhr/XMLHttpRequest", [
/**
Returns the text response entity body.
-
+
Throws an "InvalidStateError" exception if responseType is not the empty string or "text".
@property responseText
@@ -4677,7 +5096,7 @@ define("moxie/xhr/XMLHttpRequest", [
/**
Returns the response entity body (http://www.w3.org/TR/XMLHttpRequest/#response-entity-body).
Can become: ArrayBuffer, Blob, Document, JSON, Text
-
+
@property response
@type Mixed
*/
@@ -4714,7 +5133,7 @@ define("moxie/xhr/XMLHttpRequest", [
_responseHeadersBag
;
-
+
Basic.extend(this, props, {
/**
Unique id of the component
@@ -4723,7 +5142,7 @@ define("moxie/xhr/XMLHttpRequest", [
@type String
*/
uid: Basic.guid('uid_'),
-
+
/**
Target for Upload events
@@ -4731,7 +5150,7 @@ define("moxie/xhr/XMLHttpRequest", [
@type XMLHttpRequestUpload
*/
upload: new XMLHttpRequestUpload(),
-
+
/**
Sets the request method, request URL, synchronous flag, request username, and request password.
@@ -4759,12 +5178,12 @@ define("moxie/xhr/XMLHttpRequest", [
*/
open: function(method, url, async, user, password) {
var urlp;
-
+
// first two arguments are required
if (!method || !url) {
throw new x.DOMException(x.DOMException.SYNTAX_ERR);
}
-
+
// 2 - check if any code point in method is higher than U+00FF or after deflating method it does not match the method
if (/[\u0100-\uffff]/.test(method) || Encode.utf8_encode(method) !== method) {
throw new x.DOMException(x.DOMException.SYNTAX_ERR);
@@ -4774,8 +5193,8 @@ define("moxie/xhr/XMLHttpRequest", [
if (!!~Basic.inArray(method.toUpperCase(), ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'TRACE', 'TRACK'])) {
_method = method.toUpperCase();
}
-
-
+
+
// 4 - allowing these methods poses a security risk
if (!!~Basic.inArray(_method, ['CONNECT', 'TRACE', 'TRACK'])) {
throw new x.DOMException(x.DOMException.SECURITY_ERR);
@@ -4783,15 +5202,15 @@ define("moxie/xhr/XMLHttpRequest", [
// 5
url = Encode.utf8_encode(url);
-
+
// 6 - Resolve url relative to the XMLHttpRequest base URL. If the algorithm returns an error, throw a "SyntaxError".
urlp = Url.parseUrl(url);
_same_origin_flag = Url.hasSameOrigin(urlp);
-
+
// 7 - manually build up absolute url
_url = Url.resolveUrl(url);
-
+
// 9-10, 12-13
if ((user || password) && !_same_origin_flag) {
throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
@@ -4799,16 +5218,16 @@ define("moxie/xhr/XMLHttpRequest", [
_user = user || urlp.user;
_password = password || urlp.pass;
-
+
// 11
_async = async || true;
-
+
if (_async === false && (_p('timeout') || _p('withCredentials') || _p('responseType') !== "")) {
throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
}
-
+
// 14 - terminate abort()
-
+
// 15 - terminate send()
// 18
@@ -4819,11 +5238,11 @@ define("moxie/xhr/XMLHttpRequest", [
// 19
_p('readyState', XMLHttpRequest.OPENED);
-
+
// 20
this.dispatchEvent('readystatechange');
},
-
+
/**
Appends an header to the list of author request headers, or if header is already
in the list of author request headers, combines its value with value.
@@ -4831,7 +5250,7 @@ define("moxie/xhr/XMLHttpRequest", [
Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set.
Throws a "SyntaxError" exception if header is not a valid HTTP header field name or if value
is not a valid HTTP header field value.
-
+
@method setRequestHeader
@param {String} header
@param {String|Number} value
@@ -4860,7 +5279,7 @@ define("moxie/xhr/XMLHttpRequest", [
"user-agent",
"via"
];
-
+
// 1-2
if (_p('readyState') !== XMLHttpRequest.OPENED || _send_flag) {
throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
@@ -4878,7 +5297,7 @@ define("moxie/xhr/XMLHttpRequest", [
}*/
header = Basic.trim(header).toLowerCase();
-
+
// setting of proxy-* and sec-* headers is prohibited by spec
if (!!~Basic.inArray(header, uaHeaders) || /^(proxy\-|sec\-)/.test(header)) {
return false;
@@ -4887,7 +5306,7 @@ define("moxie/xhr/XMLHttpRequest", [
// camelize
// browsers lowercase header names (at least for custom ones)
// header = header.replace(/\b\w/g, function($1) { return $1.toUpperCase(); });
-
+
if (!_headers[header]) {
_headers[header] = value;
} else {
@@ -4897,6 +5316,18 @@ define("moxie/xhr/XMLHttpRequest", [
return true;
},
+ /**
+ * Test if the specified header is already set on this request.
+ * Returns a header value or boolean false if it's not yet set.
+ *
+ * @method hasRequestHeader
+ * @param {String} header Name of the header to test
+ * @return {Boolean|String}
+ */
+ hasRequestHeader: function(header) {
+ return header && _headers[header.toLowerCase()] || false;
+ },
+
/**
Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2.
@@ -4908,7 +5339,7 @@ define("moxie/xhr/XMLHttpRequest", [
},
/**
- Returns the header field value from the response of which the field name matches header,
+ Returns the header field value from the response of which the field name matches header,
unless the field name is Set-Cookie or Set-Cookie2.
@method getResponseHeader
@@ -4943,7 +5374,7 @@ define("moxie/xhr/XMLHttpRequest", [
}
return null;
},
-
+
/**
Sets the Content-Type header for the response to mime.
Throws an "InvalidStateError" exception if the state is LOADING or DONE.
@@ -4954,7 +5385,7 @@ define("moxie/xhr/XMLHttpRequest", [
*/
overrideMimeType: function(mime) {
var matches, charset;
-
+
// 1
if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {
throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
@@ -4978,7 +5409,7 @@ define("moxie/xhr/XMLHttpRequest", [
_finalMime = mime;
_finalCharset = charset;
},
-
+
/**
Initiates the request. The optional argument provides the request entity body.
The argument is ignored if request method is GET or HEAD.
@@ -4989,7 +5420,7 @@ define("moxie/xhr/XMLHttpRequest", [
@param {Blob|Document|String|FormData} [data] Request entity body
@param {Object} [options] Set of requirements and pre-requisities for runtime initialization
*/
- send: function(data, options) {
+ send: function(data, options) {
if (Basic.typeOf(options) === 'string') {
_options = { ruid: options };
} else if (!options) {
@@ -4997,19 +5428,19 @@ define("moxie/xhr/XMLHttpRequest", [
} else {
_options = options;
}
-
+
// 1-2
if (this.readyState !== XMLHttpRequest.OPENED || _send_flag) {
throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
}
-
- // 3
+
+ // 3
// sending Blob
if (data instanceof Blob) {
_options.ruid = data.ruid;
_mimeType = data.type || 'application/octet-stream';
}
-
+
// FormData
else if (data instanceof FormData) {
if (data.hasBlob()) {
@@ -5018,12 +5449,12 @@ define("moxie/xhr/XMLHttpRequest", [
_mimeType = blob.type || 'application/octet-stream';
}
}
-
+
// DOMString
else if (typeof data === 'string') {
_encoding = 'UTF-8';
_mimeType = 'text/plain;charset=UTF-8';
-
+
// data should be converted to Unicode and encoded as UTF-8
data = Encode.utf8_encode(data);
}
@@ -5054,10 +5485,10 @@ define("moxie/xhr/XMLHttpRequest", [
// 8.5 - Return the send() method call, but continue running the steps in this algorithm.
_doXHR.call(this, data);
},
-
+
/**
Cancels any network activity.
-
+
@method abort
*/
abort: function() {
@@ -5264,18 +5695,18 @@ define("moxie/xhr/XMLHttpRequest", [
}
}
}
-
+
/*
function _toASCII(str, AllowUnassigned, UseSTD3ASCIIRules) {
// TODO: http://tools.ietf.org/html/rfc3490#section-4.1
return str.toLowerCase();
}
*/
-
-
+
+
function _doXHR(data) {
var self = this;
-
+
_start_time = new Date().getTime();
_xhr = new RuntimeTarget();
@@ -5295,12 +5726,12 @@ define("moxie/xhr/XMLHttpRequest", [
self.dispatchEvent('readystatechange');
self.dispatchEvent(e);
-
+
if (_upload_events_flag) {
self.upload.dispatchEvent(e);
}
});
-
+
_xhr.bind('Progress', function(e) {
if (_p('readyState') !== XMLHttpRequest.LOADING) {
_p('readyState', XMLHttpRequest.LOADING); // LoadStart unreliable (in Flash for example)
@@ -5308,7 +5739,7 @@ define("moxie/xhr/XMLHttpRequest", [
}
self.dispatchEvent(e);
});
-
+
_xhr.bind('UploadProgress', function(e) {
if (_upload_events_flag) {
self.upload.dispatchEvent({
@@ -5319,12 +5750,12 @@ define("moxie/xhr/XMLHttpRequest", [
});
}
});
-
+
_xhr.bind('Load', function(e) {
_p('readyState', XMLHttpRequest.DONE);
_p('status', Number(runtime.exec.call(_xhr, 'XMLHttpRequest', 'getStatus') || 0));
_p('statusText', httpCode[_p('status')] || "");
-
+
_p('response', runtime.exec.call(_xhr, 'XMLHttpRequest', 'getResponse', _p('responseType')));
if (!!~Basic.inArray(_p('responseType'), ['text', ''])) {
@@ -5336,7 +5767,7 @@ define("moxie/xhr/XMLHttpRequest", [
_responseHeaders = runtime.exec.call(_xhr, 'XMLHttpRequest', 'getAllResponseHeaders');
self.dispatchEvent('readystatechange');
-
+
if (_p('status') > 0) { // status 0 usually means that server is unreachable
if (_upload_events_flag) {
self.upload.dispatchEvent(e);
@@ -5353,7 +5784,7 @@ define("moxie/xhr/XMLHttpRequest", [
self.dispatchEvent(e);
loadEnd();
});
-
+
_xhr.bind('Error', function(e) {
_error_flag = true;
_p('readyState', XMLHttpRequest.DONE);
@@ -5398,7 +5829,7 @@ define("moxie/xhr/XMLHttpRequest", [
if (!_same_origin_flag) {
_options.required_caps.do_cors = true;
}
-
+
if (_options.ruid) { // we do not need to wait if we can connect directly
exec(_xhr.connectRuntime(_options));
@@ -5412,8 +5843,8 @@ define("moxie/xhr/XMLHttpRequest", [
_xhr.connectRuntime(_options);
}
}
-
-
+
+
function _reset() {
_p('responseText', "");
_p('responseXML', null);
@@ -5429,7 +5860,7 @@ define("moxie/xhr/XMLHttpRequest", [
XMLHttpRequest.HEADERS_RECEIVED = 2;
XMLHttpRequest.LOADING = 3;
XMLHttpRequest.DONE = 4;
-
+
XMLHttpRequest.prototype = EventTarget.instance;
return XMLHttpRequest;
@@ -5453,6 +5884,12 @@ define("moxie/runtime/Transporter", [
"moxie/runtime/RuntimeClient",
"moxie/core/EventTarget"
], function(Basic, Encode, RuntimeClient, EventTarget) {
+
+ /**
+ @class moxie/runtime/Transporter
+ @private
+ @constructor
+ */
function Transporter() {
var mod, _runtime, _data, _size, _pos, _chunk_size;
@@ -5602,7 +6039,7 @@ define("moxie/image/Image", [
/**
Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data.
- @class Image
+ @class moxie/image/Image
@constructor
@extends EventTarget
*/
@@ -5621,7 +6058,7 @@ define("moxie/image/Image", [
/**
Dispatched when resize operation is complete.
-
+
@event resize
@param {Object} event
*/
@@ -5713,7 +6150,7 @@ define("moxie/image/Image", [
meta: {},
/**
- Alias for load method, that takes another mOxie.Image object as a source (see load).
+ Alias for load method, that takes another moxie.image.Image object as a source (see load).
@method clone
@param {Image} src Source for the image
@@ -5724,19 +6161,20 @@ define("moxie/image/Image", [
},
/**
- Loads image from various sources. Currently the source for new image can be: mOxie.Image, mOxie.Blob/mOxie.File,
- native Blob/File, dataUrl or URL. Depending on the type of the source, arguments - differ. When source is URL,
- Image will be downloaded from remote destination and loaded in memory.
+ Loads image from various sources. Currently the source for new image can be: moxie.image.Image,
+ moxie.file.Blob/moxie.file.File, native Blob/File, dataUrl or URL. Depending on the type of the
+ source, arguments - differ. When source is URL, Image will be downloaded from remote destination
+ and loaded in memory.
@example
- var img = new mOxie.Image();
+ var img = new moxie.image.Image();
img.onload = function() {
var blob = img.getAsBlob();
-
- var formData = new mOxie.FormData();
+
+ var formData = new moxie.xhr.FormData();
formData.append('file', blob);
- var xhr = new mOxie.XMLHttpRequest();
+ var xhr = new moxie.xhr.XMLHttpRequest();
xhr.onload = function() {
// upload complete
};
@@ -5744,7 +6182,7 @@ define("moxie/image/Image", [
xhr.send(formData);
};
img.load("http://www.moxiecode.com/images/mox-logo.jpg"); // notice file extension (.jpg)
-
+
@method load
@param {Image|Blob|File|String} src Source for the image
@@ -5754,30 +6192,188 @@ define("moxie/image/Image", [
_load.apply(this, arguments);
},
+
+ /**
+ Resizes the image to fit the specified width/height. If crop is specified, image will also be
+ cropped to the exact dimensions.
+
+ @method resize
+ @since 3.0
+ @param {Object} options
+ @param {Number} options.width Resulting width
+ @param {Number} [options.height=width] Resulting height (optional, if not supplied will default to width)
+ @param {String} [options.type='image/jpeg'] MIME type of the resulting image
+ @param {Number} [options.quality=90] In the case of JPEG, controls the quality of resulting image
+ @param {Boolean} [options.crop='cc'] If not falsy, image will be cropped, by default from center
+ @param {Boolean} [options.fit=true] Whether to upscale the image to fit the exact dimensions
+ @param {Boolean} [options.preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
+ @param {String} [options.resample='default'] Resampling algorithm to use during resize
+ @param {Boolean} [options.multipass=true] Whether to scale the image in steps (results in better quality)
+ */
+ resize: function(options) {
+ var self = this;
+ var orientation;
+ var scale;
+
+ var srcRect = {
+ x: 0,
+ y: 0,
+ width: self.width,
+ height: self.height
+ };
+
+ var opts = Basic.extendIf({
+ width: self.width,
+ height: self.height,
+ type: self.type || 'image/jpeg',
+ quality: 90,
+ crop: false,
+ fit: true,
+ preserveHeaders: true,
+ resample: 'default',
+ multipass: true
+ }, options);
+
+ try {
+ if (!self.size) { // only preloaded image objects can be used as source
+ throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
+ }
+
+ // no way to reliably intercept the crash due to high resolution, so we simply avoid it
+ if (self.width > Image.MAX_RESIZE_WIDTH || self.height > Image.MAX_RESIZE_HEIGHT) {
+ throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
+ }
+
+ // take into account orientation tag
+ orientation = (self.meta && self.meta.tiff && self.meta.tiff.Orientation) || 1;
+
+ if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation
+ var tmp = opts.width;
+ opts.width = opts.height;
+ opts.height = tmp;
+ }
+
+ if (opts.crop) {
+ scale = Math.max(opts.width/self.width, opts.height/self.height);
+
+ if (options.fit) {
+ // first scale it up or down to fit the original image
+ srcRect.width = Math.min(Math.ceil(opts.width/scale), self.width);
+ srcRect.height = Math.min(Math.ceil(opts.height/scale), self.height);
+
+ // recalculate the scale for adapted dimensions
+ scale = opts.width/srcRect.width;
+ } else {
+ srcRect.width = Math.min(opts.width, self.width);
+ srcRect.height = Math.min(opts.height, self.height);
+
+ // now we do not need to scale it any further
+ scale = 1;
+ }
+
+ if (typeof(opts.crop) === 'boolean') {
+ opts.crop = 'cc';
+ }
+
+ switch (opts.crop.toLowerCase().replace(/_/, '-')) {
+ case 'rb':
+ case 'right-bottom':
+ srcRect.x = self.width - srcRect.width;
+ srcRect.y = self.height - srcRect.height;
+ break;
+
+ case 'cb':
+ case 'center-bottom':
+ srcRect.x = Math.floor((self.width - srcRect.width) / 2);
+ srcRect.y = self.height - srcRect.height;
+ break;
+
+ case 'lb':
+ case 'left-bottom':
+ srcRect.x = 0;
+ srcRect.y = self.height - srcRect.height;
+ break;
+
+ case 'lt':
+ case 'left-top':
+ srcRect.x = 0;
+ srcRect.y = 0;
+ break;
+
+ case 'ct':
+ case 'center-top':
+ srcRect.x = Math.floor((self.width - srcRect.width) / 2);
+ srcRect.y = 0;
+ break;
+
+ case 'rt':
+ case 'right-top':
+ srcRect.x = self.width - srcRect.width;
+ srcRect.y = 0;
+ break;
+
+ case 'rc':
+ case 'right-center':
+ case 'right-middle':
+ srcRect.x = self.width - srcRect.width;
+ srcRect.y = Math.floor((self.height - srcRect.height) / 2);
+ break;
+
+
+ case 'lc':
+ case 'left-center':
+ case 'left-middle':
+ srcRect.x = 0;
+ srcRect.y = Math.floor((self.height - srcRect.height) / 2);
+ break;
+
+ case 'cc':
+ case 'center-center':
+ case 'center-middle':
+ default:
+ srcRect.x = Math.floor((self.width - srcRect.width) / 2);
+ srcRect.y = Math.floor((self.height - srcRect.height) / 2);
+ }
+
+ // original image might be smaller than requested crop, so - avoid negative values
+ srcRect.x = Math.max(srcRect.x, 0);
+ srcRect.y = Math.max(srcRect.y, 0);
+ } else {
+ scale = Math.min(opts.width/self.width, opts.height/self.height);
+
+ // do not upscale if we were asked to not fit it
+ if (scale > 1 && !opts.fit) {
+ scale = 1;
+ }
+ }
+
+ this.exec('Image', 'resize', srcRect, scale, opts);
+ } catch(ex) {
+ // for now simply trigger error event
+ self.trigger('error', ex.code);
+ }
+ },
+
/**
Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions.
@method downsize
- @param {Object} opts
- @param {Number} opts.width Resulting width
- @param {Number} [opts.height=width] Resulting height (optional, if not supplied will default to width)
- @param {Boolean} [opts.crop=false] Whether to crop the image to exact dimensions
- @param {Boolean} [opts.preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
- @param {String} [opts.resample=false] Resampling algorithm to use for resizing
+ @deprecated use resize()
*/
- downsize: function(opts) {
+ downsize: function(options) {
var defaults = {
width: this.width,
height: this.height,
type: this.type || 'image/jpeg',
quality: 90,
crop: false,
+ fit: false,
preserveHeaders: true,
- resample: false
- };
+ resample: 'default'
+ }, opts;
- if (typeof(opts) === 'object') {
- opts = Basic.extend(defaults, opts);
+ if (typeof(options) === 'object') {
+ opts = Basic.extend(defaults, options);
} else {
// for backward compatibility
opts = Basic.extend(defaults, {
@@ -5788,26 +6384,12 @@ define("moxie/image/Image", [
});
}
- try {
- if (!this.size) { // only preloaded image objects can be used as source
- throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
- }
-
- // no way to reliably intercept the crash due to high resolution, so we simply avoid it
- if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) {
- throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
- }
-
- this.exec('Image', 'downsize', opts.width, opts.height, opts.crop, opts.preserveHeaders);
- } catch(ex) {
- // for now simply trigger error event
- this.trigger('error', ex.code);
- }
+ this.resize(opts);
},
/**
Alias for downsize(width, height, true). (see downsize)
-
+
@method crop
@param {Number} width Resulting width
@param {Number} [height=width] Resulting height (optional, if not supplied will default to width)
@@ -5821,13 +6403,11 @@ define("moxie/image/Image", [
if (!Env.can('create_canvas')) {
throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
}
-
- var runtime = this.connectRuntime(this.ruid);
- return runtime.exec.call(this, 'Image', 'getAsCanvas');
+ return this.exec('Image', 'getAsCanvas');
},
/**
- Retrieves image in it's current state as mOxie.Blob object. Cannot be run on empty or image in progress (throws
+ Retrieves image in it's current state as moxie.file.Blob object. Cannot be run on empty or image in progress (throws
DOMException.INVALID_STATE_ERR).
@method getAsBlob
@@ -5873,31 +6453,34 @@ define("moxie/image/Image", [
},
/**
- Embeds a visual representation of the image into the specified node. Depending on the runtime,
- it might be a canvas, an img node or a thrid party shim object (Flash or SilverLight - very rare,
+ Embeds a visual representation of the image into the specified node. Depending on the runtime,
+ it might be a canvas, an img node or a thrid party shim object (Flash or SilverLight - very rare,
can be used in legacy browsers that do not have canvas or proper dataURI support).
@method embed
@param {DOMElement} el DOM element to insert the image object into
- @param {Object} [opts]
- @param {Number} [opts.width] The width of an embed (defaults to the image width)
- @param {Number} [opts.height] The height of an embed (defaults to the image height)
- @param {String} [type="image/jpeg"] Mime type
- @param {Number} [quality=90] Quality of an embed, if mime type is image/jpeg
- @param {Boolean} [crop=false] Whether to crop an embed to the specified dimensions
+ @param {Object} [options]
+ @param {Number} [options.width] The width of an embed (defaults to the image width)
+ @param {Number} [options.height] The height of an embed (defaults to the image height)
+ @param {String} [options.type="image/jpeg"] Mime type
+ @param {Number} [options.quality=90] Quality of an embed, if mime type is image/jpeg
+ @param {Boolean} [options.crop=false] Whether to crop an embed to the specified dimensions
+ @param {Boolean} [options.fit=true] By default thumbs will be up- or downscaled as necessary to fit the dimensions
*/
- embed: function(el, opts) {
+ embed: function(el, options) {
var self = this
, runtime // this has to be outside of all the closures to contain proper runtime
;
- opts = Basic.extend({
+ var opts = Basic.extend({
width: this.width,
height: this.height,
type: this.type || 'image/jpeg',
- quality: 90
- }, opts || {});
-
+ quality: 90,
+ fit: true,
+ resample: 'nearest'
+ }, options);
+
function render(type, quality) {
var img = this;
@@ -5920,7 +6503,7 @@ define("moxie/image/Image", [
}
if (Env.can('use_data_uri_of', dataUrl.length)) {
- el.innerHTML = ']*>/,"").replace(/<\/pre>\s*$/,""))}catch(n){return null}return c},abort:function(){var t=this;l&&l.contentWindow&&(l.contentWindow.stop?l.contentWindow.stop():l.contentWindow.document.execCommand?l.contentWindow.document.execCommand("Stop"):l.src="about:blank"),e.call(this,function(){t.dispatchEvent("abort")})}})}return e.XMLHttpRequest=u}),i(he,[ue,j],function(e,t){return e.Image=t}),a([u,c,l,d,h,f,p,m,g,v,w,y,E,_,b,x,R,A,I,T,S,O,N])}(this);;(function(e){"use strict";var t={},n=e.moxie.core.utils.Basic.inArray;return function r(e){var i,s;for(i in e)s=typeof e[i],s==="object"&&!~n(i,["Exceptions","Env","Mime"])?r(e[i]):s==="function"&&(t[i]=e[i])}(e.moxie),t.Env=e.moxie.core.utils.Env,t.Mime=e.moxie.core.utils.Mime,t.Exceptions=e.moxie.core.Exceptions,e.mOxie=t,e.o||(e.o=t),t})(this); \ No newline at end of file +!function(e,t){var i=function(){var e={};return t.apply(e,arguments),e.moxie};"function"==typeof define&&define.amd?define("moxie",[],i):"object"==typeof module&&module.exports?module.exports=i():e.moxie=i()}(this||window,function(){!function(e,t){"use strict";function i(e,t){for(var i,n=[],r=0;r | ' +
'