Uploading a pic doesn't just work on android native browser - javascript

I've been having problem with this code that uploads an image. It doesn't work on native android browser(Tried on galaxy note 2). It works fine on all other browsers on different machines. Please help if anyone has ever come across this problem before or can figure out what went wrong.
Here is the template -> image_upload_view.hbs
<label>
<div class='label-text'>{{t label }}:</div>
<div class="input-prepend">
<div class="preview" style="background-image: url('{{src}}');"></div>
<i class="icon-arrow-up"></i>
<span class="input-description">{{t description}}</span>
<span class="change-notification hide">{{t 'COMPONENT_IMAGE_UPLOAD_IMAGE_CHANGED'}}</span>
<i class="icons"></i>
<input class="input hide" type="file" name="image_file_name" accept="image/gif, image/jpeg, image/jpg, image/png"></input>
</div>
</label>
Here is the logic -> image_upload_view.js
var Base = require( '../../base' ),
_ = require( 'underscore' ),
oldBrowserPreviewImage = '/images/profiles/edit/default_cover_image_preview.jpg';
module.exports = Base.extend( {
className: 'component-image-upload',
events: {
'change input[type=file]': 'onChange',
'click .remove-image': 'onRemove'
},
getTemplateData: function () {
return _( this._super() ).extend( {
description: this.description,
label: this.label,
src: this.src
} );
},
postRender: function () {
// TODO: Let parent instantiate and pass in models once new hydration logic is merged.
var ModelType = require( '../../../models/image_upload/' + this.type );
this._super();
this.model = new ModelType( {
file_url: this.src
}, {
app: this.app
} );
this.renderImagePreview();
},
onChange: function ( evt ) {
this.updateFile( this.$( evt.currentTarget ) );
},
onRemove: function ( evt ) {
var fileInput = this.$( 'input[type=file]' );
// Prevent remove click from also triggering input's file selection.
this.disableEvent( evt );
// Quirky, but correct way to clear the file input.
// http://stackoverflow.com/questions/1043957/clearing-input-type-file-using-jquery#answer-13351234
fileInput.wrap( '<form>' ).closest( 'form' ).get( 0 ).reset();
fileInput.unwrap();
this.updateFile( fileInput );
},
updateFile: function ( fileInput ) {
this.model.setFile( fileInput );
this.renderImagePreview();
// TODO: Need to let parent know which model type this is until the parent
// can instantiate the model itself (pending hydration).
this.$el.trigger( 'imageUploadComponent:changed', [ this.model, this.type ] );
},
renderImagePreview: function () {
var self = this;
this.model.getFileUrl().done( function ( url ) {
var backgroundImage,
hasFile = self.model.hasFile(),
// If we have a file set but got a null URL back, it means we're using an old browser
// that doesn't support generating local file URLs via the FileReader API.
isOldBrowser = hasFile && url === null;
if ( url ) {
backgroundImage = 'url(\'' + url + '\')';
} else if ( isOldBrowser ) {
// For old browsers, show a generic preview image.
backgroundImage = 'url(\'' + oldBrowserPreviewImage + '\')';
} else {
backgroundImage = 'none';
}
self.$( '.preview' ).css( 'background-image', backgroundImage );
// If we can't show a preview of the selected image (old browsers), display a change notification message
// to let the user know that the selection "took".
self.$( '.change-notification' ).toggleClass( 'hide', !( hasFile && isOldBrowser ) );
self.toggleActionIcon( !url );
} );
},
toggleActionIcon: function ( toggle ) {
var input = this.$( '.icons' );
input.toggleClass( 'icon-add', toggle );
input.toggleClass( 'remove-image icon-close', !toggle );
}
} );
module.exports.id = 'shared/components/image_upload_view';

If you use <file accept="image/*"/> it should also work on older (Android) browser versions.
<file accept="image/jpeg"/> is only supported on newer browsers.
I don't know from which Chrome version it is supported (chrome://version), but:
Chrome v18: doesn't support it.
Chrome v38: supports it.

Related

Capturing images from HTML page in array using javascript

I'm trying to capture all images in an HTML page using Javascript. I found this similar question, the best answer to which gives in excellent detail a solution to the problem:
Detect all images with Javascript in an html page
My question is that I can't get the code shown in the best answer to run without error - even when I copy/paste directly into the Firefox console. I suspect the answer is straightforward, though it's had me scratching my head for hours - is anyone able to help please?
This code gives me the error "SyntaxError: missing ) after argument list"...
var elements = document.body.getElementsByTagName("*");
Array.prototype.forEach.call( elements, function ( el ) {
var style = window.getComputedStyle( el, false );
if ( style.backgroundImage != "none" ) {
images.push( style.backgroundImage.slice( 4, -1 ).replace(/['"]/g, "")
}
}
The full solution, which seems to include the above, also appears to give the same error...
var images = [],
bg_images = [],
image_parents = [];
document.addEventListener('DOMContentLoaded', function () {
var body = document.body;
var elements = document.body.getElementsByTagName("*");
/* When the DOM is ready find all the images and background images
initially loaded */
Array.prototype.forEach.call( elements, function ( el ) {
var style = window.getComputedStyle( el, false );
if ( el.tagName === "IMG" ) {
images.push( el.src ); // save image src
image_parents.push( el.parentNode ); // save image parent
} else if ( style.backgroundImage != "none" ) {
bg_images.push( style.backgroundImage.slice( 4, -1 ).replace(/['"]/g, "") // save background image url
}
}
/* MutationObserver callback to add images when the body changes */
var callback = function( mutationsList, observer ){
for( var mutation of mutationsList ) {
if ( mutation.type == 'childList' ) {
Array.prototype.forEach.call( mutation.target.children, function ( child ) {
var style = child.currentStyle || window.getComputedStyle(child, false);
if ( child.tagName === "IMG" ) {
images.push( child.src ); // save image src
image_parents.push( child.parentNode ); // save image parent
} else if ( style.backgroundImage != "none" ) {
bg_images.push( style.backgroundImage.slice( 4, -1 ).replace(/['"]/g, "") // save background image url
}
} );
}
}
}
var observer = new MutationObserver( callback );
var config = { characterData: true,
attributes: false,
childList: true,
subtree: true };
observer.observe( body, config );
});
Thank you.
You're missing some closing parentheses on the images.push() line and the last line.
Not sure if this will make your code do what you ultimately want it to do, but it will at least not cause a syntax error.
var elements = document.body.getElementsByTagName("*");
Array.prototype.forEach.call( elements, function ( el ) {
var style = window.getComputedStyle( el, false );
if ( style.backgroundImage != "none" ) {
images.push(style.backgroundImage.slice(4, -1).replace(/['"]/g, ""));
}
});

Making a HTML source object

I want to create a little HTML extension which provides a tag (uai) which will be formatted like <uai src="some_what_file.mp3" controller="nav" autoplay="true">
And so on this tag will get a javascript object assigned.
function uai(){
this.src = { ... }
this.controller = { ... }
this.autoplay = { ... }
}
But I wonder how I will apply this function as an object to the html tag and make the HTML tag to apply the source to this.src
This object will be similar to the input tag *
I know the audio tag exists, and I fully know how to use it. But I want to replace the audio tag and functions with this one. It will make it easier for me to make canvas supported audio marks, so that's why I need it.
You can just access it like you would any other element and do what you need to do with it.
console.log(document.querySelector('cookies').getAttribute('flavor'))
<cookies flavor="chocolate chip"></cookies>
There are two important catches you should be aware of though:
First, it can't be self-closing. Browsers handle self-closing elements (<cookies />) in a special way, and you can't create custom self-closing tags (this is also a limitation that frameworks like Angular have to deal with). It has to have a closing tag, even if it has no children: <cookies></cookies>
Second, you can't do things like document.querySelector('cookies').flavor and access the property directly. You need to use document.querySelector('cookies').getAttribute('flavor') or .setAttribute(). You can however apply it yourself to use it latter:
Array.prototype.slice.call(document.querySelectorAll('cookies'), 0).forEach(cookie => Object.defineProperty(cookie, 'flavor', {
get: () => cookie.getAttribute('flavor'),
set: (value) => cookie.setAttribute('flavor', value)
}));
let cookie = document.querySelector('cookies');
console.log(cookie.flavor);
cookie.flavor = 'sugar';
console.log(cookie.flavor);
console.log(cookie);
<cookies flavor="chocolate chip"></cookies>
<cookies flavor="peanut butter"></cookies>
Using a transpiler that support classes and extends is very easy.
class UAIElement extends HTMLElement {
}
document.registerElement('uai', UAIElement);
the plain js version:
document.registerElement('uai', {
prototype: Object.create(HTMLElement.prototype, {
extends: 'audio'
})
});
If you want to use Custom Elements you need to insert an hyphen - in the name of your tag to be sure it won't be used in the future standard, for example: <ultimate-audio>.
Also you should use now the version 1 of the Custom Elements specification, which uses customElements.define() instead of document.registerElement() to register a new element.
Last, you cannot use the extends:'audio' option if you want to create a new tag.
You can use the class definition in all modern browsers:
Content of ulimate-audio.html:
<template>
<h3>UAI</h3>
<nav>
<button id=PlayBtn>Play</button>
<button id=StopBtn>Stop</button>
<input id=AutoplayCB type=checkbox disabled>Auto-Play
<div>Source : <output id=SourceOut></output></div>
</nav>
</template>
<script>
( function ( owner )
{
class UAI extends HTMLElement
{
constructor ()
{
super()
this.model = {}
this.view = {}
}
connectedCallback ()
{
//View
this.innerHTML = owner.querySelector( 'template' ).innerHTML
this.view.autoplay = this.querySelector( '#AutoplayCB' )
this.view.source = this.querySelector( '#SourceOut' )
//Model
//autoplay
var attr = this.getAttribute( 'autoplay' )
this.model.autoplay = typeof attr == 'string' && ( attr == '' || attr == 'true' )
//source
this.model.source = this.getAttribute( 'src' )
//Model -> View
this.view.source.textContent = this.model.source
this.view.autoplay.checked = this.model.autoplay
//[play] event
var self = this
this.querySelector( '#PlayBtn' ).addEventListener( 'click', function ()
{
self.play()
} )
this.querySelector( '#StopBtn' ).addEventListener( 'click', function ()
{
self.stop()
} )
//init
if ( this.model.autoplay )
this.play()
}
play ()
{
this.model.audio = new Audio( this.model.source )
this.model.audio.play()
}
stop ()
{
this.model.audio.pause()
}
set src ( file )
{
console.log( '%s.src=%s', this, file )
this.model.source = file
this.model.audio.src = file
this.view.source.textContent = file
if ( this.model.autoplay )
this.model.audio.play()
}
set autoplay ( value )
{
console.warn( 'autoplay=', value )
this.model.autoplay = ( value === "true" || value === true )
this.view.autoplay.checked = this.model.autoplay
}
}
customElements.define( 'ultimate-audio', UAI )
} )( document.currentScript.ownerDocument )
</script>
The UI of you control is defined in the <template>, where you can add a <style> element.
Then you can use your tag like this:
In the header, include the custom element:
<link rel="import" href="ultimate-audio.html">
In the body, use the new tag:
<ultimate-audio id=UA src="path/file.mp3" autoplay></ultimate-audio>
The methods play(), stop(), and the properties src and autoplay can be invoked form javascript:
UA.src = "path/file2.mp3"
UA.play()

CKEditor - Image Properties dialog is blank

I am using the default Image plugin with the usual values:
CKEDITOR.replace( 'editor',
{
filebrowserBrowseUrl: '/app/myimages.html',
filebrowserUploadUrl: '/app/myfiles.html',
filebrowserImageBrowseUrl: '/app/myimages.html'
}
The image shows up correctly in the editor after selection via image select dialog box.
But when i right-click on the image and select Image Properties menu.
The dialog that opens does not contain the image URL or width or height etc. It essentially has no values.
See my comments. But for me it was overridding onShow().
CKEDITOR.on('dialogDefinition', function( ev ) {
// Take the dialog window name and its definition from the event data.
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
if ( dialogName == 'image' ) {
/*dialogDefinition.onShow = function() {
this.selectPage( 'info' );
};*/ // do not override this function, it will cause a JS on save (setCustomData can not be found on null object), and the edit image will not fill in its fields.
dialogDefinition.removeContents( 'Link' ); // remove these tabs
dialogDefinition.removeContents( 'advanced' );
dialogDefinition.removeContents( 'Upload' );
var contents = dialogDefinition.getContents( 'info' );
//contents.remove( 'htmlPreview' ); // will cause a JS error if disabled.
contents.remove( 'ratioLock' );
contents.remove( 'txtHSpace' );
contents.remove( 'txtVSpace' );
contents.remove( 'txtAlt' );
contents.remove( 'txtBorder' );
contents.get('txtWidth').width = 'auto';
contents.get('txtHeight').width = 'auto';
contents.get('txtUrl').disabled = 'disabled';
}
});

Custom wp.media with arguments support

How to setup a [add media] button, with:
proper wordpress [media] UI
has size and alignments UI in popup right hand side
can custom popup title and button
size and alignments arguments can send back to be use
Just try to cover most solutions:
use tb_show("", "media-upload.php?type=image&TB_iframe=true"); and window.send_to_editor
problem: has no standard wp.media UI
in js code:
jQuery("#my_button").click(function() {
tb_show("", "media-upload.php?type=image&TB_iframe=true");
return false;
});
window.send_to_editor = function(html) {
console.log(html);
tb_remove();
}
use wp.media({frame: 'post'})
problem: cannot custom UI elements, such as: title, button
in js code:
function clearField(){
#remove file nodes
#...
}
var frame = wp.media({frame: 'post'});
frame.on('close',function() {
var selection = frame.state().get('selection');
if(!selection.length){
clearField();
}
});
frame.on( 'select',function() {
var state = frame.state();
var selection = state.get('selection');
if ( ! selection ) return;
clearField();
selection.each(function(attachment) {
console.log(attachment.attributes);
});
});
frame.open();
use wp.media.editor with wp.media.editor.open( editor_id )
problem: cannot custom UI elements, such as: title, button
in js code: https://wordpress.stackexchange.com/questions/75808/using-wordpress-3-5-media-uploader-in-meta-box#75823
use wp.media with rewrite wp.media.controller.Library and retrieve attachment in select
problem: complicated ..., but once you understand it, it all make sense, and it is my finial solution
in js code:
/**
* Please attach all the code below to a button click event
**/
//create a new Library, base on defaults
//you can put your attributes in
var insertImage = wp.media.controller.Library.extend({
defaults : _.defaults({
id: 'insert-image',
title: 'Insert Image Url',
allowLocalEdits: true,
displaySettings: true,
displayUserSettings: true,
multiple : true,
type : 'image'//audio, video, application/pdf, ... etc
}, wp.media.controller.Library.prototype.defaults )
});
//Setup media frame
var frame = wp.media({
button : { text : 'Select' },
state : 'insert-image',
states : [
new insertImage()
]
});
//on close, if there is no select files, remove all the files already selected in your main frame
frame.on('close',function() {
var selection = frame.state('insert-image').get('selection');
if(!selection.length){
#remove file nodes
#such as: jq("#my_file_group_field").children('div.image_group_row').remove();
#...
}
});
frame.on( 'select',function() {
var state = frame.state('insert-image');
var selection = state.get('selection');
var imageArray = [];
if ( ! selection ) return;
#remove file nodes
#such as: jq("#my_file_group_field").children('div.image_group_row').remove();
#...
//to get right side attachment UI info, such as: size and alignments
//org code from /wp-includes/js/media-editor.js, arround `line 603 -- send: { ... attachment: function( props, attachment ) { ... `
selection.each(function(attachment) {
var display = state.display( attachment ).toJSON();
var obj_attachment = attachment.toJSON()
var caption = obj_attachment.caption, options, html;
// If captions are disabled, clear the caption.
if ( ! wp.media.view.settings.captions )
delete obj_attachment.caption;
display = wp.media.string.props( display, obj_attachment );
options = {
id: obj_attachment.id,
post_content: obj_attachment.description,
post_excerpt: caption
};
if ( display.linkUrl )
options.url = display.linkUrl;
if ( 'image' === obj_attachment.type ) {
html = wp.media.string.image( display );
_.each({
align: 'align',
size: 'image-size',
alt: 'image_alt'
}, function( option, prop ) {
if ( display[ prop ] )
options[ option ] = display[ prop ];
});
} else if ( 'video' === obj_attachment.type ) {
html = wp.media.string.video( display, obj_attachment );
} else if ( 'audio' === obj_attachment.type ) {
html = wp.media.string.audio( display, obj_attachment );
} else {
html = wp.media.string.link( display );
options.post_title = display.title;
}
//attach info to attachment.attributes object
attachment.attributes['nonce'] = wp.media.view.settings.nonce.sendToEditor;
attachment.attributes['attachment'] = options;
attachment.attributes['html'] = html;
attachment.attributes['post_id'] = wp.media.view.settings.post.id;
//do what ever you like to use it
console.log(attachment.attributes);
console.log(attachment.attributes['attachment']);
console.log(attachment.attributes['html']);
});
});
//reset selection in popup, when open the popup
frame.on('open',function() {
var selection = frame.state('insert-image').get('selection');
//remove all the selection first
selection.each(function(image) {
var attachment = wp.media.attachment( image.attributes.id );
attachment.fetch();
selection.remove( attachment ? [ attachment ] : [] );
});
//add back current selection, in here let us assume you attach all the [id] to <div id="my_file_group_field">...<input type="hidden" id="file_1" .../>...<input type="hidden" id="file_2" .../>
jq("#my_file_group_field").find('input[type="hidden"]').each(function(){
var input_id = jq(this);
if( input_id.val() ){
attachment = wp.media.attachment( input_id.val() );
attachment.fetch();
selection.add( attachment ? [ attachment ] : [] );
}
});
});
//now open the popup
frame.open();
I would like to add to ZAC's option 4 because when I used his code, the image src="" was missing.
Here is the fix
if ( 'image' === obj_attachment.type ) {
html = wp.media.string.image( display );
_.each({
align: 'align',
size: 'image-size',
alt: 'image_alt'
}, function( option, prop ) {
if ( display[ prop ] )
options[ option ] = display[ prop ];
});
html = wp.media.string.image( display, obj_attachment );
}
This way you can call the new media uploader with custom title and button and right side bar.
var custom_uploader;
jQuery('#fileform').on('click','.select-files', function(e) {
var button = jQuery(this);
custom_uploader = wp.media.frames.file_frame = wp.media({
title: 'Choose File',
library: {
author: userSettings.uid // specific user-posted attachment
},
button: {
text: 'Choose File'
},
multiple: false
});
//When a file is selected, grab the URL and set it as the text field's value
custom_uploader.on('select', function() {
attachment = custom_uploader.state().get('selection').first().toJSON();
console.log(attachment.url);
console.log(attachment.id); // use them the way you want
});
//Open the uploader dialog
// Set post id
wp.media.model.settings.post.id = jQuery('#post_ID').val();
custom_uploader.open();
});
Check this link -> https://github.com/phpcodingmaster/WordPress-Media-Modal-Image-Uploads
It will show you how to:
Open the admin media modal
Get single image info
Get multiple images info
Tested with WordPress Version 6.0

Backbone model.change() not firing

I'm currently writing an application using Backbone and for some reason, it doesn't update a view, but only in certain circumstances.
If I refresh the page at index.html#/blog/2 it loads the page just fine, everything works great. However, if I refresh the page at index.html#/blog/1 and then change the URL to index.html#/blog/2 and press enter(NOT refresh), the change never gets fired.
This is my router:
makeChange: function() {
// Set activePage to the current page_id => /blog/2
var attributes = {activePage: this.page_id};
var $this = this;
// Loop through all sections in the app
app.sections.some( function( section ) {
// Check if section has the page
if( !section.validate( attributes ) )
{
// If it has, set the activePage to /blog/2
section.set( attributes, {silent: true} );
// Set active section to whatever section-id was matched
app.set( {activeSect: section.id}, {silent: true} );
console.log('Calling change!');
// Calling change on both the app and the section
app.change();
section.change();
console.log('Change complete!');
return true;
}
});
}
This is the app view(which is referenced as "app" up above^):
var AppView = Backbone.View.extend({
initialize: function( option ) {
app.bind( 'change', _.bind( this.changeSect, this ) );
},
changeSect: function() {
var newSect = app.sections.get( app.get('activeSect' ) );
var newSectView = newSect.view;
if( !app.hasChanged( 'activeSect' ) )
newSectView.activate( null, newSect );
else
{
var oldSect = app.sections.get( app.previous( 'activeSect' ) );
var oldSectView = oldSect.view;
newSectView.activate( oldSect, newSect );
oldSectView.deactivate( oldSect, newSect );
}
}
});
Tell me if you need to see some other classes/models/views.
I solved it! This only happens when navigating between different pages(by changing activePage in the section) in the same section, so activeSect in app was never changed, thus never called changeSect(). Now even when activeSect is the same in the app, and activePage has changed in the section, it will call the changeSect() in the app anyway.
In Section-model, I added this:
initialize: function() {
this.pages = new Pages();
this.bind( 'change', _.bind( this.bindChange, this ) );
},
prepareForceChange: function() {
this.forceChange = true;
},
bindChange: function() {
console.log('BINDCHANGE!');
if( this.forceChange )
{
AppView.prototype.forceChange();
this.forceChange = false;
}
},
In router.makeChange() above this:
section.set( attributes, {silent: true} );
app.set( {activeSect: section.id}, {silent: true} );
I added:
var oldSectId = app.get('activeSect');
if( oldSectId == section.id ) section.prepareForceChange();

Categories

Resources