Horizontal pagination in android webview like ios - javascript

func setupScrollDirection() {
switch readerConfig.scrollDirection {
case .vertical, .defaultVertical, .horizontalWithVerticalContent:
scrollView.isPagingEnabled = false
paginationMode = .unpaginated
scrollView.bounces = true
break
case .horizontal:
scrollView.isPagingEnabled = true
paginationMode = .leftToRight
paginationBreakingMode = .page
scrollView.bounces = false
break
}
}
Is any alternate to the above code, Iam trying to use webview horizontally.I have tried with javaScript like this
String varMySheet = "var mySheet = document.styleSheets[0];";
String addCSSRule = "function addCSSRule(selector, newRule) {"
+ "ruleIndex = mySheet.cssRules.length;"
+ "mySheet.insertRule(selector + '{' + newRule + ';}', ruleIndex);"
+ "}";
/* String insertRule1 = "addCSSRule('html', 'padding: 0px; height: "
+ (webView.getMeasuredHeight() / getResources().getDisplayMetrics().density)
+ "px; -webkit-column-gap: 0px; -webkit-column-width: "
+ webView.getMeasuredWidth() + "px;')";*/
float height=webView.getMeasuredHeight() / getResources().getDisplayMetrics().density;
String insertRule1 = "addCSSRule('html', 'margin:0px; padding:0px; height: "
+ (height)
+ "px; -webkit-column-gap: 0px; -webkit-column-width: "
+ webView.getMeasuredWidth() + "px;')";
webView.loadUrl("javascript:" + varMySheet);
webView.loadUrl("javascript:" + addCSSRule);
webView.loadUrl("javascript:" + insertRule1);
But the webview has a empty space below and scrolling is also not paginated.

adding style="overflow-x: auto; overflow-y: -webkit-paged-x;" to your body can be done with javascript:
String js = "javascript:function initialize() { " +
"var d = document.getElementsByTagName('body')[0];" +
"d.style.overflow = '-webkit-paged-x';" +
"}";
webView.loadUrl(js);
webView.loadUrl("javascript:initialize()");
along with overriding onOverScrolled in your webview like that:
#Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
scrollY = 0; // disables vertical scroll
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}
will result in horizontal scrolling without the pagination.
don't have solution for the pagination yet.

Related

Why does setting objectPosition cause my JavaScript to crash?

Style objectPosition Property gives this example of setting objectPosition:
document.getElementById("myImg").style.objectPosition = "0 10%";
However, when I try to set objectPosition it causes my JavaScript to crash.
In the following code I use CSS to set objectPosition like this:
#img1 {
object-position: 0 0;
width: 635px ;
height: 580px ;
}
Near the bottom of function getImg, my debug code (the “insert” statement) shows it set to “0px 0px”. However, if I proceed this with
imgStyle.objectPosition = "0 0";
The “insert” statement and all following statements are not executed. Here’s my full code with the offending statement commented out:
"use strict";
const numberOfFigures = document.getElementsByTagName('figure').length;
const scale = 3; // scaling up factor
// The function "insert" is used purely for debug purposes
function insert(figNum) {
document.getElementById("para").innerHTML = "OK so far" + figNum;
}
// Create all thumbnails & big images.
for (let i = 0; i < numberOfFigures; i++) {
getImg(i + 1);
}
function getImg(figNum) {
// Create the thumbnails and big images
let startPosn = "0px"; // x-coordinate of object-position for thumbnail
var btnDiv = document.createElement('div');
btnDiv.setAttribute("id", "bigImg" + figNum);
btnDiv.style.backgroundColor = "white";
// Get the figure caption
const figcap = document.getElementById("fig" + figNum).firstElementChild;
btnDiv.innerHTML =
'<button type="button"' +
'class="displayBtn"' +
'onclick="hideBigImg (' +
figNum +
')">Hide large image</button>';
const btnPtr = figcap.appendChild(btnDiv);
/* Append the button to the
figcaption */
var imgDiv = document.createElement('div');
imgDiv.setAttribute("id", "imgDiv" + figNum);
if (figNum === 1) {
/* First image needs height: 100vh or only the top slice is
displayed. Other images may be messed up if this is applied to
them. */
imgDiv.innerHTML = '<' + 'img id="img' + figNum + '" ' +
'class = "sprite-img" ' +
'src="bates-sprite.jpeg" ' +
'style="height: 100vh; ' +
'transform-origin: top left; ' +
'transform: scale(' +
scale + ');">';
} else {
imgDiv.innerHTML = '<' + 'img id="img' + figNum + '" ' +
'class = "sprite-img" ' +
'src="bates-sprite.jpeg" ' +
'style="transform-origin: top left; ' +
'transform: scale(' +
scale + ');">';
}
const imgPtr = btnPtr.appendChild(imgDiv);
/* Append the img to the
button */
/* Make imgDiv high enough to hold the scaled up image & make the
accompanying text visible.
IMPORTANT to do this AFTER creating & appending the. */
// Get the height and width of the image
let img = document.getElementById("img" + figNum);
const imgStyle = getComputedStyle(img);
// Set imgDiv to exactly hold image
imgDiv.style.width = parseInt(imgStyle.width) * scale + "px";
imgDiv.style.height = parseInt(imgStyle.height) * scale + "px";
imgDiv.style.overflow = "hidden"; // Clip off rest of sprite
/*********************** Create thumbnail here *************/
let thumbHTML = '<' + 'div id="thumbDiv' + figNum + '" ' +
'onclick = "showBigImg(' +
figNum + ')" ' +
'style="float: left; ' +
'height: imgStyle.height; ' +
'width: imgStyle.width; ' +
'margin-right: 1.5em; ' +
'background-color: white; ' +
'border: thick solid black;"> ' +
'<' + 'img id="img' + figNum + '" ' +
'class = "sprite-img" ' +
'src="bates-sprite.jpeg" ' +
'style="transform-origin: top left; ' +
'transform: scale(0.5);" ' +
'onclick = "showBigImg(' +
figNum + ')";>' +
'</div>';
figcap.insertAdjacentHTML("afterend", thumbHTML);
/* Append the
thumbnail to the
figcaption */
/* Shrink the div to match the size of the thumbnail, and free up all the
blank space which the full size image would have occupied if it hadn't
been reduced with transform: scale */
let thumbnail = document.getElementById("thumbDiv" + figNum);
thumbnail.style.width = parseInt(imgStyle.width) / 2 + "px";
thumbnail.style.height = parseInt(imgStyle.height) / 2 + "px";
// Set object-position for image in sprite
//imgStyle.objectPosition = "0 0";
insert(imgStyle.objectPosition);
hideBigImg(figNum);
}
function showBigImg(figNum) {
document.getElementById('bigImg' + figNum).style.display = 'block';
document.getElementById('thumbDiv' + figNum).style.display = 'none';
}
function hideBigImg(figNum) {
document.getElementById('bigImg' + figNum).style.display = 'none';
document.getElementById('thumbDiv' + figNum).style.display = 'block';
}
/* Global constants */
:root {
--shrink: 0.30;
/* Size compressed to 30% */
}
figure {
display: block;
width: 96%;
float: left;
border-width: thin;
}
figcaption {
background-color: yellow;
}
.sprite-img {
background-repeat: no-repeat;
object-fit: none;
}
#img1 {
object-position: 0 0;
width: 635px;
height: 580px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="general.css">
</head>
<body>
<figure id="fig1">
<figcaption>Camberley Mail</figcaption>
<p id="para">Text to go with picture.</p>
</figure>
</body>
</html>
The reason why the program 'crashes' or more specifically throws an Exception is because you are trying to modify the properties of a read-only object.
In detail:
const img = document.querySelector("img");
const imgStyle = getComputedStyle(img); // imgStyle is a read-only object
imgStyle.objectPosition = "0 0";
The above code will throw:
Uncaught DOMException: Failed to set the 'object-position' property on 'CSSStyleDeclaration': These styles are computed, and therefore the 'object-position' property is read-only.
As stated in the MDN documentation:
"The object from getComputedStyle is read-only, and should be used to inspect the element's style — including those set by a element or an external stylesheet.
The element.style object should be used to set styles on that element, or inspect styles directly added to it from JavaScript manipulation or the global style attribute."
So, based on the docs, you should use the element.style object for setting the properties:
img.style.objectPosition = "0 0";

Hosted Website loads with errors in <body> that are not in the code

Ahoi,
I am hosting a small debug-website with my "Olimex ESP-32 POE". The goal is to send some internal data via JSON there to not have to use the Serial-Output from the Arduino IDE (The reasons behind that do not matter).
#include "Arduino.h"
#include <WiFiClient.h>
#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
#include <string>
const char* ssid = "SSID";
const char* password = "password";
int looper = 0;
int looperSpeed = 0;
int looperMode = 0;
int looperDestination = 0;
int looperETC = 0;
WebServer webserver(80);
void initWebServer();
void getSettings() {
String response = "{";
response+= "\"speed\": \""+(String) looperSpeed+"\"";
response+= ",\"mode\": \""+(String) looperMode+"\"";
response+= ",\"dest\": \""+(String) looperDestination+"\"";
response+= ",\"etc\": \""+(String) looperETC+"\"";
if (webserver.arg("signalStrength")== "true"){
response+= ",\"signalStrengh\": \""+String(WiFi.RSSI())+"\"";
}
response+="}";
webserver.send(200, "text/json", response);
}
void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += webserver.uri();
message += "\nMethod: ";
message += (webserver.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += webserver.args();
message += "\n";
for (uint8_t i = 0; i < webserver.args(); i++) {
message += " " + webserver.argName(i) + ": " + webserver.arg(i) + "\n";
}
webserver.send(404, "text/plain", message);
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
initWebServer();
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Set not found response
webserver.onNotFound(handleNotFound);
// Start server
webserver.begin();
Serial.println("HTTP server started");
}
void loop() {
webserver.handleClient();
//Some test values are changed here periodically (looperXYZ)
}
}
And the part which creates the website:
std::string online_output = "Test";
const char* serverIndex() {
const char* o = online_output.c_str();
const char* r =
(std::string("") +
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>" +
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>" +
"<input type='file' name='update'>" +
"<input type='submit' value='Update'>" +
"</form>" +
"<div id='prg'>Progress: 0%</div>" +
"<div id='output' style=\"font-family: monospace; border: 1px solid black; width: 350px;min-height:398px;\">" +
"</div>" +
"<script>" +
"var id = 0;" +
"var removeId = 0;" +
"setInterval(function(){" +
/*"var xhReq = new XMLHttpRequest();" +
"xhReq.open('GET', '/JSON', false);" +
"xhReq.send(null);" +
"var jsonObject = JSON.parse(xhReq.responseText);" +*/
"var data = {};" +
"$.ajax({" +
"type: 'GET'," +
"url: '/JSON'," +
"data: data," +
"async: true," +
"beforeSend: function (xhr) {" +
"if (xhr && xhr.overrideMimeType) {" +
"xhr.overrideMimeType('application/json;charset=utf-8');" +
"}" +
"}," +
"dataType: 'json'," +
"success: function (data) {" +
"document.getElementById('output').innerHTML = \"<p id=\" + id + \" style='margin:0;padding:0px;'>\" + \"Mode: \" + fill(data.mode,2) + \" | Speed: \" + fill(data.speed,4) + \" | Dest: \" + fill(data.dest,4) + \" | ETC: \" + fill(data.etc,5) + \"</p>\" + document.getElementById('output').innerHTML;" +
// "if (document.getElementById('output').offsetHeight > 400) document.getElementById('output').innerHTML = \"<p style='margin:0;padding:0px;'>\" + data.name + \"</p>\";" +
"if (document.getElementById('output').offsetHeight > 400) { document.getElementById(removeId).remove(); removeId++;}" +
"id++;" +
"console.log(data);" +
"}" +
"});" +
"}, 50);" +
"function fill(n,m) { " +
"var pre=\"\";" +
"var dec=10;" +
"for(var i=1;i<m;i++) { if(n<dec) { pre+=\".\"; } dec*=10; }" +
"pre = pre + n;" +
"return pre; }" +
"$('form').submit(function(e){" +
"e.preventDefault();" +
"var form = $('#upload_form')[0];" +
"var data = new FormData(form);" +
" $.ajax({" +
"url: '/update'," +
"type: 'POST'," +
"data: data," +
"contentType: false," +
"processData:false," +
"xhr: function() {" +
"var xhr = new window.XMLHttpRequest();" +
"xhr.upload.addEventListener('progress', function(evt) {" +
"if (evt.lengthComputable) {" +
"var per = evt.loaded / evt.total;" +
"$('#prg').html('progress: ' + Math.round(per*100) + '%');" +
"}" +
"}, false);" +
"return xhr;" +
"}," +
"success:function(d, s) {" +
"console.log('success!')" +
"}," +
"error: function (a, b, c) {" +
"}" +
"});" +
"});" +
"</script>").c_str();
return r;
}
const char* host = "esp32";
void initWebServer() {
if (!MDNS.begin(host)) { //http://esp32.local
Serial.println("Error setting up MDNS responder!");
while (1) {
delay(1000);
}
}
Serial.println("mDNS responder started");
/*return index page which is stored in serverIndex */
webserver.on("/", HTTP_GET, []() {
webserver.sendHeader("Connection", "close");
webserver.send(200, "text/html", serverIndex());
});
webserver.on("/JSON", HTTP_GET, []() {
getSettings();
});
/*handling uploading firmware file */
webserver.on("/update", HTTP_POST, []() {
webserver.sendHeader("Connection", "close");
webserver.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
ESP.restart();
}, []() {
HTTPUpload& upload = webserver.upload();
if (upload.status == UPLOAD_FILE_START) {
Serial.printf("Update: %s\n", upload.filename.c_str());
if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
/* flashing firmware to ESP*/
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { //true to set the size to the current progress
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(Serial);
}
}
});
webserver.begin();
}
This is testing code, so there might be left-overs from previous tests - FYI.
When loading the website (currently I am using Chrome) it sometimes works, sometimes nothing is loaded (THIS SITE IS NOT WORKING, and then an empty page) and sometimes I get a result like: xV­ºùÿý?øÿý?;"> which is the only output on the screen.
In detail it shows the following:
<html><head></head><body>xV­ºùÿý?øÿý?;"><script>var id = 0; [...the rest of the <script> part is loaded properly...]
I just noticed that in front of these strange characters are 364 centered points (·) but I cannot actually copy them, no editor is displaying them besides the Chrome->Inspect->"Sources"-Tab.
So basically the body is broken and these characters appear, they also do not change currently.
Can someone point me into a direction to solve this on my own, so that the website is always correctly loaded or knows what the error is?
The error seems to be on the following line:
const char* r = (std::string("") + “...”).c_str();
You are creating and std::string which allocates the raw c string on the heap. You then get the c representation of the string with .c_str(). The issue is that the string is freed since you have not assigned the string to a variable of type std::string. As a result, you were accessing memory that was not yours. When its memory wasn’t yet reused, it worked, but want is was reused by another program, it failed since you got basically random bytes from memory.
You can solve the issue by adding the following:
auto my_str = std::string("") + “...”;
Because you don’t need the raw pointer.
For the server index function, it should look like:
std::string serverIndex() {
For your init web server function:
webserver.on("/", HTTP_GET, []() {
webserver.sendHeader("Connection", "close");
auto r = serverIndex();
webserver.send(200, "text/html", r.c_str());
});
Disclaimer: this code wasn’t tested as it was only written in the app.

How to successfully execute a callback on an async method

I am currently trying to return a value from a function that contains an async function and I'm stuck.
I am currently working with SharePoint 2013 JSOM to extract the email address from a Person column. I have found a nice function that does this and I elected to pass the userID into the function.
The function itself contains console.log and outputs the expected result, however, I need those results up where I called the function from in the first place so I found that I need to use a callback. I cannot extract a variable from the calling method.
var t = oListItem.get_item('ElementContactFullName').get_lookupId();
var q = getEmail(t, function(returnedValue){});
function getEmail(userId, callback) {
var x = [];
var context = new SP.ClientContext();
var web = context.get_web();
var user = web.get_siteUsers().getById(userId);
context.load(user);
context.executeQueryAsync(function() {
//console.log(user.get_email());
var y = user.get_email();
x.push(y);
}
, function() {
console.log("error");
});
callback(x);
}
What I want is q to equal the email address so I can use it elsewhere in the calling function.
What I get is "Undefined" no matter what I try.
I can place console.log in function(returnedValue){}) but that still doesn't let me get at the variable. Not done enough JScript to understand the very complex dicussions on the proposed duplicate.
function getEUEmail(userId, JT, flag, callback) {
var x = [];
var contextEU = new SP.ClientContext();
var web = contextEU.get_web();
var user = web.get_siteUsers().getById(userId);
contextEU.load(user);
contextEU.executeQueryAsync(function() {
//console.log(user.get_email());
var y = "<div class='tablewrapper'>" +
"<div class='table'>" +
"<div class='row'>" +
"<div class='rowspanned cell'>" +
' <img class="contacts" src="' + _spPageContextInfo.webServerRelativeUrl + '/_layouts/15/userphoto.aspx?size=M&accountname='+ user.get_email() +'"/>' +
"</div>" +
"<div class='cell'>" +
user.get_title() +
"</div>" +
"</div>" +
"<div class='row'>" +
"<div class='empty cell'></div>" +
"<div class='cell'>" +
JT +
"<div class='cell'>" +
' <img class="flag" src="' + window.location.protocol + "//" + window.location.host + '/SiteAssets/Images/'+ flag +'.png"/>' +
//http://staging.intranet.ent.sys.element.com/SiteAssets/Images/EU.png
"</div>" +
"</div>" +
"</div>" +
"</div>" +
"</div>"
x.push(y);
callback(x);
}
Then to use it
getEUEmail(t,u, v, function(returnedValueEU) {
//console.log(returnedValue[0])
$("#divListItemsEU").append(
"<style type='text/css'> .tablewrapper { position: relative; box-sizing: border-box; height:72px} .table {display: table; } .row { display: table-row; padding: 1px; } .cell { display: table-cell; border: none solid red; padding: 3px;} .cell.empty { border: none; width: 75px; } .cell.rowspanned { position: absolute; top: 0; bottom: 0; width: 75px; display: block; margin: 1px;} .contacts{ width: 72px; height: 72px;} .flag { width: 30px; height: 20px; }</style> " +
"" + returnedValueEU[0] +
'<br />');
});
$("#divListItemsEU").html(listEUItemInfoEU);
}
I ended up passing all the values into the getEmail function, building the HTML then worked out how to leverage the callback with some help. Probably not correct, efficient or elegant but it works. Thanks

Print wide html table using HTML/css/javascript (with responsive design)

I have tried the code from the article to print my wide table in a single page, that worked great only for Google Chrome. Couldn't get it working on IE as mentioned in the article and comments. Below is my sample code with IE I tried almost for hours and couldn't get the issue.
function printGrid() {
var gridElement = $('#grid'),
printableContent = '',
win = window.open('', '', 'scrollbars=1,resizable=1,width=1150,height=650,left=0,top=0'),
doc = win.document.open(),
dataSource = $("#grid").data("kendoGrid").dataSource;
var htmlStart =
'<!DOCTYPE html>' +
'<html>' +
'<head>' +
'<meta charset="utf-8" />' +
'<link href="../Content/kendo/2014.1.318/kendo.common.min.css" rel="stylesheet" />' +
'<style>' +
'html { font: 11pt sans-serif; }' +
'.k-grid { border-top-width: 0;}' +
'.k-grid, .k-grid-content { height: auto !important;}' +
'.k-grid-content { overflow: visible !important; }' +
'div.k-grid table { table-layout: fixed; border:1px solid #000000; width: 100% !important; }' +
'.k-grid .k-grid-header th { border-top: 1px solid; border:1px solid #000000;}' +
'.k-grid td {border:1px solid #000000;} ' +
'.k-grid-toolbar, .k-grid-pager > .k-link { display: none; }' +
'#media only screen and (max-width: 760px),(min-device-width: 768px) and (max-device-width: 1024px) {table, thead, tbody, th, td, tr { display:block;width:100%;-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;float:left;clear:left;}' +
'thead tr {position: absolute;top: -9999px;left: -9999px;}' +
'tr {border: 1px solid #ccc;}' +
'td {border: none;border-bottom: 1px solid #eee;position: relative;padding-left: 50%;height:10px;}' +
'td:before {position: absolute;top: 6px;left: 6px;width: 45%;padding-right: 10px;white-space: nowrap;}' +
'td:nth-of-type(1):before {content: "Column1";}' +
'td:nth-of-type(1):before {content: "Column2";}' +
'td:nth-of-type(1):before {content: "Column3";}' +
'td:nth-of-type(1):before {content: "Column4";}' +
'td:nth-of-type(1):before {content: "Column5";}' +
'td:nth-of-type(1):before {content: "Column6";}' +
'td:nth-of-type(1):before {content: "Column7";}' +
'td:nth-of-type(1):before {content: "Column8";}' +
'td:nth-of-type(1):before {content: "Column9";}' +
'td:nth-of-type(1):before {content: "Column10";}' +
'td:nth-of-type(1):before {content: "Column11";}' +
'td:nth-of-type(1):before {content: "Column12";}' +
'td:nth-of-type(1):before {content: "Column13";}' +
'td:nth-of-type(1):before {content: "Column14";}' +
'td:nth-of-type(1):before {content: "Column15";}' +
'}' +
'#media only screen and (min-device-width : 320px) and (max-device-width : 480px) {' +
'body {padding: 0;margin: 0;width: 320px;}' +
'}' +
'#media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {' +
'body {width: 495px;}' +
'}' +
'</style>' +
'</head>' +
'<body>';
var htmlEnd =
'</body>' +
'</html>';
var gridHeader = gridElement.children('.k-grid-header');
if (gridHeader[0]) {
var thead = gridHeader.find('thead').clone().addClass('k-grid-header');
printableContent = gridElement
.clone()
.children('.k-grid-header').remove()
.end()
.children('.k-grid-content')
.find('table')
.first()
.children('tbody').before(thead)
.end()
.end()
.end()
.end()[0].outerHTML;
} else {
printableContent = gridElement.clone()[0].outerHTML;
}
doc.write(htmlStart + printableContent + htmlEnd);
doc.close();
var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/ ') >= 0;
var isChrome = !!window.chrome && !isOpera;
if (!isChrome)
win.print();
}
Tried a different solution to print as shown in the demo here http://salman-w.blogspot.com/2013/04/printing-wide-html-tables.html. It worked !
Note: I am using a Kendo grid, with that the following solution perfectly works ! This has some additional filter display stuff.etc. Please remove the same if not required. I am sure it can be optimized, but this is the quick code that works.
function printGrid() {
var gridElement = $('#grid'),
firstprintableContent = '',
lastprintableContent = '',
win = window.open('', '', 'scrollbars=1,resizable=1,width=1150,height=650,left=0,top=0'),
doc = win.document.open(), dataSource = $("#grid").data("kendoGrid").dataSource;
//get the filter values
var filterHtml = "", operator = "", fieldName = "", localCounter = 0;;
var fieldArray = new Array("Field1", "Field2", "Field3", "Field4", "Field5", "Field6", "Field7", "Field8", "Field9", "Field10", "Field11", "Field12", "Field13", "Field14", "Field15");
var nameArray = new Array("Column1", "Column2", "Column3", "Column4", "Column5", "Column6", "Column7", "Column8", "Column9", "Column10", "Column11", "Column12", "Column13", "Column14", "Column15");
//Logic for getting the filters and displaying them on the print page
var currentFilter = dataSource.filter();
if (currentFilter) {
currentFilter.filters.forEach(function (filter, index) {
localCounter = localCounter + 1;
if (filter.operator == "neq")
operator = "not equals to";
if (filter.operator == "eq")
operator = "equals to";
if (filter.operator == "startswith")
operator = "starting with";
for (var iCounter = 0; iCounter < 15; iCounter++) {
if (filter.field == fieldArray[iCounter]) {
fieldName = nameArray[iCounter];
break;
}
}
if (localCounter > 1)
filterHtml += "<p style='padding-left:9.1em'>" + fieldName + " " + operator + " " + "'" + filter.value + "'" + "</p>";
else
filterHtml += fieldName + " " + operator + " " + "'" + filter.value + "'" + "<br/> ";
});
}
else
filterHtml = "None";
var htmlStart =
'<!DOCTYPE html>' +
'<html>' +
'<head>' +
'<meta charset="utf-8" />' +
'<style>' +
'html { font: 11pt sans-serif; }' +
'table { width: 100%; border-collapse: collapse;table-layout:fixed;}' +
'tr:nth-of-type(odd) { background: #eee;}' +
'th { background: #DDDDDD;white-space: nowrap; color: white; font-weight: bold; pointer-events:none;cursor:default;text-decoration:none;}' +
'td, th { padding: 6px; border: 1px solid #ccc; text-align: left;outline:1px solid #ccc}' +
'tr {border: 1px solid #ccc;}' +
'</style>' +
'</head>' +
'<body>' +
'<div class="site-header__logo col-xs-4">' +
'<img src="/Content/images/mark-red-48x52.png" alt=" Products">' +
'<img src="/Content/images/logo-299x63.png" alt="Products">' +
'</div>' + '<br/><br/>' +
'Applied Data Filters' + ':' + " " + filterHtml + '<br/>' +
'<center><strong><h2>' + 'My grid' + '</h2></strong> </center>' + '<br/>';
var htmlEnd = '</body>' + '</html>';
//get the total columns, hidden columns and shown columns
var totalColumns = $("#grid").data("kendoGrid").columns.length;
var hiddencolumnsarray = [];
var showncolumnsarray = [];
if (totalColumns > 0) {
for (i = 0; i < totalColumns; i++) {
if ($("#grid").data("kendoGrid").columns[i].hidden) {
hiddencolumnsarray.push(i);
}
else {
showncolumnsarray.push(i);
}
}
}
if (showncolumnsarray.length > 8) {
iMoreColumns = 1;
//show only the first eight columns if user is viewing more than 8 columns
printfirsteightcolumns();
firstprintableContent = getPrintableContent(gridElement);
printlastsevencolumns();
lastprintableContent = getPrintableContent(gridElement);
} else {
iMoreColumns = 0;
firstprintableContent = getPrintableContent(gridElement);
}
//set the columns visibility back to normal once the print HTML is captured with the respective number of columns
printshowhidecolumns();
if (showncolumnsarray.length > 8)
doc.write(htmlStart + firstprintableContent + "<br/>" + "<div style='page-break-before:always;'>" + lastprintableContent + "</div>" + htmlEnd);
else
doc.write(htmlStart + firstprintableContent + htmlEnd);
var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/ ') >= 0;
var isChrome = !!window.chrome && !isOpera;
if (!isChrome)
win.print();
}
function getPrintableContent(gridElement) {
var gridHeader = gridElement.children('.k-grid-header');
if (gridHeader[0]) {
var thead = gridHeader.find('thead').clone().addClass('k-grid-header');
printableContent = gridElement.css('height', '')
.clone()
.children('.k-grid-header').remove()
.end()
.children('.k-grid-content').css('height', '')
.find('table')
.first()
.children('tbody').before(thead)
.end()
.end()
.end()
.end()[0].outerHTML;
} else {
printableContent = gridElement.clone()[0].outerHTML;
}
return printableContent;
}
function printfirsteightcolumns() {
var counter = 0;
var columns = $("#grid").data("kedoGrid").columns;
jQuery.each(columns, function (index) {
if (counter > 8) {
$("#grid").data("kendoGrid").hideColumn(parseInt(counter));
}
counter = counter + 1;
});
}
function printlastsevencolumns() {
var counter = 0;
var columns = $("#grid").data("kedoGrid").columns;
jQuery.each(columns, function (index) {
if (counter > 8) {
$("#grid").data("kendoGrid").showColumn(parseInt(counter));
}
else {
$("#grid").data("kendoGrid").hideColumn(parseInt(counter));
}
counter = counter + 1;
});
}
Cheers,
Srini

Drag/drop & delete dynamic text on HTML canvas

I've found a number of tutorials online for dragging and dropping images and shapes within an HTML canvas. But they all seem to be aimed at moving objects that are generated within the canvas when the page loads. I'm building an app that lets the user click a button on a virtual keyboard, then click on the canvas to have the corresponding number or character appear. This is my code:
<script type="text/javascript">
var mathCanvas = document.getElementById("matharea");
var ctx = mathCanvas.getContext("2d");
ctx.font="20px Arial";
var placementCallback = function(){}
mathCanvas.onselectstart = function(){return false;}
function insertOne(){placementCallback = function(x, y){ctx.fillText('1', x-6,y+6);}};
function insertTwo(){placementCallback = function(x, y){ctx.fillText('2', x-6,y+6);}};
function insertThree(){placementCallback = function(x, y){ctx.fillText('3', x-6,y+6);}};
mathCanvas.onclick = function(event){
placementCallback(event.offsetX, event.offsetY);
}
</script>
I cut out some of the insert functions to keep this shorter (the buttons in my HTML have an onclick attribute that calls these functions). I need to be able to select the characters that are placed on the screen and implement drag/drop and delete functionality, but I can't think of a way to do this for text that gets placed on the screen after the page loads (I'm fairly new to Javascript). How would I do this? I'm not expecting anyone to give me the code to do this, but if I could get a push in the right direction, that'd be great.
The problem is that canvas is immediate-mode. Whatever you tell it to put on the canvas it will put on the canvas, instantly. It will not give you the ability to modify that value in any way, shape or form.
Think of it like the difference between MS Paint (or your OS' equivalent) and Photoshop.
In PS, you can have layers which can be moved around and edited, and when you decide your image is done, you save it and it flattens all of that data.
When you make an image in MS Paint, as soon as you click or type, that thing that you put there is there, and it's not moving/being edited unless you erase it, draw over it, or draw a rectangle around a section and move that whole rectangle (including the pixels around what you're trying to edit).
Just calling fillText will paint the words on, that instant, but will not remember what it drew, where it is, what it is, how the text is different from the surrounding pixels, et cetera.
So your generalized solution is that you need to turn your text into objects, and then draw an aspect (the text-content) of those objects to the screen.
If your text changes, you can make a change in the object, and redraw it (because your object will have its X and Y coordinates stored, and will have its width value stored, using the context.measureText(textObj.text).width method/property), and when you click on the canvas, you can check the coordinates of the click, and if those coordinates intersect with your text-object's stored coordinates, then you can modify its position on the screen.
In that regard, you should look into those examples which deal with dragging objects on the canvas.
The button click should be treated as a way to CREATE one of those objects.
I know this is a lot of code ... But I didn't want to go through it .. It's PART of something I built a long time ago ... Just copy and paste into a html file ... I hope it helps with what you need:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/jquery-ui.min.js" type="text/javascript"></script>
<script src="http://jquery-ui.googlecode.com/svn/tags/latest/external/jquery.bgiframe-2.1.2.js" type="text/javascript"></script>
<script src="http://jquery-ui.googlecode.com/svn/tags/latest/ui/minified/i18n/jquery-ui-i18n.min.js" type="text/javascript"></script>
<script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script>
<script>
;(function($) {
$.fn.insertAtCaret = function (myValue) {
return this.each(function() {
//IE support
if (document.selection) {
this.focus();
sel = document.selection.createRange();
sel.text = myValue;
this.focus();
} else if (this.selectionStart || this.selectionStart == '0') {
//MOZILLA / NETSCAPE support
var startPos = this.selectionStart;
var endPos = this.selectionEnd;
var scrollTop = this.scrollTop;
this.value = this.value.substring(0, startPos)+ myValue+ this.value.substring(endPos,this.value.length);
this.focus();
this.selectionStart = startPos + myValue.length;
this.selectionEnd = startPos + myValue.length;
this.scrollTop = scrollTop;
} else {
this.value += myValue;
this.focus();
}
});
};
})(jQuery);
$(function go_prev() {
//When you click on a link with class of poplight and the href starts with a #
$('a.poplight[href^=#]').click(function() {
var popID = $(this).attr('rel'); //Get Popup Name
var popURL = $(this).attr('href'); //Get Popup href to define size
//Pull Query & Variables from href URL
var query= popURL.split('?');
var dim= query[1].split('&');
var popWidth = dim[0].split('=')[1]; //Gets the first query string value
//Fade in the Popup and add close button
$('#' + popID).fadeIn().css({ 'width': Number( popWidth ) }).prepend('<img src="close_pop.png" class="btn_close" title="Close Window" alt="Close" />');
//Define margin for center alignment (vertical horizontal) - we add 80px to the height/width to accomodate for the padding and border width defined in the css
var popMargTop = ($('#' + popID).height() + 90) / 2;
var popMargLeft = ($('#' + popID).width() + 80) / 2;
//Apply Margin to Popup
$('#' + popID).css({
'top' : 10,
'margin-left' : -popMargLeft
});
//Fade in Background
$('body').append('<div id="fade"></div>'); //Add the fade layer to bottom of the body tag.
$('#fade').css({'filter' : 'alpha(opacity=80)'}).fadeIn(); //Fade in the fade layer - .css({'filter' : 'alpha(opacity=80)'}) is used to fix the IE Bug on fading transparencies
return false;
});
//Close Popups and Fade Layer
$('a.close, #fade').live('click', function() { //When clicking on the close or fade layer...
$('#fade , .popup_block').fadeOut(function() {
$('#fade, a.close').remove(); //fade them both out
});
return false;
});
});
</script>
<script>
var NumIms = 0;
var NumTxts = 0;
//IMAGE VARIABLES
var ImIds=[];
var ImNm=[];
var ImWdth=[];
var ImHght=[];
//TEXT VARIABLES
var TxtIds=[];
var Txt=[];
var TxtFnt=[];
var TxtCol=[];
var TxtSz=[];
var MyWidth;
var MyHeight;
var img;
function MoveOver(id,Rid) {
var img = new Image();
img.src = Rid;
MyWidth = img.width;
MyHeight = img.height;
$("#UpIm" + id).append("W=" + MyWidth + " H=" + MyHeight);
$("#containment-wrapper").append('<div id="AdIm' + id + '" class="draggable ui-widget-content" style="width:' + MyWidth + 'px; height:' + MyHeight + 'px; background-image: url(' + Rid + '); position:absolute; left:18px; top:18px;"></div>');
ImIds[id]="AdIm" + id;
ImNm[id]=Rid;
ImWdth[id]=MyWidth;
ImHght[id]=MyHeight;
$( "#AdIm" + id ).draggable();
var f = document.getElementById('UpIm' +id);
var Olddiv = document.getElementById('ul' + id);
f.removeChild(Olddiv);
}
</script>
<script>
function removeIm(id) {
var f = document.getElementById('files');
var Folddiv = document.getElementById('UpIm' + id);
f.removeChild(Folddiv);
var d = document.getElementById('containment-wrapper');
var Dolddiv = document.getElementById('AdIm' + id);
d.removeChild(Dolddiv);
ImIds.splice(id,1,"deleted");
}
</script>
<script type="text/javascript" >
var iid = -1;
var pic_real_width, pic_real_height, img;
function removeFormIm(Rid,id) {
var f = document.getElementById('files');
var Folddiv = document.getElementById('UpIm' + id);
f.removeChild(Folddiv);
var d = document.getElementById('containment-wrapper');
var Dolddiv = document.getElementById('AdIm' + id);
d.removeChild(Folddiv);
}
</script>
<style>
#containment-wrapper { width: 845px; height:150px; border:2px solid #ccc; }
#fade { /*--Transparent background layer--*/
display: none; /*--hidden by default--*/
background: #000;
position: fixed; left: 0; top: 0;
width: 100%; height: 100%;
opacity: .80;
z-index: 9999;
}
.popup_block{
display: none; /*--hidden by default--*/
background: #fff;
padding: 20px;
border: 20px solid #ddd;
float: left;
font-size: 1.2em;
position: fixed;
top: 50%; left: 50%;
z-index: 99999;
/*--CSS3 Box Shadows--*/
-webkit-box-shadow: 0px 0px 20px #000;
-moz-box-shadow: 0px 0px 20px #000;
box-shadow: 0px 0px 20px #000;
/*--CSS3 Rounded Corners--*/
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
.t_t{
display: none; /*--hidden by default--*/
background: #fff;
padding: 20px;
border: 20px solid #ddd;
float: left;
font-size: 1.2em;
position: fixed;
top: 50%; left: 50%;
z-index: 99999;
/*--CSS3 Box Shadows--*/
-webkit-box-shadow: 0px 0px 20px #000;
-moz-box-shadow: 0px 0px 20px #000;
box-shadow: 0px 0px 20px #000;
/*--CSS3 Rounded Corners--*/
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
img.btn_close {
float: right;
margin: -55px -55px 0 0;
}
/*--Making IE6 Understand Fixed Positioning--*/
*html #fade {
position: absolute;
}
*html .popup_block {
position: absolute;
}
</style>
<script>
function changeTxt(id){
var my_txt;
my_txt = document.getElementById('TxtIn' + id).value;
document.getElementById('AdText' + id).innerHTML = my_txt;
Txt[id] = my_txt;
}
</script>
<script>
function makebold(id){
$('#TxtIn' + id).insertAtCaret('<b></b>');
changeTxt(id);
}
function makeitalic(id){
$('#TxtIn' + id).insertAtCaret('<i></i>');
changeTxt(id);
}
function makecenter(id){
var my_txt;
my_txt = document.getElementById('TxtIn' + id).value;
$("textarea#TxtIn" + id).val('<center>' + my_txt + '</center>');
changeTxt(id)
}
function makebr(id){
$('#TxtIn' + id).insertAtCaret('<br>');
changeTxt(id);
}
function makelink(id){
get_color = document.getElementById('fcolor' + id).value;
$('#TxtIn' + id).insertAtCaret('');
changeTxt(id);
}
function makeh2(id){
$('#TxtIn' + id).insertAtCaret('<H2></H2>');
changeTxt(id);
}
function makeh3(id){
$('#TxtIn' + id).insertAtCaret('<H3></H3>');
changeTxt(id);
}
</script>
<script>
function callFontType(id){
var type;
type = document.getElementById('ftype' + id).value;
document.getElementById('AdText' + id).style.fontFamily=type;
TxtFnt[id] = type;
}
</script>
<script>
function CxColor(id){
var Clor;
Clor = document.getElementById('fcolor' + id).value;
Clor = '#' + Clor;
document.getElementById('AdText' + id).style.color=Clor;
TxtCol[id] = Clor;
}
</script>
<script>
function changeFSize(id){
var my_size;
my_size = document.getElementById('SizeIn' + id).value;
my_size = my_size + 'px';
document.getElementById('AdText' + id).style.fontSize = my_size;
TxtSz[id] = my_size;
}
</script>
<script>
var id = -1;
function addFormField() {
id = id + 1;
$("#divTxt").append("<span id='row" + id + "'><small>Add: to textbox:</small><input value=\"b\" onclick=\"makebold(" + id + ")\" title=\"bold: <b>text</b>\" type=\"button\"><input value=\"i\" onclick=\"makeitalic(" + id + ")\" title=\"italic: <i>text</i>\" type=\"button\"><input value=\"center\" onclick=\"makecenter(" + id + ")\" title=\"center: <center>text</center>\" type=\"button\"><input value=\"BR\" onclick=\"makebr(" + id + ")\" title=\"BR: <br>\" type=\"button\"><input value=\"link\" onclick=\"makelink(" + id + ")\" title=\"link: <a href= >URL</a>\" type=\"button\"><input value=\"H2\" onclick=\"makeh2(" + id + ")\" title=\"H2: <H2>text</H2>\" type=\"button\"><input value=\"H3\" onclick=\"makeh3(" + id + ")\" title=\"H3: <H3>text</H3>\" type=\"button\"><br><table><tr><td><a onClick='removeFormField(\"#row" + id + "\",\"" + id + "\"); return false;'>REMOVE</a></td><td> <textarea cols=50 rows=5 name='txt[]' id='TxtIn" + id + "' onKeyUp=\"changeTxt(" + id + ");\">Text " + id + "</textarea></td><td>Font:<select onChange=\"callFontType(" + id + ");\" id=\"ftype" + id + "\"><option value=\"Arial, Helvetica, sans-serif\">Arial</option><option value=\"Impact, Charcoal, sans-serif\">Impact</option><option value=\"Palatino Linotype, Book Antiqua, Palatino, serif\">Palatino</option><option value=\"Tahoma, Geneva, sans-serif\">Tahoma</option><option value=\"Century Gothic, sans-serif\">Century Gothic</option><option value=\"Lucida Sans Unicode, Lucida Grande, sans-serif\">Lucida Grande</option><option value=\"Arial Black, Gadget, sans-serif\">Arial Black</option><option value=\"Times New Roman, Times, serif\">Times New Roman</option><option value=\"Arial Narrow, sans-serif\">Arial Narrow</option><option value=\"Verdana, Geneva, sans-serif\">Verdana</option><option value=\"Copperplate, Copperplate Gothic Light, sans-serif\">Copperplate</option><option value=\"Lucida Console, Monaco, monospace\">Lucida Console</option><option value=\"Gill Sans, Gill Sans MT, sans-serif\">Gill Sans</option><option value=\"Trebuchet MS, Helvetica, sans-serif\">Trebuchet</option><option value=\"Courier New, Courier, monospace\">Courier New</option><option value=\"Georgia, Serif\">Georgia</option></select><br>Color: <input id=\"fcolor" + id + "\" class=\"color\" value=\"000000\"><img src=\"go.png\" style=\"vertical-align:middle;\" onClick='CxColor(" + id + ");'><br>Size: <input type='text' size='4' value=\"12\" name='txt[]' id='SizeIn" + id + "' onKeyUp=\"changeFSize(" + id + ");\"></td></tr></table><br><hr style=\"width:800px; float:left;\"><br></span>");
$("#containment-wrapper").append('<span id="AdText' + id + '" class="draggable ui-widget-content" style="position:absolute; left:18px; top:18px; font-size:16px; font-family:Arial, Helvetica, sans-serif;">Text ' + id + '</span>');
$( "#AdText" + id ).draggable();//{ containment: "#containment-wrapper", scroll: true }
$('#fcolor' + id).load(jscolor.init());
TxtIds[id] = "AdText" + id;
Txt[id] = "Ad Text";
TxtFnt[id] = "Arial";
TxtCol[id] = "#000000";
TxtSz[id] = "16";
$('#row' + id).highlightFade({
speed:1000
});
document.getElementById("id").value = id;
}
function removeFormField(Rid,id) {
$(Rid).remove();
var d = document.getElementById('containment-wrapper');
var olddiv = document.getElementById('AdText' + id);
d.removeChild(olddiv);
TxtIds.splice(id,1,"deleted");
}
function GetURL(id) {
var gurl;
var Ims = "";
var len=ImIds.length;
NumIms = 0;
NumTxts = 0;
//############ Start Get Images for URL ##############
for(var i=0; i<len; i++) {
NumIms++;
var value = ImIds[i];
Ims += '&ImName' + i + '=' + value;
if (value != "deleted"){
value = ImNm[i];
Ims += '&ImNm' + i + '=' + value;
value = ImWdth[i];
Ims += '&ImWidth' + i + '=' + value;
value = ImHght[i];
Ims += '&ImHeight' + i + '=' + value;
value = $('#AdIm' + i).position().left - $('#AdIm' + i).closest('#containment-wrapper').position().left;
Ims += '&ImLt' + i + '=' + value;
value = $('#AdIm' + i).position().top - $('#AdIm' + i).closest('#containment-wrapper').position().top;
Ims += '&ImTop' + i + '=' + value;
}
}
//########### End Get Images For URL #####################
len=TxtIds.length;
//############ Start Get Texts for URL ##############
for(var i=0; i<len; i++) {
NumTxts++;
var value = TxtIds[i];
Ims += '&TxtName' + i + '=' + escape(value);
if (value != "deleted"){
value = Txt[i];
Ims += '&Txt' + i + '=' + escape(value);
value = TxtFnt[i];
Ims += '&TxtFnt' + i + '=' + escape(value);
value = TxtCol[i];
value = value.substring(1);
Ims += '&TxtCol' + i + '=' + escape(value);
value = TxtSz[i];
Ims += '&TxtSz' + i + '=' + escape(value);
value = $('#AdText' + i).position().left - $('#AdText' + i).closest('#containment-wrapper').position().left;
Ims += '&TxtLt' + i + '=' + value;
value = $('#AdText' + i).position().top - $('#AdText' + i).closest('#containment-wrapper').position().top;
Ims += '&TxtTop' + i + '=' + value;
}
}
//########### End Get Texts For URL #####################
gurl = "ad.php?AdType=hero&ImNum=" + NumIms + "&TxtNum=" + NumTxts;
gurl = gurl + Ims;
//alert(gurl);gurl = escape( gurl );
$("#genurl" + id).html('<textarea id="fe_text" cols=50 rows=5 name="ad_url">' + gurl + '</textarea><br><br><table><tr><td><font style="font-family:Arial, Helvetica, sans-serif; font-size:16px; color:#009999">Preview Gernerated Ad:</font></td><td><img src="view.png"></td></tr></table><br>');
}
</script>
<script type="text/javascript">
$(document).ready(function(){
$("#myform1").validate({
debug: false,
submitHandler: function(form) {
// do other stuff for a valid form
$.post('process.php', $("#myform1").serialize(), function(data) {
$('#results').fadeIn('fast');
var mySplitResult = data.split("|||");
if(mySplitResult[1] !== "fail" && mySplitResult[1] !== "disable"){
$('#upd1').html('<textarea id="fe_text" cols=50 rows=5 readonly="readonly">' + mySplitResult[1] + '</textarea><br />');
}
$('#results').html(mySplitResult[0]);
$('#prev1').html(mySplitResult[1]);
setTimeout(function() {
$('#results').fadeOut('slow');
}, 2500);
});
}
});
});
</script>
<script type="text/javascript" src="jscolor.js"></script>
</head>
<body>
<div id="containment-wrapper">
<!--<span id="AdText0" class="draggable ui-widget-content">For Testing ... </span> -->
</div>
<div style="margin-left:50px;">
<center><p style="font-family:Arial, Helvetica, sans-serif; font-size:24px; color:#FF0099">Text Field Input</p>
<p>Add Text Field</p></center>
<form action="#" method="get" id="form1" style="font-family:Arial, Helvetica, sans-serif; font-size:16px;">
<input type="hidden" id="id" value="1">
<div id="divTxt"></div>
</form>
</div>
<!-- End Hidden Divs -->
</body>
</html>

Categories