Web browsers are good as thin clients for web applications.
But if the user has to enter some code (where tabs and formatting are important) in an edit box, inside a web browser, he navigates through the webpage controls every time he hits the "tab" key, instead of printing the "tab" character.
Are there any free web controls or is there any code to get the opposite behavior?
Google Docs does this perfectly.
Thanks.
Yahoo UI library has a rich text editor that handles tab characters properly.
EDIT: I suspect (because I haven't looked) that both the YUI editor and Google's editor accomplish this by adding a onKeyPress handler to the text container. When they detect a tab character they append a tab to the container and return false to cancel the normal tab action.
You can filter the keyDown event and catch the tab key:
<html>
<body>
<script type="text/javascript">
function keyFilter(e, field) {
var key = window.event ? e.keyCode : e.which;
if (key == 9) {
field.value += "\t";
return false;
}
return true;
}
</script>
<form>
<textarea onkeydown="return keyFilter(event, this);"></textarea>
</form>
</html>
EDIT: Note that it's of course more complicated than this. One needs to keep track on where in the text the tab key is pressed and insert the character accordingly.
Related
We are replacing the forms for our lists with forms built with SPFx. Building and deploying the form is no issue. The problem is redirecting the form controls to this form (when a user opens an item or clicks new, etc...). Is there a recommended method of accomplishing this? I have been successful using two methods but they both seem volatile and hacky.
The first being replacing the entire form code using SharePoint designer. For instance, the new form code would be
<%# Page language="C#" %>
<html lang="en">
<head>
<script type="text/javascript">
const list = window.location.href;
const site = list.substring(0,list.toLowerCase().indexOf('/lists/'));
window.location.replace(site + "/SitePages/MyListForm.aspx");
</script>
</head>
<body>
</body>
</html>
This works sometimes... Upon saving, the form code seems to regenerate the form code but the redirect still works. However, if I open and save the code again, everything breaks and the list action goes back to default (clicking new would now show the 'New Item' call out instead of directing to the form).
The other method is opening the new/edit/display form in the browser, with ?toolpaneview=2 which allows me to add a script web part to the page (although it doesnt like to save) and add the script redirect in.
<script type="text/javascript">
const list = window.location.href;
const site = list.substring(0,list.toLowerCase().indexOf('/lists/'));
window.location.replace(site + "/SitePages/MyListForm.aspx");
</script>
this seems to be less volatile than the first method, but it still seems hacky. If I delete the original form web part, the form breaks and the list actions again revert to default. Editing the script requires visiting the form with ?contents=1 to delete the script web part and then I have to re-add it again using the toolpaneview method. In order to even save the web part change I have to click "Edit Web Part", which in turn saves it. There is no simple "Save" action which again makes me feel like this method is not intended to be done.
Is there any recommended way to accomplish these redirects? I've found plenty or tutorials online about setting up the list form, but nothing about this essential step.
I have an extension that I'm provisionally calling "multi-tab" for opening a given set of URLs in multiple tabs. For my personal use, which is to open several stock charts for stocks I'm tracking, I've just hard-coded the URLs. But it seems to me like this is something that others might find useful, and I can't find it among existing extensions. But in order to make it useful to others, I need to have some kind of interface for editing the URLs that you want to open. Here's the Github of what I have so far: https://github.com/aisthesis/multi-tab
So far the behavior is: You click on the icon for the extension, and it just opens the tabs. I'd like to keep that as simple as possible. I also tried using the "commands" API with a hot-key like "Ctrl+Shift+E" for opening some kind of editor interface (for which I think the Stack Exchange question monitor extension is a good model), but I couldn't get that to work, probably because I don't have a background popup for the key combo to bind to. I also tried using an omnibox where the editing menu would come up after you type "multi-tab-edit " or something like that. While I could get the omnibox version to work, but it doesn't seem very user-friendly. What I think would be ideal would be to have Ctrl-click on the icon in the extensions section open a dialog for editing your URLs, but I'm not seeing how the APIs would support that. Please respond if you can give me any pointers on how to make that happen!
Another option would be to open a popup when you click on the icon that would then allow you to choose whether you want to open the URLs you have currently set or to edit those URLs. I don't like that because it creates an additional step in the base use-case of just opening the tabs.
Does anyone have an idea for how one might implement an "editing" interface in a user-friendly way and leaving it so that just clicking on the icon just makes the various tabs open? Or is it possible to open an editor simply when you control-click on the icon?
You can simply set up an option page, with a bunch of HTML input elements, where your users can input the URLs they want to open:
<input type="text" name="url1" value="" />
<input type="text" name="url2" value="" />
<input id="save" type="button" value="Save" />
Then you save all those URLs to the local storage:
$('#save').click(function()
{
var urls = [];
$( "input[type=text]" ).each(function( index )
{
urls.push($(this).val());
});
var items = { "urls": urls };
chrome.storage.local.set(items, function() {});
});
Finally, you get all those URLs on a click on your browser action:
chrome.browserAction.onClicked.addListener(function(tab)
{
chrome.storage.local.get("urls", function(items)
{
var urls = items.urls;
for (var i = 0; i < urls.length; i++)
{
chrome.tabs.create({ url: urls[i]});
}
});
});
I am having some problems getting CodeMirror to indent the code at the beginning of a new line.
I have a text area, and when I hit save, the code that is saved to the DB is something like:
<meta charset=\"utf-8\">\r\n\t\t\t<title></title>\r\n\r\n<div class=\"wra ... etc
But when I read that out and do in the code behind in asp.net, ViewCode.Text = dbModel.ViewCode ... i.e. try to assign that string to the textarea which will then be 'converted' into the code mirror editor with relevant js on the page, the indent at the start of new lines is lost. If I indent half way along a line however, those render.
Also, if there is a new line return and then a blank row and then more text, the blank row gets lost when read back out to the text area.
Note: the textarea is runat server to fill the value from the database. I have tried with divs and literals but can't get it working.
So how can I save something like:
<div>
<b>
test
</b>
</div>
and not get it back like
<div>
<b>
test
</b>
</div>
I presume I have to encode it on save but I swear I have tried all encoding methods and now work! lol
Any pointers would be appreciated.
Cheers
Robin
Update/Solution
I have come back to put this in, in case some one stumbles across this post.
Basically I could not still not get the following to play nicely on the particular page in question. I.e.
Code behind
ViewCode.Value = dbModel.ViewCode
where
dbModel.ViewCode
// --> is comes from db as e.g.:
// <meta charset=\"utf-8\">\r\n\t\t\t<title></title>\r\n\r\n<div class=\"wra ... etc
JS (at end of page)
<script>
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("ViewCode"), {
lineNumbers: true
});
</script>
What I did get working however, is if you put the same JS code on the page, however, do NOT fill the text area from the code behind. Then I just make a simple ajax call to a page method to get the data (on page load).
$.ajax({
url: '/WidgetMaint.aspx/GetFileHTML',
type: 'Get',
contentType: 'application/json',
data: { tempid: id },
success: function(result) {
myCodeMirror.setValue(result.d);
}
});
The save and everything else works perfectly because the textarea is still run at server, so can still get its value 'on save', as code mirror takes care of this.
I am fairly sure that there is something else in the pipeline which is stuffing around with the text and 'formatting' it different before code mirror can get to it in time in the first attempt I was doing. However, with the ajax call the problem goes away because the browser/framework/whatever does not have any opportunity to access the string the DB returns. It is feed straight to the instance of code mirror which deals with it.
So in case you are having a similar problem, might be easier to change approach....
Cheers
Robin
Note: accepted answer by Eliran as it gave me this idea, and upvoted Marjin, because that comment proved it code mirror can handle indents...
I would advice you to drop that textarea and keep a live instance of CodeMirror on the page. That way you can assign the response directly to that instance using the CodeMirror API.
Take a look at doc.setValue(content: string) in particular, that should get you on the right track.
I created a script to publish the following html page using Html Service:
<html>
<div id="fixeddiv"></div>
<script>
var div=document.getElementById("fixeddiv");
div.style.position="fixed";
alert(div.style.position);
</script>
</html>
The alert window shows an empty string.
Isn't possible to set a fixed position for a div element?
I just ran into the same thing and the answer appears to be NO. Apparently they're worried fixed divs are a security exposure.
Next thing they'll be wanting to remove the keys from our keyboards too ;-)
I used this to get a 'fixed' effect for a global navbar at the top. It might be of use to you or others.
$(document).ready(function() {
$( window ).scroll(function() {
$( '.fixed' ).css('top', $( this ).scrollTop());
});
});
Note: in GAS the $( window ).scroll() wasn't working for me so I instead created a div block the size of the view port with a scroll bar overflow and used that instead.
I've found another 'solution' for this:
I created 2 divs, fixedHeader and content
<div id="fixedHeader"></div>
<div id="content"></div>
The css code, where we set #fixedHeader to be always on top and for #content we set a padding-top matching the height of #fixedHeader so the elements won't get under #fixedHeader:
#fixedHeader {position:absolute; top:0;}
#content {padding-top:50px; overflow:auto;}
And finally javascript to make #contet match the height of the viewport when document loads:
$(function(){ $("#content").css('height',window.innerHeight); }
Hope it helps
It appears that position:fixed is not allowed due to security concerns: http://code.google.com/p/google-apps-script-issues/issues/detail?id=1840
I noticed that the Buffer app for chrome does things a little differently with a floating div when the extension icon is clicked. How is this achieved?
I don't believe they do this in a new window since I am not seeing an addition window being spawned.
Basically what I need is a thickbox to be displayed when the icon is clicked.
Any insight on how this is done would be appreciated.
They're using an api from that background page, to listen to the click event for when the browser action button gets clicked.
Here's a link to that API page:
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(tab.id, {'file': 'createPopup.js'}, function callBackStub(){})
});
createPopup.js
You're html will be in a string. I personally recommend writing this like this:
var widgetHtml =
'<div id="main"> '+
' <p>some stuff goes here</p>'+
'</div>';
Then as your html grows, you can do a column edit of the beginning quote and end '+
Ok, now what you'll want to do is put your html in an iframe, but without setting a src property. Like this:
var iframe = document.createElement('iframe');
document.documentElement.appendChild(iframe); //fastest way to append to DOM: http://jsperf.com/insertbefore-vs-appendchild/2
iframe.contentDocument.body.innerHTML = widgetHtml;
WHY? So your stuff doesn't take on styles from the rest of the page.
Um, and then you can do a translateX or transition left/right position to slide the element into the page.