I have a gap just below my first pre tag I can not remove it.
I have tried
pre {
margin: 0 0 0;
}
And
pre {
margin: 0 0 0 !important;
}
But still shows
Question: How is it possible to correctly remove the margin or padding
just below the first pre?
Note: just found out something to do with nl2br on controller function below
I use codeigniter and ajax to generate the preview.
CSS
<style type="text/css">
body {
background-color: #F0F0F0;
}
pre {
display: block;
padding: 9.5px;
margin: 0 0 0 !important;
font-size: 13px;
line-height: 1.42857143;
color: #333;
word-break: break-all;
word-wrap: break-word;
background-color: #f5f5f5;
border: 1px solid #ccc;
border-radius: 4px;
}
hr {
background-color: #dedede !important;
height: 1px !important;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
padding: 0;
font-family: Roboto,"Helvetica Neue",Helvetica,Arial,sans-serif;
margin-top: 0;
}
</style>
Script
<script type="text/javascript">
$('#preview-question').on('click', function (e) {
$.ajax({
url: "<?php echo base_url('question/preview');?>",
type: 'POST',
data: {
title: $('#title').val(),
question: $('#question').val(),
'<?php echo $this->security->get_csrf_token_name(); ?>' : '<?php echo $this->security->get_csrf_hash(); ?>'
},
dataType: 'json',
success: function(response){
if (response.success) {
$('#preview').html(response.question);
$('#preview pre br').remove();
var str = $('#preview pre').html();
$('#preview pre').html(str.replace(/</g, "<").replace(/>/g, ">"));
$('pre').each(function(i, block) {
hljs.highlightBlock(block);
});
} else {
}
}
});
e.preventDefault();
});
</script>
Function
public function preview() {
$data = array('success' => false, 'question' => '');
if ($_POST) {
$data['question'] = nl2br($this->input->post('question'));
$data['success'] = true;
}
echo json_encode($data);
}
FULL HTML
<?php echo form_open_multipart('question/create', array('id' => 'question_create', 'class' => 'form-horizontal', 'role' => 'form'));?>
<div class="container">
<div class="row">
<div class="panel panel-default">
<div class="panel-heading">
<h1 class="panel-title"></h1>
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-lg-2">Title</label>
<div class="col-lg-10">
<input type="text" name="title" id="title" class="form-control" placeholder="Title" />
</div>
</div>
<div class="form-group">
<label class="col-lg-2">Question</label>
<div class="col-lg-10">
<textarea name="question" id="question" class="form-control" rows="10"></textarea>
</div>
</div>
<div class="form-group">
<label class="col-lg-2"></label>
<div class="col-lg-10">
<div id="preview"></div>
</div>
</div>
</div>
<div class="panel-footer">
<div class="text-center">
<button type="submit" class="btn btn-primary">Submit</button>
<button type="button" id="preview-question" class="btn btn-default">Preview</button>
<button type="button" class="btn btn-warning">Clear Textarea</button>
Cancel
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$('#preview-question').on('click', function (e) {
$.ajax({
url: "<?php echo base_url('question/preview');?>",
type: 'POST',
data: {
title: $('#title').val(),
question: $('#question').val(),
'<?php echo $this->security->get_csrf_token_name(); ?>' : '<?php echo $this->security->get_csrf_hash(); ?>'
},
dataType: 'json',
success: function(response){
if (response.success) {
$('#preview').html(response.question);
$('#preview pre br').remove();
var str = $('#preview pre').html();
$('#preview pre').html(str.replace(/</g, "<").replace(/>/g, ">"));
$('#preview pre').each(function(i, block) {
hljs.highlightBlock(block);
});
} else {
}
}
});
e.preventDefault();
});
</script>
<?php echo form_close();?>
I think if you format your HTML like this, you can manage the margins of a pre element. You have to apply the 'box' styles of color and backgroud e.g. to the .highlight class and the other styles to the pre.
The code element is optional if you use the same 'code recognizer' as bootstrap.
HTML
<figure class="highlight">
<pre>
<!--<code class="language-html" data-lang="html">-->
<!-- your code here -->
<!--</code>-->
</pre>
</figure>
CSS
.highlight {
padding: 9px 14px;
margin-bottom: 0; /* no margin-bottom */
}
First i think you should use
pre {
margin: 0 0 0 0 !important;
}
instead of
pre {
margin: 0 0 0 !important;
}
Let me know if that helps
Add clear into the pre tag
pre {
clear:both;
}
Thanks to #djl suggestion I have found out i needed to add replace('\n', '') to my script below to remove invisible line breaks
All working
<script type="text/javascript">
$('#preview-question').on('click', function (e) {
$.ajax({
url: "<?php echo base_url('question/preview');?>",
type: 'POST',
data: {
title: $('#title').val(),
question: $('#question').val(),
'<?php echo $this->security->get_csrf_token_name(); ?>' : '<?php echo $this->security->get_csrf_hash(); ?>'
},
dataType: 'json',
success: function(response){
if (response.success) {
$('#preview').html(response.question);
$('#preview pre br').remove();
var str = $('#preview pre').html();
$('#preview pre').html(str.replace(/</g, "<").replace(/>/g, ">").replace('\n', ''));
$('#preview pre').each(function(i, block) {
hljs.highlightBlock(block);
});
} else {
}
}
});
e.preventDefault();
});
</script>
Related
Our videos use the lower third of the page for introductions, etc. much like TV News stations do. When captions are on, they're blocking all of that, thus creating a LOT of complaints from the communities that need the captions. I've tried tinkering with the CSS, but with a responsive layout, resizing the player wreaks havoc, often putting them out of sight altogether.
Is there a setting that can be changed, or technique to use, that will keep the captions at the top and in view when resized, OR in an external container?
Problem: the JW player 608 live captions are not formatted cleanly.
To solve this, disable the JW caption display and format our own window, named "ccbuffer"
<style type="text/css">
.jw-captions {
display: none !important;
}
#ccbuffer {
border: 2px solid white !important;
border-radius: 4px;
background-color: black !important;
display: flex;
height: 120px;
margin-top: 6px;
font: 22px bold arial, sans-serif;
color: white;
justify-content: center;
align-items: center;
}
</style>
Here is where I show the player, and ccbuffer is a div right below it
<div id="myPlayer">
<p style="color: #FFFFFF; font-weight: bold; font-size: x-large; border-style: solid; border-color: #E2AA4F">
Loading video...
</p>
</div>
<div id="ccbuffer" />
DOMSubtreeModified is deprecated. Use MutationObserver, which is less stressful on the client.
Let's hook the 'captionsChanged' event from JW. if track is 0 then no captions are selected and we disconnect the observer. If captions are selected, then we use jquery to pull the text out of the jw-text-track-cue element, and format it into a nice 3 line display in our ccbuffer window.
<script>
var observer;
jwplayer().on('captionsChanged', function (event) {
if (event.track == 0) {
observer.disconnect();
$('#ccbuffer').hide('slow');
}
else {
$('#ccbuffer').show('slow');
// select the target node
var target = document.querySelector('.jw-captions');
// create an observer instance
observer = new MutationObserver(function(mutations) {
$('.jw-text-track-cue').each(function(i) {
if (i == 0)
$('#ccbuffer').html( $(this).text() );
else
$('#ccbuffer').append("<br/>" + $(this).text() );
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true }
// pass in the target node, as well as the observer options
observer.observe(target, config);
}
});
$(document).ready(function () {
$('#ccbuffer').hide();
});
</script>
So when the user enables captions, the ccbuffer window will slide open and display a clean 3 line representation of the CC text.
Final Solution: External Captions that are draggable/resizable
All credit to #Basildane, I worked out how to extenalize the captions with VOD, and to make them draggable and resizable, with CSS experimentation for ADA consideration:
<!DOCTYPE html>
<html>
<head>
<title>JW External Captions</title>
<meta http-equiv="Expires" content="Fri, Jan 01 1900 00:00:00 GMT">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Lang" content="en">
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="/jwplayer/v8.10/jwplayer.js"></script>
<style type="text/css">
#myPlayer {
margin-bottom:5px;
}
.jw-captions {
display: none !important;
}
#ccbuffer {
color: white;
background-color: black;
opacity:.7;
font: 22px bold san-serif;
width: 100%;
padding: 15px;
height: 100%;
position:relative;
}
.night {
color:silver !important;
background-color: black !important;
opacity:1 !important;
border-color:silver !important;
}
.highcontrast {
color:white ! important;
background-color: black !important;
opacity:1 !important;
border-color:white !important;
}
.highcontrast2 {
color:black !important;
background-color: yellow !important;
opacity:1 !important;
border-color:black !important;
}
.highcontrast3 {
color:yellow !important;
background-color: black !important;
opacity:1 !important;
border-color:yellow !important;
}
#ccContainer {
position: absolute;
z-index: 9;
border: 1px solid inherit;
overflow: hidden;
resize: both;
width: 640px;
height: 180px;
min-width: 120px;
min-height: 90px;
max-width: 960px;
max-height: 300px;
}
#ccContainerheader {
padding: 3px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
border:1px solid;
}
</style>
</head>
<body>
<h3>JW Draggable Captions Container</h3>
<div id="PlayerContainer" style="width:401px;">
<div id="myPlayer">Loading video...</div>
</div>
<div id="ccContainer">
<!-- Include a header DIV with the same name as the draggable DIV, followed by "header" -->
<div style="float:right;">
<form id="myform">
<select id="ccFontFamily">
<option value="sans-serif">Default Font</option>
<option value="serif">Serif</option>
<option value="monospace">Monospace</option>
<option value="cursive">Cursive </option>
</select>
<select id="ccFontSize" style="">
<option value="22">Default Size</option>
<option value="14">14</option>
<option value="18">18</option>
<option value="24">24</option>
<option value="32">32</option>
</select>
<select id="ccContrast" style="">
<option value="ccdefault">Default Contrast</option>
<option value="night">Night</option>
<option value="highcontrast">High Contrast</option>
<option value="highcontrast2">Black/Yellow</option>
<option value="highcontrast3">Yellow/Black</option>
</select>
<button id="ccFontReset">Reset</button>
</form>
</div>
<div id="ccContainerheader">
Captions (click to move)
</div>
<div id="ccbuffer"></div>
</div>
<script type="text/javascript">
$(document).ready(function() {
jwplayer.key = 'xxxxxxxxxxxxxxxxxxx';
jwplayer('myPlayer').setup({
width: '100%', aspectratio: '16:9', repeat: 'false', autostart: 'false',
playlist: [{
sources: [ { file: 'https:www.example.com/video.mp4'}],
tracks: [ { file: 'https:www.example.com/video-captions.vtt', kind: 'captions', label: 'English', 'default': true } ]
}]
})
// External CC Container
$('#ccContainer').hide();
var position = $('#myPlayer').position();
var width = $('#PlayerContainer').outerWidth();
ccTop = position.top;
ccLeft = (width+50)+'px'
$('#ccContainer').css({'top':ccTop, left:ccLeft });
var observer;
jwplayer().on('captionsList', function (event) {
ccObserver(event);
});
jwplayer().on('captionsChanged', function (event) {
ccObserver(event);
});
videoplayer.on('fullscreen', function(event){
if(event.fullscreen){
$('.jw-captions').css('display','block');
}else{
$('.jw-captions').css('display','none');
}
});
$("#ccFontFamily").change(function() {
$('#ccbuffer').css("font-family", $(this).val());
});
$("#ccFontSize").change(function() {
$('#ccbuffer').css("font-size", $(this).val() + "px");
});
$("#ccContrast").change(function() {
$('#ccContainer').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
$('#ccContainerheader').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
$('#ccbuffer').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
$('select').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
$('#ccFontReset').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
});
$('#ccFontReset').click(function() {
ccFontReset();
});
function ccFontReset(){
$("#ccFontFamily").val($("#ccFontFamily option:first").val()).trigger('change');
$("#ccFontSize").val($("#ccFontSize option:first").val()).trigger('change');
$("#ccContrast").val($("#ccContrast option:first").val()).trigger('change');
}
ccFontReset();
});
function ccObserver(event){
if (event.track == 0) {
$('#ccContainer').hide('slow');
$('.jw-captions').css('display','block'); // VERY important
if (observer != null){
observer.disconnect();
}
}
else {
$('#ccContainer').show('slow');
$('.jw-captions').css('display','none'); // VERY important
var target = document.querySelector('.jw-captions');
observer = new MutationObserver(function(mutations) {
$('.jw-text-track-cue').each(function(i) {
if (i == 0)
$('#ccbuffer').html( $(this).text() );
else
$('#ccbuffer').append("<br/>" + $(this).text() );
});
});
var config = { attributes: true, childList: true, characterData: true }
observer.observe(target, config);
}
}
// External CC Container - Make the DIV element draggable:
dragElement(document.getElementById("ccContainer"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById(elmnt.id + "header")) {
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
}
}
</script>
</body>
</html>
#(Html.Kendo().Upload()
.Name("files").Multiple(false)
.HtmlAttributes(new { #style = "width:100%" })
.HtmlAttributes(new { accept = ".doc, .docx, .pdf, .ppt, .pptx " }) )
<input type="button" id="btnsubmit" value="Save"/>
<script id="fileTemplate" type="text/x-kendo-template">
<div class='file-wrapper'>
<label class="col-sm-1 col-xs-1" style="padding-left:0px!important;">
<span class='file-icon #=addExtensionClass(files[0].extension)#'></span>
</label>
<label class="col-sm-9 col-xs-9"><span class='uploadFileName'>#=name#</span></label>
<label class="col-sm-9 col-xs-9" style="margin-top:20px;display:none;">
<input type="text" class="k-textbox"
data-val-required="*"
style="width:70%"
id="txtFileName" name="txtFileName"
value="#=name.substring(0, name.lastIndexOf('.'))#" />
<span class="k-icon k-i-tick fileRenameTick" style="cursor:pointer;" data-extension="#=name.split('.').pop()#"></span>
<span class="k-icon k-i-close fileRenameTickClose" style="cursor:pointer;"></span>
</label>
<div class="col-sm-1 col-xs-1 btnFileRemove" style="padding-right:0px!important;padding-left:0px!important;margin-left:0px!important;width:5%!important;border:0px solid red;">
<span class='k-icon k-i-close fileRemove'></span>
</div>
</div>
</script>
<script>
var myfile = [];
$(document).ready(function () {
});
var i = 0;
function onUpload(e) {
myfile.push(e.files[0]);
}
$('#btnsubmit').click(function () {
var fileRenameList = [];
var formData = new FormData();
formData.append("BookBackImage", $("#companyname").val());
formData.append("BookFrontImage", $("#country").val());
for (var i = 0; i < myfile.length; i++) {
alert(myfile.length);
formData.append("file[" + i + "]", myfile[i].rawFile);
}
$('.uploadFileName').each(function () {
fileRenameList.push($(this).text());
});
formData.append("FrontImageRename", JSON.stringify(fileRenameList));
$.ajax({
type: "POST",
url: '#Url.Action("Index","Library")',
data: formData,
dataType: 'json',
contentType: false,
processData: false,
success: function (response) {
},
error: function (error) {
}
});
});
function addExtensionClass(extension) {
switch (extension) {
case '.jpg':
case '.jpeg':
case '.img':
case '.gif':
return "img-file";
case '.png':
return "png-file";
case '.doc':
case '.docx':
return "doc-file";
case '.ppt':
case '.pptx':
return "ppt-file";
case '.xls':
case '.xlsx':
return "xls-file";
case '.pdf':
return "pdf-file";
case '.zip':
case '.rar':
return "zip-file";
default:
return "default-file";
}
}
$(document).on("click", ".fileRenameTick", function (e) {
e.preventDefault();
var inputval = $(this).siblings('input').kendoValidator().data("kendoValidator");
if (inputval.validate()) {
var ext = $(this).data("extension");
var reName = $(this).siblings('input').val() + "." + ext;
$(this).parent('label').prev('label').children('span').text(reName);
$(this).parent('label').css("display", "none");
$(this).parent('label').prev('label').css("display", "inline");
}
});
$(document).on("click", ".fileRenameTickClose", function (e) {
e.preventDefault();
$(this).parent('label').css("display", "none");
$(this).parent('label').prev('label').css("display", "inline");
});
$(document).on("click", ".fileRemove", function (e) {
e.preventDefault();
$(this).parent('div').parent('div').parent('li').remove();
var uid = $(this).parent('div').parent('div').parent('li').data("uid");
$.each(myfile, function (i, el) {
if (this.uid === uid) {
myfile.splice(i, 1);
}
});
});
$(document).on("click", ".uploadFileName", function (e) {
e.preventDefault();
var str = $(this).text();
var rest = str.substring(0, str.lastIndexOf("."));
$(this).parent('label').next('label').css("display", "inline");
$(this).parent('label').next('label').children('input').val(rest);
$(this).parent('label').css("display", "none");
$(this).parent('label').next('label').children('.field-validation-error').hide();
$("#txtFileName_validationMessage").hide();
});
</script>
<style>
.file-icon {
display: inline-block;
float: left;
width: 48px;
height: 48px;
margin-top: 13.5px;
}
.lblForMaterialName .file-icon {
float: left;
width: 20px;
height: 20px;
}
.img-file {
background-image: url(../content/web/upload/jpg.png);
}
.png-file {
background-image: url(../content/web/upload/png_converted.png);
}
.doc-file {
background-image: url(../content/web/upload/doc.png);
}
.ppt-file {
background-image: url(../content/web/upload/ppt.png);
}
.pdf-file {
background-image: url(../content/web/upload/pdf.png);
}
.xls-file {
background-image: url(../content/web/upload/xls.png);
}
.zip-file {
background-image: url(../content/web/upload/zip.png);
}
.default-file {
background-image: url(../content/web/upload/default.png);
}
.uploadFileName, .uploadBookBackImage, .uploadBookImage, .uploadBookOtherImage {
cursor: pointer;
font-size: .9em;
float: left;
width: 95%;
height: 25px;
-ms-text-overflow: ellipsis;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
margin-top: 20px;
font-weight: normal;
}
/*.test{
float: left;
-ms-text-overflow: ellipsis;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}*/
li.k-file div.file-wrapper {
position: relative;
height: 75px;
}
.k-file {
padding: .5em .0em .0em .5em !important;
}
.btnFileRemove {
padding-right: 0px !important;
padding-left: 0px !important;
margin-left: 0px !important;
width: 5% !important;
}
</style>
#using (Html.BeginForm(new { enctype = "multipart/form-data" }))
{
<input type="text" id="companyname" name="companyname" />
<input type="text" id="country" name="country" />
#(Html.Kendo().Upload().Name("file")
.Multiple(true).TemplateId("fileTemplate")
.Async(a => a.Save("LibraryFileSave", "Library")
.AutoUpload(true))
.Events(m => m.Upload("onUpload"))
)
<input type="button" id="btnsubmit" value="test"/>
}
<form method="post" id="form" action="update.php">
<label for="control">Control: <input id="control" class="k-checkbox" type="checkbox"/></label>
<input name="photos" id="photos" type="file"/>
<input id="send" class="k-button" type="button" value="Save"/>
</form>
Now, the JavaScript for uploading files:
$("#photos").kendoUpload({
multiple: false
});
And the function for validating the form:
$("#send").on("click", function (e) {
var ctl = $("#control").is(":checked");
if (ctl) {
// if so, send the form
$("#form").submit();
} else {
// otherwise show an alert
alert("Please check 'control' before sending");
}
});
How do I reverse the order of records returned by <firebase-collection> as follows:
<firebase-collection id="foo" order-by-child="bar">
?
Can I do it declaratively? Or do I need to call an imperative method like maybe...
this.$.foo = this.$.foo.reverse();
https://elements.polymer-project.org/elements/firebase-element?active=firebase-collection
Note: I'm using <iron-list> and not <template is="dom-repeat">.
Simplest is just to use a <dom-repeat> with an inverse sort I believe.
sort. Specifies a comparison function following the standard Array sort API.
Per https://www.polymer-project.org/1.0/docs/devguide/templates.html#filtering-and-sorting-lists
The best solution is to use <iron-list> then sort that according to this answer.
http://jsbin.com/vizexodoyi/1/edit?html,output
<html>
<head>
<title>My Element</title>
<script data-require="polymer#*" data-semver="1.0.0" src="http://www.polymer-project.org/1.0/samples/components/webcomponentsjs/webcomponents-lite.js"></script>
<script data-require="polymer#*" data-semver="1.0.0" src="http://www.polymer-project.org/1.0/samples/components/polymer/polymer.html"></script>
<base href="http://element-party.xyz/" />
<link rel="import" href="all-elements.html" />
</head>
<body>
<dom-module id="my-element">
<template>
<style>
h3 {
margin-bottom: 0px;
}
iron-list {
padding-bottom: 16px;
height: 100%;
}
.item {
#apply(--layout-horizontal);
margin: 16px 16px 0 16px;
padding: 20px;
border-radius: 8px;
background-color: white;
border: 1px solid #ddd;
}
</style>
<firebase-collection location="https://dinosaur-facts.firebaseio.com/dinosaurs" data="{{items}}">
</firebase-collection>
<h3>Controls</h3>
<paper-dropdown-menu label="Sort by">
<paper-menu class="dropdown-content" selected="{{sortVal}}" attr-for-selected="data-sortby">
<paper-item data-sortby="order">Order</paper-item>
<paper-item data-sortby="height">Height</paper-item>
</paper-menu>
</paper-dropdown-menu>
<br>
<paper-toggle-button checked="{{reverse}}">Reverse</paper-toggle-button>
<br /><br />
<br><h3>Monitor Control Values</h3>
<div>Sort by: [[sortVal]]</div>
<div>Reverse: [[reverse]]</div>
<br><h3>Iron-List Output</h3>
<iron-list id="list" items="[[items]]" as="item">
<template>
<div class="item">
Name: [[item.__firebaseKey__]]<br />
Order: [[item.order]]<br />
Height: [[item.height]]
</div>
</template>
</iron-list>
</template>
<script>
(function() {
Polymer({
is: "my-element",
properties: {
items: {
type: Array,
},
sortVal: {
type: String,
value: 'order'
},
sortOrder: {
type: Number,
value: -1, // High to low
computed: '_computeSortOrder(reverse)'
}
},
observers: [
'sortChanged(sortVal, sortOrder)'
],
_computeSortOrder: function(bool) {
return bool ? 1 : -1;
},
sortChanged(val, ord) {
if (! this.items || this.items.length == 0) {
return;
}
var temp = Array.prototype.slice.call(this.items);
temp.sort(this._computeSort(val, ord));
this.items = temp;
//console.log('ord: ' + ord);
//console.log('val: ' + val);
//console.log('items: ' + this.items);
},
_computeSort: function(val, ord) {
return function(a, b) {
if (a[val] === b[val]) {
return 0;
}
return (ord * (a[val] > b[val] ? 1 : -1));
};
}
});
})();
</script>
</dom-module>
<my-element></my-element>
</body>
</html>
<button class="button {{radius ? 'button-radius' : ''}} {{radius || ''}} {{size || '' }}">
{{ text }}
</button>
output from:
<button radius="15px" size="med" text="whatever" />
Wanted it to be easy for users to input border-radius="#px" instead of me using css to change radius. So I have been fidding but only button-radius works which has 5px radius set. Is there any way to be able to input value number in radius?
Help appreciated
There are a couple of ways you could do this. First, you could incorporate a <style> tag into your template - that way it becomes subject to the same data-binding rules as everything else:
var ractive = new Ractive({
el: 'main',
template: '#template',
data: {
radius: 10
}
});
label { display: block; }
button.large { font-size: 2em; padding: 20px; }
<script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
<main></main>
<script id='template' type='text/html'>
<style>
button {
padding: 10px;
border-radius: {{radius}}px;
}
button.large {
border-radius: {{radius*2}}px;
}
</style>
<label>
<input type='range' value='{{radius}}' min='1' max='20'/>
{{radius}}px
</label>
<button>I am a button</button>
<button class='large'>I am a button</button>
</script>
Secondly, in this scenario it's perfectly sensible to use inline styles:
var ractive = new Ractive({
el: 'main',
template: '#template',
data: {
radius: 10
}
});
label { display: block; }
button.large { font-size: 2em; padding: 20px; }
<script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
<main></main>
<script id='template' type='text/html'>
<label>
<input type='range' value='{{radius}}' min='1' max='20'/>
{{radius}}px
</label>
<button style='border-radius: {{radius}}px'>I am a button</button>
<button class='large' style='border-radius: {{radius*2}}px'>I am a button</button>
</script>
I'm building a custom ReactJS component (A 'Select2' dropdown library wrapper) and want to implement support for the standard two-way binding helper with the 'valueLink' parameter.
However it appears the mixin to handle the 'valueLink' parameter only applies to standard components, not custom components.
Is there a way to have my component implement the standard valueLink behaviour automatically, or will I need to explicitly parse and implement this support myself (Potentially introducing bugs or odd behaviours that aren't present in the base library)
The object returned from this.linkState when using the LinkedStateMixin has two relevant properties: value and requestChange(). Simply use those two properties as your value and change handler, respectively, just as if they had been passed to your custom component via value and onChange.
Here's an example of a composite component that wraps a jQuery color picker; it works both with valueLink and with standard value and onChange properties. (To run the example, expand the "Show code snippet" then click "Run code snippet" at the bottom.)
var ColorPicker = React.createClass({
render: function() {
return <div />;
},
getValueLink: function(props) {
// Create an object that works just like the one
// returned from `this.linkState` if we weren't passed
// one; that way, we can always behave as if we're using
// `valueLink`, even if we're using plain `value` and `onChange`.
return props.valueLink || {
value: props.value,
requestChange: props.onChange
};
},
componentDidMount: function() {
var valueLink = this.getValueLink(this.props);
jQuery(this.getDOMNode()).colorPicker({
pickerDefault: valueLink.value,
onColorChange: this.onColorChange
});
},
componentWillReceiveProps: function(nextProps) {
var valueLink = this.getValueLink(nextProps);
var node = jQuery(this.getDOMNode());
node.val(valueLink.value);
node.change();
},
onColorChange: function(id, color) {
this.getValueLink(this.props).requestChange(color);
}
});
div.colorPicker-picker {
height: 16px;
width: 16px;
padding: 0 !important;
border: 1px solid #ccc;
background: url(https://raw.github.com/laktek/really-simple-color-picker/master/arrow.gif) no-repeat top right;
cursor: pointer;
line-height: 16px;
}
div.colorPicker-palette {
width: 110px;
position: absolute;
border: 1px solid #598FEF;
background-color: #EFEFEF;
padding: 2px;
z-index: 9999;
}
div.colorPicker_hexWrap {width: 100%; float:left }
div.colorPicker_hexWrap label {font-size: 95%; color: #2F2F2F; margin: 5px 2px; width: 25%}
div.colorPicker_hexWrap input {margin: 5px 2px; padding: 0; font-size: 95%; border: 1px solid #000; width: 65%; }
div.colorPicker-swatch {
height: 12px;
width: 12px;
border: 1px solid #000;
margin: 2px;
float: left;
cursor: pointer;
line-height: 12px;
}
<script src="http://fb.me/react-with-addons-0.11.2.js"></script>
<script src="http://fb.me/JSXTransformer-0.11.2.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="https://dl.dropboxusercontent.com/u/113308/dnd/jsfiddle/jquery.colorPicker.min.js"></script>
<p><strong>With valueLink</strong></p>
<div id="app1"></div>
<hr>
<p><strong>With value and onChange</strong></p>
<div id="app2"></div>
<script type="text/jsx">
/** #jsx React.DOM */
var ApplicationWithValueLink = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return { color: "#FF0000" }
},
render: function() {
return (
<div>
<div>
<span style={{color: this.state.color}}>My Color Picker</span>
<button onClick={this.changeColor.bind(null, "#FF0000")}>Red</button>
<button onClick={this.changeColor.bind(null, "#00FF00")}>Green</button>
<button onClick={this.changeColor.bind(null, "#0000FF")}>Blue</button>
<input type="text" valueLink={this.linkState("color")} />
</div>
<div>
<ColorPicker valueLink={this.linkState("color")} />
</div>
</div>
);
},
changeColor: function(color) {
this.setState({color: color});
}
});
var ApplicationWithoutValueLink = React.createClass({
getInitialState: function() {
return { color: "#FF0000" }
},
render: function() {
return (
<div>
<div>
<span style={{color: this.state.color}}>My Color Picker</span>
<button onClick={this.changeColor.bind(null, "#FF0000")}>Red</button>
<button onClick={this.changeColor.bind(null, "#00FF00")}>Green</button>
<button onClick={this.changeColor.bind(null, "#0000FF")}>Blue</button>
<input type="text" value={this.state.color} onChange={this.changeColorText} />
</div>
<div>
<ColorPicker value={this.state.color} onChange={this.changeColor} />
</div>
</div>
);
},
changeColor: function(color) {
this.setState({color: color});
},
changeColorText: function(evt) {
this.changeColor(evt.target.value);
}
});
var ColorPicker = React.createClass({
render: function() {
return (
<div />
);
},
getValueLink: function(props) {
return props.valueLink || {
value: props.value,
requestChange: props.onChange
};
},
componentDidMount: function() {
var valueLink = this.getValueLink(this.props);
jQuery(this.getDOMNode()).colorPicker({
pickerDefault: valueLink.value,
onColorChange: this.onColorChange
});
},
componentWillReceiveProps: function(nextProps) {
var valueLink = this.getValueLink(nextProps);
var node = jQuery(this.getDOMNode());
node.val(valueLink.value);
node.change();
},
onColorChange: function(id, color) {
this.getValueLink(this.props).requestChange(color);
}
});
React.renderComponent(<ApplicationWithValueLink />, document.getElementById("app1"));
React.renderComponent(<ApplicationWithoutValueLink />, document.getElementById("app2"));
</script>