";
+}
+
+
diff --git a/static/css/iframe.css b/static/css/iframe.css
new file mode 100644
index 0000000..d7b90a6
--- /dev/null
+++ b/static/css/iframe.css
@@ -0,0 +1,37 @@
+.pageBreak{
+ page-break-after: always;
+ -webkit-region-break-inside: avoid;
+ border-bottom: 1px dotted #AAA;
+ width:100%;
+ height:1px;
+}
+
+.pageBreakComputed{
+ page-break-after: always;
+ -webkit-region-break-inside: avoid;
+ border-bottom: 1px dotted #AAA;
+}
+
+
+#outerdocbody > iframe{
+ left:0px !important;
+ width:850px !important;
+ margin:auto;
+}
+
+#outerdocbody{
+ background-color:#f7f7f7;
+ margin:none;
+ border:none;
+}
+
+#innerdocbody{
+ padding:100px 100px 100px 100px;
+ background-color:#fff;
+ border-radius: 5px 5px 0 0;
+ border: 1px solid #ccc;
+ border-width: 1px 1px 0 1px;
+ position: relative;
+ box-shadow: 10px 20px 40px 20px #ddd;
+}
+
diff --git a/static/css/page_view.css b/static/css/page_view.css
index 64499e0..1c782ee 100644
--- a/static/css/page_view.css
+++ b/static/css/page_view.css
@@ -4,15 +4,17 @@
overflow: hidden;
background-color: #f7f7f7;
text-align: center;
- padding-top: 27px;
+ padding-top: 16px;
}
iframe.page_view {
+/*
border-radius: 5px 5px 0 0;
border: 1px solid #ccc;
border-width: 1px 1px 0 1px;
position: relative;
- max-width: 850px;
+*/
+/* max-width: 850px;*/
}
-}
\ No newline at end of file
+}
diff --git a/static/js/page_view.js b/static/js/page_view.js
index 8f85900..3ebbd00 100644
--- a/static/js/page_view.js
+++ b/static/js/page_view.js
@@ -1,3 +1,7 @@
+var _, $, jQuery;
+var $ = require('ep_etherpad-lite/static/js/rjquery').$;
+var _ = require('ep_etherpad-lite/static/js/underscore');
+
var isMobile = $.browser.mobile;
if (!isMobile) {
@@ -33,6 +37,12 @@ if (!isMobile) {
$('#options-pageview').attr('checked',false);
pv.disable();
}
+ // Bind the event handler to the toolbar buttons
+ $('#insertPageBreak').on('click', function(){
+ context.ace.callWithAce(function(ace){
+ ace.ace_doInsertPageBreak();
+ },'insertPageBreak' , true);
+ });
};
exports.postAceInit = postAceInit;
} else {
@@ -52,3 +62,149 @@ function getParam(sname){
}
return sval;
}
+
+exports.aceEditorCSS = function(hook_name, cb){
+ return ["/ep_page_view/static/css/iframe.css"];
+} // inner pad CSS
+
+
+// Our PageBreak attribute will result in a PageBreak:1 class
+exports.aceAttribsToClasses = function(hook, context){
+ if(context.key == 'pageBreak'){
+ return ['pageBreak:' + 1 ];
+ }
+}
+
+/***
+*
+* Add the Javascript to Ace inner head, this is for the onClick listener
+*
+***/
+exports.aceDomLineProcessLineAttributes = function(name, context){
+ if( context.cls.indexOf("pageBreak") !== -1) { var type="pageBreak"; }
+ var tagIndex = context.cls.indexOf(type);
+ if (tagIndex !== undefined && type){
+ // NOTE THE INLINE CSS IS REQUIRED FOR IT TO WORK WITH PRINTING! Or is it?
+ var modifier = {
+ preHtml: '
',
+ postHtml: '
',
+ processedMarker: true
+ };
+ return [modifier]; // return the modifier
+ }
+
+ return []; // or return nothing
+
+};
+
+// Here we convert the class pageBreak into a tag
+exports.aceCreateDomLine = function(name, context){
+ var cls = context.cls;
+ var domline = context.domline;
+ var pageBreak = /(?:^| )pageBreak:([A-Za-z0-9]*)/.exec(cls);
+ var tagIndex;
+ if (pageBreak){
+ var modifier = {
+ extraOpenTags: '
',
+ extraCloseTags: '
',
+ cls: cls
+ };
+ return [modifier];
+ }
+ return [];
+};
+
+function doInsertPageBreak(){
+ this.editorInfo.ace_doReturnKey();
+ var rep = this.rep;
+ var documentAttributeManager = this.documentAttributeManager;
+ if (!(rep.selStart && rep.selEnd)){ return; } // only continue if we have some caret position
+ var firstLine = rep.selStart[0]; // Get the first line
+ var lastLine = Math.max(firstLine, rep.selEnd[0] - ((rep.selEnd[1] === 0) ? 1 : 0)); // Get the last line
+ _(_.range(firstLine, lastLine + 1)).each(function(i){ // For each line, either turn on or off task list
+ var isPageBreak = documentAttributeManager.getAttributeOnLine(i, 'pageBreak');
+ if(!isPageBreak){ // if its already a PageBreak item
+ documentAttributeManager.setAttributeOnLine(i, 'pageBreak', 'pageBreak'); // make the line a task list
+ }else{
+ documentAttributeManager.removeAttributeOnLine(i, 'pageBreak'); // remove the task list from the line
+ }
+ });
+ this.editorInfo.ace_focus();
+ this.editorInfo.ace_doReturnKey();
+}
+
+// Once ace is initialized, we set ace_doInsertPageBreak and bind it to the context
+exports.aceInitialized = function(hook, context){
+ var editorInfo = context.editorInfo;
+ editorInfo.ace_doInsertPageBreak = _(doInsertPageBreak).bind(context);
+}
+
+
+// Listen for Control Enter and if it is control enter then insert page break
+exports.aceKeyEvent = function(hook, callstack, editorInfo, rep, documentAttributeManager, evt){
+ var evt = callstack.evt;
+ var k = evt.keyCode;
+ if(evt.ctrlKey && k == 13 && evt.type == "keyup" ){
+ callstack.editorInfo.ace_doInsertPageBreak();
+ evt.preventDefault();
+ return true;
+ }else{
+ return;
+ }
+}
+
+exports.aceEditEvent = function(hook, callstack, editorInfo, rep, documentAttributeManager){
+ if(!callstack.callstack.docTextChanged) return;
+
+ var lines = {};
+ var yHeight = 1122.5; // This is dirty and I feel bad for it..
+ var lineNumber = 0;
+
+ var HTMLLines = $('iframe[name="ace_outer"]').contents().find('iframe').contents().find("#innerdocbody").children("div");
+
+ $(HTMLLines).each(function(){ // For each line
+ var y = $(this).context.offsetTop;
+ var id = $(this)[0].id; // get the id of the link
+ var height = $(this).height();
+
+ // How many PX since last break?
+ var lastLine = lineNumber-1;
+ if(!lines[lastLine]){
+ var previousY = 0;
+ var pxSinceLastBreak = 0;
+ }else{
+ var previousY = lines[lastLine].pxSinceLastBreak;
+ var pxSinceLastBreak = previousY + height;
+ }
+
+ // Does it already have any children with teh class pageBreak?
+ var manualBreak = $(this).children().hasClass("pageBreak");
+
+ // If it's a manualBreak then reset pxSinceLastBreak to 0;
+ if(manualBreak) pxSinceLastBreak = 0;
+
+ // Should this be a line break?
+ var computedBreak = ((pxSinceLastBreak + height) >= yHeight);
+ if(computedBreak){
+ // console.log(id, "should be a page break");
+ $(this).addClass("pageBreakComputed");
+ pxSinceLastBreak = 0;
+ }else{
+ $(this).removeClass("pageBreakComputed");
+ }
+
+ lines[lineNumber] = {
+ pxSinceLastBreak : pxSinceLastBreak,
+ manualBreak : manualBreak,
+ computedBreak : computedBreak,
+ id : id,
+ y : y,
+ height : height
+
+ }
+ lineNumber++;
+ });
+
+ // console.log(lines);
+}
+
diff --git a/static/js/shared.js b/static/js/shared.js
new file mode 100644
index 0000000..1cbf3bc
--- /dev/null
+++ b/static/js/shared.js
@@ -0,0 +1,28 @@
+var _ = require('ep_etherpad-lite/static/js/underscore');
+
+var collectContentPre = function(hook, context){
+ var tname = context.tname;
+ var state = context.state;
+ var lineAttributes = state.lineAttributes
+ var tagIndex = tname;
+
+ if(tagIndex >= 0){
+ lineAttributes['pageBreak'] = tagIndex;
+ }
+};
+
+var collectContentPost = function(hook, context){
+ var tname = context.tname;
+ var state = context.state;
+ var lineAttributes = state.lineAttributes
+ var tagIndex = tname;
+
+ if(tagIndex >= 0){
+ delete lineAttributes['pageBreak'];
+ }
+};
+
+exports.collectContentPre = collectContentPre;
+exports.collectContentPost = collectContentPost;
+
+
diff --git a/templates/page_view_menu.ejs b/templates/page_view_menu.ejs
new file mode 100644
index 0000000..96d9be6
--- /dev/null
+++ b/templates/page_view_menu.ejs
@@ -0,0 +1,2 @@
+