Skip to content
Snippets Groups Projects
Commit 133cf46d authored by Farbod Zamani's avatar Farbod Zamani Committed by Ron Lucke
Browse files

CW: Enhanced DocumentBlock PDF viewer

Closes #2018

Merge request studip/studip!1321
parent 022a1da0
No related branches found
No related tags found
No related merge requests found
......@@ -122,6 +122,7 @@
"typescript": "^5.0.2",
"vrp-vue-resizable": "1.2.7",
"vue": "^2.6.12",
"vue-dragscroll": "^3.0.1",
"vue-gettext": "^2.1.12",
"vue-loader": "^15.9.8",
"vue-router": "^3.5.1",
......
<?xml version="1.0" encoding="UTF-8"?><svg id="b" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><style>.f{fill:none;}.g{fill:#000;}</style></defs><g id="c"><rect class="f" width="64" height="64"/></g><g id="d"><g id="e"><path class="g" d="m50.71,13h-.42c-.82,0-1.59.2-2.29.54v-1.04c0-1.97-1.04-3.69-2.59-4.66,0,0,0,0,0,0-.26-.16-.52-.3-.8-.42-.05-.02-.09-.03-.14-.05-.25-.09-.5-.17-.77-.23-.02,0-.04-.01-.06-.02,0,0-.01,0-.02,0-.32-.07-.65-.1-.99-.11-.03,0-.05,0-.08,0-.02,0-.03,0-.05,0-.3,0-.59.03-.87.08-.08.01-.16.03-.24.05-.22.05-.44.11-.65.18-.08.03-.16.05-.24.08-.27.11-.54.23-.79.38-.73-2.19-2.79-3.76-5.22-3.76-2.74,0-5,2-5.42,4.62-.74-.38-1.56-.62-2.45-.62h-.25c-2.97,0-5.37,2.41-5.37,5.37v19.91l-3.18-6c-.93-1.76-2.74-2.76-4.61-2.76-.82,0-1.65.19-2.42.6-2.55,1.33-3.53,4.45-2.19,6.98l12.17,22.9c2.01,3.99,4.02,4.99,7.04,4.99h17.2c7.18,0,11-5.82,11-12.99v-28.71c0-2.92-2.37-5.29-5.29-5.29Zm-5.71,43h-17.2c-1.32,0-2.05,0-3.46-2.8-.01-.03-.03-.05-.04-.08l-12.16-22.9c-.18-.35-.15-.67-.08-.87.07-.21.22-.5.6-.69.18-.09.37-.14.56-.14.36,0,.82.17,1.07.63l3.18,6c.71,1.33,2.08,2.13,3.53,2.13.32,0,.64-.04.97-.12,1.78-.44,3.03-2.04,3.03-3.88V13.37c0-.76.62-1.37,1.37-1.37h.25c.19,0,.39.06.61.17.04.02.08.03.12.04.39.24.64.67.64,1.16v16.13c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5V9.5c0-.08.01-.16.02-.24,0,0,0,0,0,0,.03-.17.09-.33.17-.48,0-.01.01-.03.02-.04.08-.13.18-.25.29-.35.02-.02.04-.04.07-.05.12-.09.24-.17.38-.23.02,0,.04-.01.07-.02.15-.05.31-.09.48-.09s.32.03.46.08c.03,0,.06.02.08.03.13.05.25.12.36.2.02.01.04.03.06.05.22.18.37.42.45.65.06.16.09.32.09.5v18c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-15c0-.56.31-1.04.76-1.3.1-.06.2-.1.31-.13.02,0,.04-.02.07-.02.12-.03.24-.05.36-.05.83,0,1.5.67,1.5,1.5v19c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-13.21c0-.5.29-.92.71-1.14,0,0,.02,0,.03-.01.06-.03.12-.05.18-.07.12-.04.24-.07.37-.07h.42c.71,0,1.29.58,1.29,1.29v28.71c0,2.11-.5,9-7,9Z"/></g></g></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?><svg id="b" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><style>.f{fill:none;}.g{fill:#28497c;}</style></defs><g id="c"><rect class="f" width="64" height="64"/></g><g id="d"><g id="e"><path class="g" d="m50.71,13h-.42c-.82,0-1.59.2-2.29.54v-1.04c0-1.97-1.04-3.69-2.59-4.66,0,0,0,0,0,0-.26-.16-.52-.3-.8-.42-.05-.02-.09-.03-.14-.05-.25-.09-.5-.17-.77-.23-.02,0-.04-.01-.06-.02,0,0-.01,0-.02,0-.32-.07-.65-.1-.99-.11-.03,0-.05,0-.08,0-.02,0-.03,0-.05,0-.3,0-.59.03-.87.08-.08.01-.16.03-.24.05-.22.05-.44.11-.65.18-.08.03-.16.05-.24.08-.27.11-.54.23-.79.38-.73-2.19-2.79-3.76-5.22-3.76-2.74,0-5,2-5.42,4.62-.74-.38-1.56-.62-2.45-.62h-.25c-2.97,0-5.37,2.41-5.37,5.37v19.91l-3.18-6c-.93-1.76-2.74-2.76-4.61-2.76-.82,0-1.65.19-2.42.6-2.55,1.33-3.53,4.45-2.19,6.98l12.17,22.9c2.01,3.99,4.02,4.99,7.04,4.99h17.2c7.18,0,11-5.82,11-12.99v-28.71c0-2.92-2.37-5.29-5.29-5.29Zm-5.71,43h-17.2c-1.32,0-2.05,0-3.46-2.8-.01-.03-.03-.05-.04-.08l-12.16-22.9c-.18-.35-.15-.67-.08-.87.07-.21.22-.5.6-.69.18-.09.37-.14.56-.14.36,0,.82.17,1.07.63l3.18,6c.71,1.33,2.08,2.13,3.53,2.13.32,0,.64-.04.97-.12,1.78-.44,3.03-2.04,3.03-3.88V13.37c0-.76.62-1.37,1.37-1.37h.25c.19,0,.39.06.61.17.04.02.08.03.12.04.39.24.64.67.64,1.16v16.13c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5V9.5c0-.08.01-.16.02-.24,0,0,0,0,0,0,.03-.17.09-.33.17-.48,0-.01.01-.03.02-.04.08-.13.18-.25.29-.35.02-.02.04-.04.07-.05.12-.09.24-.17.38-.23.02,0,.04-.01.07-.02.15-.05.31-.09.48-.09s.32.03.46.08c.03,0,.06.02.08.03.13.05.25.12.36.2.02.01.04.03.06.05.22.18.37.42.45.65.06.16.09.32.09.5v18c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-15c0-.56.31-1.04.76-1.3.1-.06.2-.1.31-.13.02,0,.04-.02.07-.02.12-.03.24-.05.36-.05.83,0,1.5.67,1.5,1.5v19c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-13.21c0-.5.29-.92.71-1.14,0,0,.02,0,.03-.01.06-.03.12-.05.18-.07.12-.04.24-.07.37-.07h.42c.71,0,1.29.58,1.29,1.29v28.71c0,2.11-.5,9-7,9Z"/></g></g></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?><svg id="b" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><style>.f{fill:none;}.g{fill:#00962d;}</style></defs><g id="c"><rect class="f" width="64" height="64"/></g><g id="d"><g id="e"><path class="g" d="m50.71,13h-.42c-.82,0-1.59.2-2.29.54v-1.04c0-1.97-1.04-3.69-2.59-4.66,0,0,0,0,0,0-.26-.16-.52-.3-.8-.42-.05-.02-.09-.03-.14-.05-.25-.09-.5-.17-.77-.23-.02,0-.04-.01-.06-.02,0,0-.01,0-.02,0-.32-.07-.65-.1-.99-.11-.03,0-.05,0-.08,0-.02,0-.03,0-.05,0-.3,0-.59.03-.87.08-.08.01-.16.03-.24.05-.22.05-.44.11-.65.18-.08.03-.16.05-.24.08-.27.11-.54.23-.79.38-.73-2.19-2.79-3.76-5.22-3.76-2.74,0-5,2-5.42,4.62-.74-.38-1.56-.62-2.45-.62h-.25c-2.97,0-5.37,2.41-5.37,5.37v19.91l-3.18-6c-.93-1.76-2.74-2.76-4.61-2.76-.82,0-1.65.19-2.42.6-2.55,1.33-3.53,4.45-2.19,6.98l12.17,22.9c2.01,3.99,4.02,4.99,7.04,4.99h17.2c7.18,0,11-5.82,11-12.99v-28.71c0-2.92-2.37-5.29-5.29-5.29Zm-5.71,43h-17.2c-1.32,0-2.05,0-3.46-2.8-.01-.03-.03-.05-.04-.08l-12.16-22.9c-.18-.35-.15-.67-.08-.87.07-.21.22-.5.6-.69.18-.09.37-.14.56-.14.36,0,.82.17,1.07.63l3.18,6c.71,1.33,2.08,2.13,3.53,2.13.32,0,.64-.04.97-.12,1.78-.44,3.03-2.04,3.03-3.88V13.37c0-.76.62-1.37,1.37-1.37h.25c.19,0,.39.06.61.17.04.02.08.03.12.04.39.24.64.67.64,1.16v16.13c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5V9.5c0-.08.01-.16.02-.24,0,0,0,0,0,0,.03-.17.09-.33.17-.48,0-.01.01-.03.02-.04.08-.13.18-.25.29-.35.02-.02.04-.04.07-.05.12-.09.24-.17.38-.23.02,0,.04-.01.07-.02.15-.05.31-.09.48-.09s.32.03.46.08c.03,0,.06.02.08.03.13.05.25.12.36.2.02.01.04.03.06.05.22.18.37.42.45.65.06.16.09.32.09.5v18c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-15c0-.56.31-1.04.76-1.3.1-.06.2-.1.31-.13.02,0,.04-.02.07-.02.12-.03.24-.05.36-.05.83,0,1.5.67,1.5,1.5v19c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-13.21c0-.5.29-.92.71-1.14,0,0,.02,0,.03-.01.06-.03.12-.05.18-.07.12-.04.24-.07.37-.07h.42c.71,0,1.29.58,1.29,1.29v28.71c0,2.11-.5,9-7,9Z"/></g></g></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?><svg id="b" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><style>.f{fill:none;}.g{fill:#6e6e6e;}</style></defs><g id="c"><rect class="f" width="64" height="64"/></g><g id="d"><g id="e"><path class="g" d="m50.71,13h-.42c-.82,0-1.59.2-2.29.54v-1.04c0-1.97-1.04-3.69-2.59-4.66,0,0,0,0,0,0-.26-.16-.52-.3-.8-.42-.05-.02-.09-.03-.14-.05-.25-.09-.5-.17-.77-.23-.02,0-.04-.01-.06-.02,0,0-.01,0-.02,0-.32-.07-.65-.1-.99-.11-.03,0-.05,0-.08,0-.02,0-.03,0-.05,0-.3,0-.59.03-.87.08-.08.01-.16.03-.24.05-.22.05-.44.11-.65.18-.08.03-.16.05-.24.08-.27.11-.54.23-.79.38-.73-2.19-2.79-3.76-5.22-3.76-2.74,0-5,2-5.42,4.62-.74-.38-1.56-.62-2.45-.62h-.25c-2.97,0-5.37,2.41-5.37,5.37v19.91l-3.18-6c-.93-1.76-2.74-2.76-4.61-2.76-.82,0-1.65.19-2.42.6-2.55,1.33-3.53,4.45-2.19,6.98l12.17,22.9c2.01,3.99,4.02,4.99,7.04,4.99h17.2c7.18,0,11-5.82,11-12.99v-28.71c0-2.92-2.37-5.29-5.29-5.29Zm-5.71,43h-17.2c-1.32,0-2.05,0-3.46-2.8-.01-.03-.03-.05-.04-.08l-12.16-22.9c-.18-.35-.15-.67-.08-.87.07-.21.22-.5.6-.69.18-.09.37-.14.56-.14.36,0,.82.17,1.07.63l3.18,6c.71,1.33,2.08,2.13,3.53,2.13.32,0,.64-.04.97-.12,1.78-.44,3.03-2.04,3.03-3.88V13.37c0-.76.62-1.37,1.37-1.37h.25c.19,0,.39.06.61.17.04.02.08.03.12.04.39.24.64.67.64,1.16v16.13c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5V9.5c0-.08.01-.16.02-.24,0,0,0,0,0,0,.03-.17.09-.33.17-.48,0-.01.01-.03.02-.04.08-.13.18-.25.29-.35.02-.02.04-.04.07-.05.12-.09.24-.17.38-.23.02,0,.04-.01.07-.02.15-.05.31-.09.48-.09s.32.03.46.08c.03,0,.06.02.08.03.13.05.25.12.36.2.02.01.04.03.06.05.22.18.37.42.45.65.06.16.09.32.09.5v18c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-15c0-.56.31-1.04.76-1.3.1-.06.2-.1.31-.13.02,0,.04-.02.07-.02.12-.03.24-.05.36-.05.83,0,1.5.67,1.5,1.5v19c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-13.21c0-.5.29-.92.71-1.14,0,0,.02,0,.03-.01.06-.03.12-.05.18-.07.12-.04.24-.07.37-.07h.42c.71,0,1.29.58,1.29,1.29v28.71c0,2.11-.5,9-7,9Z"/></g></g></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?><svg id="b" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><style>.f{fill:none;}.g{fill:#cb1800;}</style></defs><g id="c"><rect class="f" width="64" height="64"/></g><g id="d"><g id="e"><path class="g" d="m50.71,13h-.42c-.82,0-1.59.2-2.29.54v-1.04c0-1.97-1.04-3.69-2.59-4.66,0,0,0,0,0,0-.26-.16-.52-.3-.8-.42-.05-.02-.09-.03-.14-.05-.25-.09-.5-.17-.77-.23-.02,0-.04-.01-.06-.02,0,0-.01,0-.02,0-.32-.07-.65-.1-.99-.11-.03,0-.05,0-.08,0-.02,0-.03,0-.05,0-.3,0-.59.03-.87.08-.08.01-.16.03-.24.05-.22.05-.44.11-.65.18-.08.03-.16.05-.24.08-.27.11-.54.23-.79.38-.73-2.19-2.79-3.76-5.22-3.76-2.74,0-5,2-5.42,4.62-.74-.38-1.56-.62-2.45-.62h-.25c-2.97,0-5.37,2.41-5.37,5.37v19.91l-3.18-6c-.93-1.76-2.74-2.76-4.61-2.76-.82,0-1.65.19-2.42.6-2.55,1.33-3.53,4.45-2.19,6.98l12.17,22.9c2.01,3.99,4.02,4.99,7.04,4.99h17.2c7.18,0,11-5.82,11-12.99v-28.71c0-2.92-2.37-5.29-5.29-5.29Zm-5.71,43h-17.2c-1.32,0-2.05,0-3.46-2.8-.01-.03-.03-.05-.04-.08l-12.16-22.9c-.18-.35-.15-.67-.08-.87.07-.21.22-.5.6-.69.18-.09.37-.14.56-.14.36,0,.82.17,1.07.63l3.18,6c.71,1.33,2.08,2.13,3.53,2.13.32,0,.64-.04.97-.12,1.78-.44,3.03-2.04,3.03-3.88V13.37c0-.76.62-1.37,1.37-1.37h.25c.19,0,.39.06.61.17.04.02.08.03.12.04.39.24.64.67.64,1.16v16.13c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5V9.5c0-.08.01-.16.02-.24,0,0,0,0,0,0,.03-.17.09-.33.17-.48,0-.01.01-.03.02-.04.08-.13.18-.25.29-.35.02-.02.04-.04.07-.05.12-.09.24-.17.38-.23.02,0,.04-.01.07-.02.15-.05.31-.09.48-.09s.32.03.46.08c.03,0,.06.02.08.03.13.05.25.12.36.2.02.01.04.03.06.05.22.18.37.42.45.65.06.16.09.32.09.5v18c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-15c0-.56.31-1.04.76-1.3.1-.06.2-.1.31-.13.02,0,.04-.02.07-.02.12-.03.24-.05.36-.05.83,0,1.5.67,1.5,1.5v19c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-13.21c0-.5.29-.92.71-1.14,0,0,.02,0,.03-.01.06-.03.12-.05.18-.07.12-.04.24-.07.37-.07h.42c.71,0,1.29.58,1.29,1.29v28.71c0,2.11-.5,9-7,9Z"/></g></g></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?><svg id="b" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><style>.f{fill:none;}.g{fill:#fff;}</style></defs><g id="c"><rect class="f" width="64" height="64"/></g><g id="d"><g id="e"><path class="g" d="m50.71,13h-.42c-.82,0-1.59.2-2.29.54v-1.04c0-1.97-1.04-3.69-2.59-4.66,0,0,0,0,0,0-.26-.16-.52-.3-.8-.42-.05-.02-.09-.03-.14-.05-.25-.09-.5-.17-.77-.23-.02,0-.04-.01-.06-.02,0,0-.01,0-.02,0-.32-.07-.65-.1-.99-.11-.03,0-.05,0-.08,0-.02,0-.03,0-.05,0-.3,0-.59.03-.87.08-.08.01-.16.03-.24.05-.22.05-.44.11-.65.18-.08.03-.16.05-.24.08-.27.11-.54.23-.79.38-.73-2.19-2.79-3.76-5.22-3.76-2.74,0-5,2-5.42,4.62-.74-.38-1.56-.62-2.45-.62h-.25c-2.97,0-5.37,2.41-5.37,5.37v19.91l-3.18-6c-.93-1.76-2.74-2.76-4.61-2.76-.82,0-1.65.19-2.42.6-2.55,1.33-3.53,4.45-2.19,6.98l12.17,22.9c2.01,3.99,4.02,4.99,7.04,4.99h17.2c7.18,0,11-5.82,11-12.99v-28.71c0-2.92-2.37-5.29-5.29-5.29Zm-5.71,43h-17.2c-1.32,0-2.05,0-3.46-2.8-.01-.03-.03-.05-.04-.08l-12.16-22.9c-.18-.35-.15-.67-.08-.87.07-.21.22-.5.6-.69.18-.09.37-.14.56-.14.36,0,.82.17,1.07.63l3.18,6c.71,1.33,2.08,2.13,3.53,2.13.32,0,.64-.04.97-.12,1.78-.44,3.03-2.04,3.03-3.88V13.37c0-.76.62-1.37,1.37-1.37h.25c.19,0,.39.06.61.17.04.02.08.03.12.04.39.24.64.67.64,1.16v16.13c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5V9.5c0-.08.01-.16.02-.24,0,0,0,0,0,0,.03-.17.09-.33.17-.48,0-.01.01-.03.02-.04.08-.13.18-.25.29-.35.02-.02.04-.04.07-.05.12-.09.24-.17.38-.23.02,0,.04-.01.07-.02.15-.05.31-.09.48-.09s.32.03.46.08c.03,0,.06.02.08.03.13.05.25.12.36.2.02.01.04.03.06.05.22.18.37.42.45.65.06.16.09.32.09.5v18c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-15c0-.56.31-1.04.76-1.3.1-.06.2-.1.31-.13.02,0,.04-.02.07-.02.12-.03.24-.05.36-.05.83,0,1.5.67,1.5,1.5v19c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-13.21c0-.5.29-.92.71-1.14,0,0,.02,0,.03-.01.06-.03.12-.05.18-.07.12-.04.24-.07.37-.07h.42c.71,0,1.29.58,1.29,1.29v28.71c0,2.11-.5,9-7,9Z"/></g></g></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?><svg id="b" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><style>.f{fill:none;}.g{fill:#ffad00;}</style></defs><g id="c"><rect class="f" width="64" height="64"/></g><g id="d"><g id="e"><path class="g" d="m50.71,13h-.42c-.82,0-1.59.2-2.29.54v-1.04c0-1.97-1.04-3.69-2.59-4.66,0,0,0,0,0,0-.26-.16-.52-.3-.8-.42-.05-.02-.09-.03-.14-.05-.25-.09-.5-.17-.77-.23-.02,0-.04-.01-.06-.02,0,0-.01,0-.02,0-.32-.07-.65-.1-.99-.11-.03,0-.05,0-.08,0-.02,0-.03,0-.05,0-.3,0-.59.03-.87.08-.08.01-.16.03-.24.05-.22.05-.44.11-.65.18-.08.03-.16.05-.24.08-.27.11-.54.23-.79.38-.73-2.19-2.79-3.76-5.22-3.76-2.74,0-5,2-5.42,4.62-.74-.38-1.56-.62-2.45-.62h-.25c-2.97,0-5.37,2.41-5.37,5.37v19.91l-3.18-6c-.93-1.76-2.74-2.76-4.61-2.76-.82,0-1.65.19-2.42.6-2.55,1.33-3.53,4.45-2.19,6.98l12.17,22.9c2.01,3.99,4.02,4.99,7.04,4.99h17.2c7.18,0,11-5.82,11-12.99v-28.71c0-2.92-2.37-5.29-5.29-5.29Zm-5.71,43h-17.2c-1.32,0-2.05,0-3.46-2.8-.01-.03-.03-.05-.04-.08l-12.16-22.9c-.18-.35-.15-.67-.08-.87.07-.21.22-.5.6-.69.18-.09.37-.14.56-.14.36,0,.82.17,1.07.63l3.18,6c.71,1.33,2.08,2.13,3.53,2.13.32,0,.64-.04.97-.12,1.78-.44,3.03-2.04,3.03-3.88V13.37c0-.76.62-1.37,1.37-1.37h.25c.19,0,.39.06.61.17.04.02.08.03.12.04.39.24.64.67.64,1.16v16.13c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5V9.5c0-.08.01-.16.02-.24,0,0,0,0,0,0,.03-.17.09-.33.17-.48,0-.01.01-.03.02-.04.08-.13.18-.25.29-.35.02-.02.04-.04.07-.05.12-.09.24-.17.38-.23.02,0,.04-.01.07-.02.15-.05.31-.09.48-.09s.32.03.46.08c.03,0,.06.02.08.03.13.05.25.12.36.2.02.01.04.03.06.05.22.18.37.42.45.65.06.16.09.32.09.5v18c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-15c0-.56.31-1.04.76-1.3.1-.06.2-.1.31-.13.02,0,.04-.02.07-.02.12-.03.24-.05.36-.05.83,0,1.5.67,1.5,1.5v19c0,1.38,1.12,2.5,2.5,2.5s2.5-1.12,2.5-2.5v-13.21c0-.5.29-.92.71-1.14,0,0,.02,0,.03-.01.06-.03.12-.05.18-.07.12-.04.24-.07.37-.07h.42c.71,0,1.29.58,1.29,1.29v28.71c0,2.11-.5,9-7,9Z"/></g></g></svg>
\ No newline at end of file
......@@ -3218,77 +3218,169 @@ c a n v a s b l o c k e n d
d o c u m e n t b l o c k
* * * * * * * * * * * * */
.cw-block-document {
.cw-pdf-header {
.cw-pdf-main-container {
width: calc(100% - 2px);
border: solid thin var(--content-color-40);
.cw-block-title {
border: none;
border-bottom: solid thin var(--content-color-40);
}
}
.cw-pdf-toolbar {
position: relative;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: baseline;
align-content: space-around;
background-color: var(--content-color-20);
padding: 4px 8px;
.cw-pdf-button-prev,
.cw-pdf-button-next {
position: absolute;
border: none;
background-repeat: no-repeat;
background-color: transparent;
height: 24px;
width: 24px;
margin: 2px 12px;
cursor: pointer;
button {
height: 100%;
margin: 0 2px 0 0;
padding: 4px;
&.active {
background-color: var(--base-color);
}
}
.cw-pdf-button-prev {
left: 0;
@include background-icon(arr_1left, clickable, 18);
&.inactive {
@include background-icon(arr_1left, inactive, 18);
.cw-pdf-toolbar-left {
position: relative;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: baseline;
align-content: space-between;
width: 33%;
}
.cw-pdf-toolbar-middle {
position: relative;
display: flex;
justify-content: center;
width: 34%;
.cw-pdf-zoom-buttons {
margin-right: 8px;
button {
margin: 0;
padding: 4px 0;
}
}
}
.cw-pdf-toolbar-right {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: baseline;
align-content: space-between;
position: relative;
width: 33%;
margin-right: 4px;
.cw-pdf-button-next {
right: 0;
@include background-icon(arr_1right, clickable, 18);
&.inactive {
@include background-icon(arr_1right, inactive, 18);
}
.cw-pdf-page-nav {
margin: 0 4px;
button {
margin: 0;
padding: 4px 0;
}
.cw-pdf-page-num {
text-align: right;
width: 2em;
}
}
.cw-pdf-download {
display: inline-block;
width: 18px;
height: 18px;
margin: 0 0.25em;
border: none;
cursor: pointer;
vertical-align: sub;
.cw-pdf-search-box {
position: absolute;
top: 33px;
left: 22px;
width: auto;
background-color: var(--content-color-20);
border-top: none;
padding: 6px;
z-index: 2;
line-height: normal;
background: no-repeat scroll 0 0;
@include background-icon(download, clickable, 18);
.cw-pdf-search-num {
margin: 4px 0 0 0;
display: block;
}
.cw-pdf-search-navs {
display: inline-block;
button {
margin: 0;
padding: 0;
}
}
.cw-pdf-canvas {
border: solid thin $content-color-40;
width: calc(100% - 2px);
}
.cw-pdf-downloadbox {
border: solid thin $content-color-40;
}
.cw-pdf-outer-container {
position: relative;
width: 100%;
.cw-pdf-content {
display: flex;
flex-direction: row;
.cw-pdf-sidebar {
width: 25%;
min-width: 270px;;
align-self: stretch;
background-color: var(--white);
border-right: solid 1px var(--content-color-40);
ul.cw-pdf-toc-list, ul.cw-pdf-toc-sub-list {
padding: 0;
list-style: none;
li {
padding: 0.5em 1em;
}
}
ul.cw-pdf-toc-list {
margin-top: 1em;
}
}
.cw-pdf-file-info {
@include background-icon(file, clickable, 24);
display: inline-block;
background-repeat: no-repeat;
padding-left: 26px;
margin: 1em;
line-height: 24px;
color: $base-color;
&.cw-pdf-fileicon-pdf {
@include background-icon(file-pdf, clickable, 24);
.cw-pdf-viewer-container {
width: 100%;
height: 100%;
overflow: hidden;
cursor: text;
&.hand-cursor-grab {
cursor: grab;
&.grabbing {
cursor: grabbing;
}
}
.cw-pdf-download-icon {
float: right;
@include background-icon(download, clickable, 24);
height: 24px;
width: 24px;
background-repeat: no-repeat;
margin: 1em;
&.has-error {
display: none;
}
.page {
position: relative;
margin: 0 auto;
}
}
}
.cw-pdf-viewer-fake-container {
position: absolute;
}
.cw-pdf-error-page {
overflow: hidden;
width: calc(100% - 16px);
height: 100%;
padding: 8px;
display:table;
}
}
}
......
......@@ -10,35 +10,183 @@
@closeEdit="initCurrentData"
>
<template #content>
<div v-if="hasFile" class="cw-pdf-header cw-block-title">
<button class="cw-pdf-button-prev" :class="{ inactive: pageNum - 1 === 0 }" @click="prevPage" />
<span class="cw-pdf-title">{{ currentTitle }}</span>
<a v-if="fileDownloadable" :href="currentUrl" class="cw-pdf-download" download></a>
<div class="cw-pdf-main-container">
<template v-if="hasFile">
<div v-if="currentTitle !== ''" class="cw-block-title">
{{ currentTitle }}
</div>
<div class="cw-pdf-toolbar">
<div class="cw-pdf-toolbar-left">
<div class="cw-pdf-toc">
<button
class="undecorated"
:class="{active: pdfTOCDisplay}"
:title="$gettext('Inhaltsverzeichnis')"
:aria-pressed="pdfTOCDisplay ? 'true' : 'false'"
@click="toggleTOCViewer"
>
<studip-icon
shape="table-of-contents"
:role="pdfTOC.length === 0 ? 'inactive' : pdfTOCDisplay ? 'info_alt' :'clickable'"
:size="18"
class="text-bottom"
/>
</button>
</div>
<div class="cw-pdf-search-toggle-btn">
<button
class="undecorated"
:class="{active: showPdfSearchBox}"
:title="$gettext('Suche')"
:aria-pressed="showPdfSearchBox ? 'true' : 'false'"
@click="togglePdfSearchBox"
>
<studip-icon
shape="search"
:role="showPdfSearchBox ? 'info_alt' : 'clickable'"
:size="18"
class="text-bottom"
/>
</button>
</div>
<div class="cw-pdf-search-box" v-show="showPdfSearchBox">
<input ref="pdfSearchInput" type="text" v-model="pdfSearch" @change="doSearchInPdf">
<div class="cw-pdf-search-navs" v-if="pdfSearchFoundNums > 1">
<button class="undecorated" @click="prevPdfSearch" :title="$gettext('Letzte')">
<studip-icon
shape="arr_1left"
:role="pdfSearchFoundSelectedIndex === 0 ? 'inactive' : 'clickable'"
:size="18"
class="text-bottom"
/>
</button>
<button class="undecorated" @click="nextPdfSearch" :title="$gettext('Nächste')">
<studip-icon
shape="arr_1right"
:role="pdfSearchFoundSelectedIndex === pdfSearchFoundNums - 1 ? 'inactive' : 'clickable'"
:size="18"
class="text-bottom"
/>
</button>
</div>
<span class="cw-pdf-search-num" v-if="pdfSearchFoundNums > 0">
{{ (pdfSearchFoundSelectedIndex + 1) }} / {{ pdfSearchFoundNums }} {{ $gettext('Treffer') }}
</span>
</div>
<div class="cw-pdf-page-nav">
<button class="undecorated" @click="prevPage" :title="$gettext('Eine Seite zurück')">
<studip-icon
shape="arr_1up"
:role="pageNum - 1 === 0 ? 'inactive' : 'clickable'"
:size="18"
class="text-bottom"
/>
</button>
<button class="undecorated" @click="nextPage" :title="$gettext('Eine Seite vor')">
<studip-icon
shape="arr_1down"
:role="pageNum === pageCount ? 'inactive' : 'clickable'"
:size="18"
class="text-bottom"
/>
</button>
<input
type="text"
ref="pageNumInput"
class="cw-pdf-page-num"
:aria-label="$gettext('Seite')"
:value="pageNum"
@change="updatePageNum"
>
<span>
<translate :translate-params="{pageNum, pageCount}">
(Seite %{ pageNum } von %{ pageCount })
</translate>
{{ $gettext('von') }} {{ pageCount }}
</span>
<button class="cw-pdf-button-next" :class="{ inactive: pageNum === pageCount }" @click="nextPage" />
</div>
<canvas
v-if="hasFile"
ref="pdfcanvas"
class="cw-pdf-canvas"
@mousedown="browse = true"
@mouseup="browse = false"
@mouseleave="browse = false"
@mousemove="browsePdf"
</div>
<div class="cw-pdf-toolbar-middle">
<div class="cw-pdf-zoom-buttons">
<button class="undecorated" @click="zoomIn" :title="$gettext('Vergrößern')">
<studip-icon shape="add" :size="18" class="text-bottom" />
</button>
<button class="undecorated" @click="zoomOut" :title="$gettext('Verkleinern')">
<studip-icon shape="remove" :size="18" class="text-bottom" />
</button>
<select v-model="currentScale" :aria-label="$gettext('Zoom')" @change="updateZoom">
<option v-show="false" :value="currentScale">{{ formattedZoom }}%</option>
<option v-for="(value, index) in scaleValues" :key="index" :value="value">{{ value * 100 }}%</option>
</select>
</div>
<div class="cw-pdf-rotate">
<button class="undecorated" @click="doRotatePdf" :title="$gettext('Drehen')">
<studip-icon shape="rotate-right" :size="18" class="text-bottom" />
</button>
</div>
</div>
<div class="cw-pdf-toolbar-right">
<div class="cw-pdf-handtool">
<button
class="undecorated"
:class="{active: pdfHandTool}"
:title="$gettext('Hand-Werkzeug')"
:aria-pressed="pdfHandTool ? 'true' : 'false'"
@click="toggleHandTool"
>
<studip-icon
shape="hand"
:role="pdfHandTool ? 'info_alt' : 'clickable'"
:size="18"
class="text-bottom"
/>
</button>
</div>
<div class="cw-pdf-download">
<a v-if="downloadable === 'true'" :href="currentUrl" download :title="$gettext('Speichern')">
<studip-icon shape="download" :size="18" class="text-bottom"/>
</a>
</div>
</div>
</div>
<div class="cw-pdf-outer-container" ref="outerContainer">
<div class="cw-pdf-content">
<span class="sr-only" aria-live="polite">{{ srMessage }}</span>
<div class="cw-pdf-sidebar" v-show="pdfTOCDisplay">
<ul class="cw-pdf-toc-list">
<CoursewarePDFTableOfContent v-for="(item, index) in pdfTOC" :item="item" :key="index" @tocPageNav="tocPageNav" />
</ul>
</div>
<div
ref="container"
class="cw-pdf-viewer-container"
:class="{'hand-cursor-grab': pdfHandTool, 'grabbing': pdfGrabbing, 'has-error': pdfError}"
v-dragscroll="pdfHandTool"
@mousedown="handleMouseDown"
@mouseup="handleMouseUp"
>
<div class="pdfViewer"/>
</div>
</div>
<div v-show="pdfError" class="cw-pdf-error-page">
<courseware-companion-box
mood="sad"
:msgCompanion="$gettext('Es gab einen Fehler. Bitte versuchen Sie es erneut!')"
>
</courseware-companion-box>
</div>
<div ref="fakeContainer" class="cw-pdf-viewer-fake-container">
<div class="pdfViewer"/>
</div>
</div>
</template>
</div>
</template>
<template v-if="canEdit" #edit>
<form class="default" @submit.prevent="">
<label>
<translate>Überschrift</translate>
{{ $gettext('Überschrift') }}
<input type="text" v-model="currentTitle" />
</label>
<label>
<translate>Datei</translate>
{{ $gettext('Datei') }}
<courseware-file-chooser
v-model="currentFileId"
:isDocument="true"
......@@ -46,14 +194,14 @@
/>
</label>
<label>
<translate>Download-Icon anzeigen</translate>
{{ $gettext('Download-Icon anzeigen') }}
<select v-model="currentDownloadable">
<option value="true"><translate>Ja</translate></option>
<option value="false"><translate>Nein</translate></option>
<option value="true">{{ $gettext('Ja') }}</option>
<option value="false">{{ $gettext('Nein') }}</option>
</select>
</label>
<label>
<translate>Dateityp</translate>
{{ $gettext('Dateityp') }}
<select v-model="currentDocType">
<option value="pdf">PDF</option>
</select>
......@@ -61,27 +209,48 @@
</form>
</template>
<template #info>
<p><translate>Informationen zum Dokument-Block</translate></p>
<p>{{ $gettext('Informationen zum Dokument-Block') }}</p>
</template>
</courseware-default-block>
</div>
</template>
<script>
import CoursewareCompanionBox from './CoursewareCompanionBox.vue';
import CoursewareDefaultBlock from './CoursewareDefaultBlock.vue';
import CoursewareFileChooser from './CoursewareFileChooser.vue';
import CoursewarePDFTableOfContent from './CoursewarePDFTableOfContent.vue';
import { blockMixin } from './block-mixin.js';
import * as pdfjsLib from 'pdfjs-dist';
import { getDocument } from 'pdfjs-dist';
import {
DefaultAnnotationLayerFactory,
DefaultTextLayerFactory,
DefaultXfaLayerFactory,
DefaultStructTreeLayerFactory,
PDFFindController,
PDFLinkService,
PDFPageView,
PDFViewer,
EventBus
} from 'pdfjs-dist/web/pdf_viewer.js';
// pdfjsWorker must be imported!
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry';
import { dragscroll } from 'vue-dragscroll'
import { mapActions } from 'vuex';
import 'pdfjs-dist/web/pdf_viewer.css';
export default {
name: 'courseware-document-block',
mixins: [blockMixin],
components: {
CoursewareCompanionBox,
CoursewareDefaultBlock,
CoursewareFileChooser,
CoursewarePDFTableOfContent
},
directives: {
dragscroll
},
props: {
block: Object,
......@@ -96,18 +265,38 @@ export default {
currentDownloadable: '',
currentDocType: '',
PdfViewer: true,
pdfError: false,
pdfBasePage: null,
pdfPage: null,
pdfTextContent: null,
pdfHandTool: false,
pdfGrabbing: false,
pdfTextLayer: null,
pdfAnnotationLayer: null,
pdfAnnotation: false,
pdfRotate: 0,
PdfViewer: null,
pdfEventBus: null,
pdfLinkService: null,
pdfFindController: null,
pdfDoc: null,
pdfLoadingTask: null,
pdfSearch: '',
pdfSearchMatchesMapping: [],
pdfSearchFoundNums: 0,
pdfSearchFoundSelectedIndex: 0,
pdfSearchHighlightedList: [],
showPdfSearchBox: false,
pdfTOC: [],
pdfTOCDisplay: false,
pageNum: 1,
pageRendering: false,
pageNumPending: null,
pageCount: 0,
scale: 2,
canvas: {},
context: {},
browse: false,
browseDirection: [],
file: null
scale: 1,
currentScale: 1,
scaleValues: [0.5, 1, 1.5, 2, 3, 4],
file: null,
srMessage: ''
};
},
computed: {
......@@ -135,20 +324,30 @@ export default {
},
hasFile() {
return this.currentFileId !== '';
}
},
formattedZoom () {
return Number.parseInt(this.scale * 100, 10);
},
},
watch: {
browseDirection: function (val) {
if (val.length > 6) {
this.evaluateBrowseAction();
}
scale(newValue) {
let overflow = newValue > 1 ? 'auto' : 'hidden';
let container = this.$refs.container;
container.style.overflow = overflow;
this.currentScale = newValue;
},
pageNum(newValue) {
this.resetPdfViewer();
},
showPdfSearchBox() {
this.resetPdfSearch();
}
},
mounted() {
this.loadFileRefs(this.block.id).then((response) => {
this.file = response[0];
this.currentFile = this.file;
this.loadPdfViewer();
this.initPdfTask();
});
this.initCurrentData();
},
......@@ -168,80 +367,380 @@ export default {
this.currentFile = file;
this.currentFileId = file.id;
},
loadPdfViewer() {
if (this.PdfViewer && this.currentUrl) {
initPdfTask() {
if (this.currentUrl) {
let view = this;
view.pdfEventBus = new EventBus();
view.pdfLoadingTask = getDocument(this.currentUrl).promise;
view.pdfLoadingTask.__PDFDocumentLoadingTask = true;
// Link Service
view.pdfLinkService = new PDFLinkService({
eventBus: view.pdfEventBus,
});
// Find Controller
view.pdfFindController = new PDFFindController({
eventBus: view.pdfEventBus,
linkService: view.pdfLinkService
});
// Annotation Layer
view.pdfAnnotationLayer = new DefaultAnnotationLayerFactory();
// Text Layer
view.pdfTextLayer = new DefaultTextLayerFactory();
// Load Pdf Document
view.loadPdfDocument();
// Handle search results.
view.pdfEventBus.on('updatetextlayermatches', ({source, pageIndex}) => {
if (view.pdfViewer.pdfPage._pageIndex == pageIndex) {
setTimeout(() => {
view.handleSearchMatches();
}, 260);
}
});
}
},
loadPdfDocument() {
if (this.pdfLoadingTask) {
let view = this;
view.pdfLoadingTask.then((pdfDocument) => {
view.pdfDoc = pdfDocument;
view.pageCount = pdfDocument.numPages;
// get table of contents if any.
view.loadPdfTOC();
// Rendering PDF viewer
view.loadPdfViewer();
view.pdfLinkService.setDocument(view.pdfDoc, null);
view.pdfFindController.setDocument(view.pdfDoc);
});
}
},
loadPdfTOC() {
if (this.pdfDoc) {
let view = this;
this.canvas = this.$refs.pdfcanvas;
this.context = this.canvas.getContext('2d');
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;
pdfjsLib.getDocument(this.currentUrl).promise.then(function (pdf) {
view.pdfDoc = pdf;
view.pageCount = view.pdfDoc.numPages;
view.renderPage(view.pageNum);
view.pdfTOC = [];
// Get the tree outline
view.pdfDoc.getOutline().then((outline) => {
if (outline) {
view.pdfTOC = outline;
}
});
}
},
renderPage(num) {
loadPdfViewer() {
if (this.pdfDoc) {
let view = this;
this.pageRendering = true;
this.pdfDoc.getPage(num).then(function (page) {
let viewport = page.getViewport({ scale: view.scale });
view.canvas.height = viewport.height;
view.canvas.width = viewport.width;
this.pdfError = false;
let container = this.$refs.container;
let outerContainer = this.$refs.outerContainer;
let fakeContainer = this.$refs.fakeContainer;
this.pdfDoc.getPage(parseInt(view.pageNum)).then((pdfPage) => {
view.pdfPage = pdfPage;
// Creating the page view with default parameters.
let defaultViewport = pdfPage.getViewport({
scale: 1.35,
});
let renderContext = {
canvasContext: view.context,
viewport: viewport,
};
let renderTask = page.render(renderContext);
view.pdfBasePage = new PDFViewer({
container: fakeContainer,
eventBus: view.pdfEventBus,
findController: view.pdfFindController
});
renderTask.promise.then(function () {
view.pageRendering = false;
if (view.pageNumPending !== null) {
view.renderPage(view.pageNumPending);
view.pageNumPending = null;
let pdfPageViewOptions = {
container: container,
id: view.pageNum,
scale: view.scale,
defaultViewport: defaultViewport,
eventBus: view.pdfEventBus,
findController: view.pdfFindController,
textHighlighterFactory: view.pdfBasePage,
xfaLayerFactory: view.pdfDoc.isPureXfa
? new DefaultXfaLayerFactory()
: null,
structTreeLayerFactory: new DefaultStructTreeLayerFactory()
};
if (view.pdfHandTool === false) {
pdfPageViewOptions.textLayerFactory = view.pdfTextLayer;
pdfPageViewOptions.annotationLayerFactory = view.pdfAnnotationLayer;
} else {
pdfPageViewOptions.textLayerMode = 0;
pdfPageViewOptions.annotationMode = 0;
}
// Force annotation to be disabled.
if (!this.pdfAnnotation && pdfPageViewOptions?.annotationLayerFactory) {
pdfPageViewOptions.annotationLayerFactory = null;
pdfPageViewOptions.annotationMode = 0;
}
view.pdfViewer = new PDFPageView(pdfPageViewOptions);
// Associates the actual page with the view, and drawing it
view.pdfViewer.setPdfPage(view.pdfPage);
// Set LinkService viewer
view.pdfLinkService.setViewer(view.pdfViewer);
// Set outer container height
outerContainer.style.height = container.offsetHeight + 'px';
view.renderPage();
}).catch(err => {
console.log(err);
outerContainer.style.minHeight = '350px';
view.pdfError = true;
});
}
},
renderPage() {
if (this.pdfViewer) {
this.updatePdfViewer();
this.pdfViewer.draw();
if (!this.pdfHandTool) {
this.pdfViewer.textLayer.findController = this.pdfFindController;
}
if (this.pdfPage) {
this.pdfPage.getTextContent().then((textContent) => {
this.pdfTextContent = textContent;
});
}
if (this.pdfSearchMatchesMapping.length) {
this.pdfSearchDisplayHandler();
}
}
},
queueRenderPage(num) {
if (this.pageRendering) {
this.pageNumPending = num;
} else {
this.renderPage(num);
resetPdfViewer() {
this.pdfViewer.destroy();
let container = this.$refs.container;
while (!container.lastChild.classList.contains('pdfViewer')) {
container.removeChild(container.lastChild);
}
this.loadPdfViewer();
},
updatePdfViewer(resetScale = false) {
let updateArgs = {
scale: resetScale ? 1 : this.scale,
rotation: this.pdfRotate,
};
this.pdfViewer.update(updateArgs);
},
prevPage() {
if (this.pageNum <= 1) {
return;
}
this.pageNum--;
this.queueRenderPage(this.pageNum);
},
nextPage() {
if (this.pageNum >= this.pdfDoc.numPages) {
return;
}
this.pageNum++;
this.queueRenderPage(this.pageNum);
},
browsePdf(e) {
if (this.browse) {
this.browseDirection.push(e.clientX);
goToPage(page) {
const pageNum = Number.parseInt(page, 10);
if (pageNum < 1 || pageNum > this.pdfDoc.numPages) {
return;
}
this.pageNum = pageNum;
},
tocPageNav(dest) {
let view = this;
let destObj = dest.find((ref) =>
typeof ref === "object" && ref !== null &&
Number.isInteger(ref.num) && ref.num >= 0 &&
Number.isInteger(ref.gen) && ref.gen >= 0);
if (destObj) {
view.pdfDoc.getPageIndex(destObj).then((pageIndex) => {
view.goToPage(pageIndex + 1);
});
}
},
evaluateBrowseAction() {
this.browse = false;
let first = this.browseDirection[0];
let last = this.browseDirection.pop();
this.browseDirection = [];
if (first < last) {
this.prevPage();
updatePageNum() {
let pageNumInput = this.$refs.pageNumInput;
let value = Number.parseInt(pageNumInput.value, 10);
if (Number.isInteger(value) && value > 0 && value <= Number.parseInt(this.pageCount, 10)) {
this.pageNum = value;
} else {
this.nextPage();
pageNumInput.value = this.pageNum;
}
},
doRotatePdf() {
let rotationDegs = [0, 90, 180, 270, 360];
let index = rotationDegs.indexOf(this.pdfRotate);
let nextIndex = index + 1 >= rotationDegs.length ? 0 : index + 1;
let nextDeg = rotationDegs[nextIndex];
this.pdfRotate = nextDeg;
this.renderPage();
this.updateSrMessage(this.$gettext('gedreht'));
},
zoomIn() {
this.scale = this.scale < 4 ? (this.scale * 10 + 1) / 10 : this.scale;
this.renderPage();
this.updateSrMessage(this.$gettext('vergrößert'));
},
zoomOut() {
this.scale = this.scale > 0.1 ? (this.scale * 10 - 1) / 10 : this.scale;
this.renderPage();
this.updateSrMessage(this.$gettext('verkleinert'));
},
updateZoom(e) {
const value = e.target.value;
if (this.scale === value) {
return;
}
this.scale = value;
this.renderPage();
this.updateSrMessage(this.$gettext('Zoom Stufe ausgweählt'));
},
toggleHandTool() {
this.pdfHandTool = !this.pdfHandTool;
this.resetPdfViewer();
this.showPdfSearchBox = false;
},
handleHandToolDisplay(event) {
this.pdfGrabbing = event.type === 'mousedown';
},
handleMouseDown(e) {
this.handleHandToolDisplay(e);
},
handleMouseUp(e) {
this.handleHandToolDisplay(e);
},
togglePdfSearchBox() {
this.showPdfSearchBox = this.pdfHandTool ? false : !this.showPdfSearchBox;
if (this.showPdfSearchBox) {
this.$nextTick(() => {
this.$refs.pdfSearchInput.focus();
});
}
},
handleSearchMatches() {
let view = this;
let allMatches = view.pdfFindController.pageMatches;
let totalMatches = 0;
let searchSelectIndex = 0;
let matchesPageCount = 0;
view.pdfSearchMatchesMapping = [];
for (let pageIndex = 0; pageIndex < view.pageCount; pageIndex++) {
let pageNum = pageIndex + 1;
let pageMatches = allMatches[pageIndex];
totalMatches += pageMatches.length;
if (pageMatches.length) {
matchesPageCount++;
}
for (let i in pageMatches) {
let matchIndex = parseInt(i, 10);
let mappingObj = {
selectIndex: searchSelectIndex,
matchIndex: matchIndex,
pageNum: pageNum,
}
view.pdfSearchMatchesMapping.push(mappingObj);
searchSelectIndex++;
}
}
// Find next match if there the current page has nothing.
if (
view.pdfSearchFoundSelectedIndex === 0
&& view.pdfViewer.pdfPage._pageIndex > 0
&& matchesPageCount > 0
) {
let nextMapped = view.pdfSearchMatchesMapping.filter(map => map.pageNum >= view.pdfViewer.pdfPage._pageIndex + 1);
if (nextMapped.length) {
view.pdfSearchFoundSelectedIndex = nextMapped[0].selectIndex;
}
}
view.pdfSearchFoundNums = totalMatches;
view.pdfSearchDisplayHandler();
},
doSearchInPdf() {
let findObj = {
type: '',
query: this.pdfSearch,
phraseSearch: true,
caseSensitive: false,
entireWord: true,
highlightAll: true,
findPrevious: false,
matchDiacritics: false
};
this.pdfEventBus.dispatch('find', findObj);
},
prevPdfSearch() {
if (this.pdfSearchFoundSelectedIndex === 0) {
return;
}
this.pdfSearchFoundSelectedIndex--;
this.pdfSearchDisplayHandler();
},
nextPdfSearch() {
if (this.pdfSearchFoundSelectedIndex === this.pdfSearchFoundNums - 1) {
return;
}
this.pdfSearchFoundSelectedIndex++;
this.pdfSearchDisplayHandler();
},
pdfSearchDisplayHandler() {
// Go to page based on selected index.
let pageMatches = this.pdfSearchMatchesMapping.filter(map =>
map.selectIndex === this.pdfSearchFoundSelectedIndex
);
if (pageMatches.length) {
let matchObj = pageMatches[0];
// A timeout of > 250ms is needed when page is changed!
let highlightRenderTimeout = 0;
if (matchObj.pageNum !== this.pageNum) {
this.goToPage(matchObj.pageNum);
highlightRenderTimeout = 260;
}
setTimeout(() => {
this.setPdfSearchHighlighted();
this.scrollToSearchFounds(matchObj.matchIndex);
}, highlightRenderTimeout);
}
},
scrollToSearchFounds(matchIndex) {
if (this.pdfSearchHighlightedList?.length) {
let selectedSpan = this.pdfSearchHighlightedList[matchIndex];
if (selectedSpan) {
selectedSpan.classList.add('selected');
selectedSpan.scrollIntoView({ behavior: 'smooth', block: "center" });
}
}
},
setPdfSearchHighlighted() {
if (this.pdfViewer?.textLayer?.textDivs) {
let textDivs = this.pdfViewer.textLayer.textDivs;
let highlightedSpans = [];
for (let textSpan of textDivs) {
if (textSpan?.children) {
let children = [...textSpan.children];
for (let child of children) {
if (child.nodeName == 'SPAN' && child.classList.contains('highlight')) {
child.classList.remove('selected');
highlightedSpans.push(child);
}
}
}
}
// Sort the array based on the top of the span.
highlightedSpans.sort((current, next) => {
let currentTop = parseInt(current.parentNode.style.top, 10);
let nextTop = parseInt(next.parentNode.style.top, 10);
return currentTop > nextTop;
});
this.pdfSearchHighlightedList = highlightedSpans;
}
},
resetPdfSearch() {
this.pdfSearch = '';
this.pdfSearchFoundNums = 0;
this.pdfSearchFoundSelectedIndex = 0;
this.pdfSearchHighlightedList = [];
this.pdfSearchMatchesMapping = [];
this.doSearchInPdf();
},
toggleTOCViewer() {
if (this.pdfTOC.length) {
this.pdfTOCDisplay = !this.pdfTOCDisplay;
} else {
this.pdfTOCDisplay = false;
}
},
storeBlock() {
if (this.currentFile === undefined) {
this.companionWarning({
......@@ -253,7 +752,7 @@ export default {
attributes.payload = {};
attributes.payload.title = this.currentTitle;
attributes.payload.file_id = this.currentFile.id;
attributes.payload.downloadable = this.currentDownloadable;
attributes.payload.downloadable = this.currentDownloadable.toString();
attributes.payload.doc_type = this.currentDocType;
this.updateBlock({
......@@ -263,6 +762,10 @@ export default {
});
}
},
updateSrMessage(message) {
this.srMessage = '';
this.srMessage = message;
}
},
};
</script>
<template>
<li class="cw-pdf-toc-item">
<a href="#" @click.prevent="tocPageNav(item.dest)">
<strong v-if="item.bold">{{ item.title }}</strong>
<span v-else>{{ item.title }}</span>
</a>
<template v-if="item.items">
<ul class="cw-pdf-toc-sub-list">
<courseware-pdf-toc-item v-for="(item, index) in item.items" :item="item" :key="index" @tocPageNav="tocPageNav"></courseware-pdf-toc-item>
</ul>
</template>
</li>
</template>
<script>
export default {
name: 'courseware-pdf-toc-item',
props: {
item: {
type: Object,
required: true,
},
},
methods: {
tocPageNav(dest) {
this.$emit('tocPageNav', dest);
}
},
}
</script>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment