def modal(trigger='', *args, **kwargs): # trigger 如果是对innerHTML的处理,就是一个click_dom_id(selector), 如果是一个url,则是超级链接的title caller = kwargs.pop('caller', None) if not caller or not hasattr(caller, '__call__'): # 不是作为block模式,而是直接调用,可能是GET方式打开一个URL url = kwargs.get('url') or '' if not url and args: url = args[0] title = trigger if isinstance(url, (str, unicode)): # 创建一个GET模式的modal的a元素 dom_id = kwargs.get('id') return render_api_template('api_syntax_modal.jade', ajax=True, return_html=True, url=url, title=title, dom_id=dom_id, **kwargs) return '' inner_html = caller() dom_id = get_random_html_dom_id() if trigger and not trigger.startswith('#') and not trigger.startswith( '.'): # id 类型的补足 trigger = '#' + trigger html = render_api_template('api_syntax_modal.jade', inner_html=inner_html, dom_id=dom_id, selector=trigger, return_html=True, **kwargs) return html
def get_nav(nav_data, load_front_sources=True, toggle_menu=False, **scss_vars): if not isinstance(nav_data, (list, tuple)): return '' nav_data = pre_nav_data(nav_data) if not nav_data: return '' first_item = nav_data[0] if isinstance(first_item, dict): nav_type = 'full' else: nav_type = 'plain' # 跟 site.get_nav 接近的逻辑 # auto_frontend 表示默认载入前端资源 # scss_vars 是 menu 的 scss 替换 html_content = render_api_template( 'api_namespace_html_nav.jade', nav_data=nav_data, nav_type=nav_type, load_front_sources=load_front_sources, toggle_menu=toggle_menu, return_html=True, scss_vars=scss_vars, ) return html_content
def paginator(paginator=None, style='simple', **kwargs): if 'simple' in kwargs and not kwargs.get('simple'): # 对旧的兼容,最开始的时候,auto 风格的调用是 simple=False style = 'auto' # 构建上下页的label,当然本身也是可以传入 HTML 片段的 if 'pre_label' not in kwargs: if style == 'mini': pre_label = '<' else: pre_label = '« Prev' kwargs['pre_label'] = pre_label if 'next_label' not in kwargs: if style == 'mini': next_label = '>' else: next_label = 'Next »' kwargs['next_label'] = next_label paginator = paginator or get_paginator() if not paginator: return '' # ignore return render_api_template('paginator', paginator=paginator, paginator_style=style, return_html=True, **kwargs)
def tab(keys, active=1, **kwargs): # +tab(keys=[a, b, c], active=1) # #tab # #tab # #tab.etc caller = kwargs.pop('caller', None) if not caller or not hasattr(caller, '__call__'): return '' if not isinstance(keys, (list, tuple)) or not keys: return '' dom_id = get_random_html_dom_id() inner_html = caller() real_tabs_count = inner_html.count('<div id="tab">') keys = keys[:real_tabs_count] if len(keys) <=1: # 只有一个,没有处理为tab的需要 return inner_html for i in range(len(keys)): tab_dom_id = '%s-%s' % (dom_id, i) # 替换模板默认的tab id inner_html = re.sub(r'(<div )([^<>]*?id=[\'"])(tab\d*)([\'"])', '\g<1> class=tab_item \g<2>%s\g<4>'%tab_dom_id, inner_html, count=1) html = render_api_template('api_tab.jade', keys=keys, dom_id=dom_id, active=active, inner_html=inner_html, return_html=True, **kwargs) return html
def system_configs_setup(): if not get_logined_admin_bucket(): abort(404, "not admin") data_obj = load_app_global_envs() info = "" if request.method == "POST": configs = request.form.to_dict() set_app_global_envs(configs) if request.method == "POST": new_data_obj = load_app_global_envs() if new_data_obj != data_obj: # 尝试重启整个 Web App data_obj = new_data_obj # update should_sync_buckets_in_backend = auto_type( data_obj.get("should_sync_buckets_in_backend")) restart_backend = False if should_sync_buckets_in_backend: restart_backend = True try_to_reload_web_app(restart_backend=restart_backend) for field in ["show_donation", "should_sync_buckets_in_backend"]: if field in data_obj: data_obj[field] = auto_type(data_obj[field]) html = render_api_template("page_admin_system_setup.jade", info=info, data_obj=data_obj) #print(time.time() - t1) return Response(html)
def create_form_dom_by_field(field, field_container_class='', **kwargs): # field 是一个 to_form_fields_obj 中的一个 数据元素 html_content = render_api_template( 'form_dom.jade', field=field, field_container_class=field_container_class, return_html=True, **kwargs) return html_content
def page(*sub_args, **kwargs): caller = kwargs.pop('caller', None) if caller and request.args.get('pjax', '').lower() == 'true' and hasattr( caller, '__call__'): # pjax 下的时候,仅仅处理 caller 下的内容,这样就不会引入冗余的 html,从而直接 ajax append 即可 return force_response(caller()) html = render_api_template('api_syntax_page.jade', caller=caller, return_html=True, **kwargs) return html
def auto_toc(self, post=None, **kwargs): # for markdown post_type = post.get('_type') or post.get('type') if not post or not isinstance(post, dict) or post_type not in [ 'post', 'folder_post', 'folder' ]: return '' if not post.get('toc'): return '' html_content = render_api_template('auto_toc', post=post, **kwargs) return html_content
def js_view(title, url=None, group_id=None, view_type='', **kwargs): if url is None: # 默认值, 这样图片调用的时候, 只要一个传入就可以了 url = title url = smart_unicode(url) if isinstance(title, (tuple, list)) and len(title) == 2: title, thumbnail = title # 图片类型的 else: title = smart_unicode(title) mime_type = guess_type(title) or '' if mime_type.startswith('image/'): thumbnail = title # title 本身就是一张图片 title = kwargs.get('alt') or os.path.split(title)[ -1] # 文件名作为 title title = smart_unicode(title) else: thumbnail = '' if not view_type: # 自动推断 if thumbnail: view_type = 'image' elif url.endswith('.mp4'): view_type = 'video' else: link_mime_type = guess_type(url) or '' if link_mime_type.startswith('image/'): view_type = 'image' else: view_type = 'iframe' class_name = kwargs.get('class_name') or '' css_class = 'js_view js_view_%s %s' % (view_type, class_name) if group_id: css_class += ' js_view_group ' else: group_id = '' dom_id = get_a_random_dom_id() html_content = render_api_template('js_view', view_type=view_type, title=title, thumbnail=thumbnail, url=url, css_class=css_class, uuid=dom_id, group_id=group_id, return_html=True, **kwargs) return html_content
def auto_sidebar(self, side='left', sidebar_name='sidebar', width=300, default_status="hide"): # for markdown if side not in ['left', 'right']: side = 'left' width = to_int(width, 300) html = render_api_template('auto_sidebar', sidebar_name=sidebar_name, side=side, sidebar_width=width, default_status=default_status, return_html=True) return html
def add_new_comment_web_view(): bucket = request.values.get("bucket") site_configs = get_bucket_site_configs(bucket) if not site_configs: comments_allowed = False else: comments_allowed = site_configs.get("comments") if not comments_allowed: abort(404, 'comment is not allowed in this site') new_comment_doc = add_comment() if new_comment_doc.get('error'): # 错误信息 return jsonify(new_comment_doc) if request.values.get('format') in ['json', 'JSON']: return jsonify(new_comment_doc) else: return render_api_template('comment.jade', comment=new_comment_doc)
def change_bucket_date(): if not get_logined_admin_bucket(): abort(404, "not admin") info = "" bucket = request.values.get("bucket") date = request.values.get("date") if request.method == "POST": # change the expired date of bucket if not has_bucket(bucket): info = "no bucket found" elif not date: info = "no date to set" else: change_bucket_expired_date(bucket, date) service_info = get_bucket_service_info(bucket) html = render_api_template("page_admin_bucket_expired_date.jade", info=info, service_info=service_info) return Response(html)
def re_sub_for_referred_docs(re_obj, show_date=True, post_doc=None, url_root=None, url_prefix=None, hit_url_path=False): #prefix = re_obj.group(1) url = re_obj.group(2) url = unqote_url_path_to_unicode(url) original_html = re_obj.group(0) html_before_a = re_obj.group(1) html_after_a = re_obj.group(3) if "?x" in url: inline = True else: if html_before_a and html_before_a.startswith( "<span ") and html_before_a.endswith(">") and html_after_a: inline = False else: inline = True if "://" in url: return original_html if "original=yes" in url: return original_html else: sub_post = get_post_with_greed(url, parent_doc=post_doc) if not sub_post: return original_html if "#" in url: hash_id = url.split("#", 1)[-1] else: hash_id = "" post_url = get_post_url_with_url_path(sub_post, url_prefix=url_prefix, url_root=url_root, hit_url_path=hit_url_path) return render_api_template("builtin_api_referred_post.jade", sub_post=sub_post, show_date=show_date, post_url=post_url, hash_id=hash_id, inline=inline)
def show_wiki_nodes_as_sub_site(): bucket = get_bucket_in_request_context() if not bucket: return request_path = get_request_path().strip("/") if not re.match("wiki_nodes(/|$)", request_path): return wiki_configs = get_json_content_by_path(bucket, "__wiki.json", force_dict=True) enable_wiki_nodes = auto_type(wiki_configs.get("enable_wiki_nodes", True)) if not enable_wiki_nodes: return wiki_root = smart_unicode(wiki_configs.get("wiki_root", "")) if not wiki_root: return wiki_root = wiki_root.strip("/") wiki_title = wiki_configs.get("wiki_title") or get_just_name(wiki_root, for_folder=True) path = request.values.get("path", "").strip("/") if request.values.get("type") == "data": # return json data wiki_root = wiki_root.lower() under = "%s/%s" % (wiki_root, path) posts_info = get_bucket_posts_info(bucket) data = filter_and_get_posts_link_points_info(posts_info, under=under) nodes = data.get("nodes") if nodes: for node in nodes: node_id = node.get("id") if node_id and isinstance(node_id, string_types): if node_id.startswith("#"): tag = node_id.lstrip("#") url = "/wiki/tag/%s" % tag node["url"] = url else: relative_path = get_relative_path(node_id.strip("/"), wiki_root, return_name_if_fail=False) if relative_path: url = "/wiki/post/%s" % relative_path node["url"] = url return force_response(data) else: return render_api_template("builtin_theme_wiki_nodes.jade", wiki_title=wiki_title)
def create_grid_form(data_obj=None, keys=None, formats=None, callback_func=None, form_id=None, **kwargs): # 主要是会用 pure 进行排版的生成 if not keys: return '' do_post = False if request.method == 'POST': # 构建 data_obj do_post = True if form_id and request.args.get('form_id') != form_id: # 可能多个 form 混合,避免 POST 次序混了,确认form_id do_post = False if do_post: data_obj = get_data_obj_from_POST(keys) if callback_func: # POST 后的回调函数 callback_info = callback_func(data_obj) if isinstance(callback_info, string_types): callback_info = callback_info.strip() if callback_info and isinstance(callback_info, string_types): kwargs[ 'info'] = callback_info # 这个info会作为grid_form构建html时候的info变量 if request.values.get('ajax') == 'true': # AJAX 产生的提交, 直接返回请求的结果 info = callback_info or '' return force_response(info, 'text/plain') form_fields = to_form_fields_obj(data_obj, keys, formats) html_content = render_api_template('form_grid_form.jade', fields=form_fields, form_id=form_id, return_html=True, **kwargs) return html_content
def comments_as_html(obj): doc = obj site_configs = get_bucket_site_configs() should_hide_comments = not get_value_from_data(site_configs, 'comments', True) third_party_comments_script = get_value_from_data( site_configs, 'third_party_comments_script') or '' third_party_comments_script = smart_unicode( third_party_comments_script.strip()) if third_party_comments_script: # 有第三方评论脚本,直接进行替换 should_hide_comments = True if not should_hide_comments and get_value_from_data( doc, 'metadata.comment') in [False, 'no', 'No']: # doc 本身不允许显示 should_hide_comments = True if should_hide_comments: # 不显示评论系统 return third_party_comments_script html = render_api_template('comments.jade', doc=doc) return html
def create_simple_form(title='', keys=(), data_obj=None, formats=None, info=None, submit_text=None, **kwargs): # 自动生成一个 form,但没有自动处理 POST 的能力 # 变量预处理 starts title = title or '' if not isinstance(title, string_types) or not isinstance( keys, (list, tuple, dict, str, unicode)): return 'parameters error for simple form' formats = formats or {} if isinstance(keys, string_types): # 单 key keys = [keys] # 默认需要 focus 的元素 focus_dom_name = kwargs.pop('focus', None) if focus_dom_name: focus_dom_name = smart_unicode(focus_dom_name) focus_dom_name = focus_dom_name.split('#')[0] form_fields = to_form_fields_obj(data_obj, keys, formats) html_content = render_api_template('form_simple_form.jade', title=title, fields=form_fields, info=info, submit_text=submit_text, focus=focus_dom_name, formats=formats, return_html=True, **kwargs) return html_content
def ajax(dom_id, url, method='get', data='', callback=''): # 能够在模板中直接生成 ajax 的代码逻辑 # 向 url 发送 method 的请求,data 为 data, callback是一个本地的 js 函数名称 # 即使在一个 list 中,我们也认为 dom_id 是可以界定的,即使最终生成的代码看起来累赘,实际并没有什么性能问题 url = smart_unicode(url) if "'" in url: return "' is not allowed be included in a url" dom_id = smart_unicode(dom_id) method = smart_unicode(method).lower() if method not in ['get', 'post', 'delete', 'update']: method = 'get' if data: data = json_dumps(data) html_content = render_api_template('ajax.jade', url=url, method=method, data=data, callback=callback, dom_id=dom_id) return html_content
def slider(folder=None, doc_type='image', **kwargs): if doc_type not in ['post', 'image']: doc_type = 'image' if folder and isinstance(folder, (str, unicode)): docs = Data.get_data(path=folder, type=doc_type, level=1, with_page=False, limit=10, sort='position') else: docs = [] caller = kwargs.pop('caller', None) if not caller or not hasattr(caller, '__call__'): # 相当于直接的函数调用 inner_html = '' else: inner_html = caller() or '' elements = [] # turn docs into elements for doc in docs: element = render_api_template('api_slider_doc_element.jade', doc=doc, return_html=True, **kwargs) element = element.strip() if element: elements.append(element) dom_id = get_random_html_dom_id() height = kwargs.get('height') or '500px' nav_bottom = kwargs.get('nav_bottom') or '30px' block_css_style = "#%s .slider_element, #%s .unslider, #%s .bitcron_slider{height: %s} #%s .unslider-nav{bottom: %s}" % \ (dom_id, dom_id, dom_id, height, dom_id, nav_bottom) if inner_html: # 有 inner_html 的,进行某些标记性质的切割,获得 elements raw_elements = inner_html.split('<div class="slider_end"></div>') for raw_element in raw_elements: element = raw_element.strip() if element: elements.append(element) # slider 的动效等基本设定 autoplay = kwargs.pop('autoplay', True) if isinstance(autoplay, Undefined): autoplay = True show_arrows = kwargs.pop('show_arrows', True) if isinstance(show_arrows, Undefined): show_arrows = True animation = kwargs.pop('animation', '') if isinstance(animation, Undefined): animation = '' show_image_title = kwargs.pop('show_image_title', False) html = render_api_template('api_slider.jade', elements=elements, dom_id=dom_id, block_css_style=block_css_style, autoplay=autoplay, show_arrows=show_arrows, animation=animation, show_image_title=show_image_title, return_html=True, **kwargs) return html
def search_in_html(self, base_url='', under='', just_js=False, **kwargs): # 产生搜索的HTML代码片段 return render_api_template('search_posts.jade', search_base_url=base_url, search_under=under, just_js=just_js, **kwargs)
def show_wiki_as_sub_site(): bucket = get_bucket_in_request_context() if not bucket: return request_path = get_request_path().strip("/") if not re.match("wiki(/|$)", request_path): return wiki_configs = get_json_content_by_path(bucket, "__wiki.json", force_dict=True) wiki_root = smart_unicode(wiki_configs.get("wiki_root", "")) if not wiki_root: return set_data_root_in_request(wiki_root) # set data_root to request wiki_root = wiki_root.strip("/") wiki_title = wiki_configs.get("wiki_title") or get_just_name(wiki_root, for_folder=True) wiki_root = wiki_root.lower() kwargs = dict(wiki_root=wiki_root, wiki_title=wiki_title, wiki_configs=wiki_configs) if re.match("wiki/?$", request_path): # index docs = [] user_categories = wiki_configs.get("categories") if not isinstance(user_categories, (list, tuple)): user_categories = [] for user_category in user_categories: if not isinstance(user_category, dict): continue category_path = user_category.get("path") summary = smart_unicode(user_category.get("summary") or "") icon = smart_unicode(user_category.get("icon") or "") doc = get_record_by_path(bucket=bucket, path=category_path) if not doc: category_path = "%s/%s" % (wiki_root, category_path.strip("/")) doc = get_record_by_path(bucket=bucket, path=category_path) if not doc: continue doc_type = get_type_from_record(doc) if doc_type not in ["post", "folder"]: continue doc["icon"] = icon or get_value_from_data(doc, "metadata.icon") doc["summary"] = summary or get_value_from_data(doc, "metadata.summary") docs.append(doc) if not docs: # by default docs = Data.get_data(type='folder', level=1, limit=50, with_page=False, path=wiki_root) # 处理 url, 取 relative index_docs = [] for doc in docs: wiki_url = get_wiki_url_for_doc(wiki_root, doc) if not wiki_url: continue doc["wiki_url"] = wiki_url index_docs.append(doc) return render_api_template("builtin_theme_knowbase_index.jade", docs=index_docs, **kwargs) elif re.match("wiki/tag/", request_path): current_tag = get_offset_path(request_path, 2) if not current_tag: abort(404, "no tag?") docs = get_records_by_tag(bucket, current_tag, sort_by="-date") for doc in docs: doc["wiki_url"] = get_wiki_url_for_doc(wiki_root, doc) return render_api_template("builtin_theme_knowbase_tag.jade", current_tag=current_tag, docs=docs, **kwargs) elif re.search("wiki/search(/|$)", request_path): keywords = request.values.get("s") data_namespace = get_data_namespace() docs = data_namespace.get_data(bucket=bucket, keywords=keywords, pager_name="wiki", path=wiki_root, sort_by='-date', min_limit=8) for doc in docs: doc["wiki_url"] = get_wiki_url_for_doc(wiki_root, doc) return render_api_template("builtin_theme_knowbase_search.jade", docs=docs, **kwargs) elif re.match("wiki/category/", request_path): # category category_path = get_offset_path(request_path, 2).lower() wiki_nodes_url = "/wiki_nodes?path=%s" % category_path category_path = "%s/%s" % (wiki_root, category_path) folder_doc = get_record_by_path(bucket, category_path) enable_wiki_nodes = auto_type(wiki_configs.get("enable_wiki_nodes", True)) if not enable_wiki_nodes: wiki_nodes_url = "" if not folder_doc or get_type_from_record(folder_doc) != "folder": abort(404, "no category found") else: category = Category(folder_doc) docs = auto_pg(bucket=bucket, data_type="post", pager_name="wiki", path=category.path, ignore_marked_id=True, prefix_to_ignore='_', sort_by='-date', min_limit=8) for doc in docs: doc["wiki_url"] = get_wiki_url_for_doc(wiki_root, doc) return render_api_template("builtin_theme_knowbase_category.jade", category=category, docs=docs, wiki_nodes_url=wiki_nodes_url, **kwargs) elif re.match("wiki/post/", request_path): # detail doc_path = get_offset_path(request_path, 2) doc_path = "%s/%s" % (wiki_root, doc_path) doc = get_record_by_path(bucket, doc_path) if not doc: abort(404, "no doc found") else: return render_api_template("builtin_theme_knowbase_post.jade", doc=doc, **kwargs)
def show_albums_as_sub_site(): bucket = get_bucket_in_request_context() if not bucket: return request_path = get_request_path().strip("/") if not re.match("album(/|$)", request_path): return if "." in request_path and guess_type( request_path, default_type="").startswith("image/"): # 可能是直接的图片地址,避免被整个 album 给拦截了 return site_configs = get_bucket_site_configs(bucket) albums_root = smart_unicode(site_configs.get("albums_root", "")) if not albums_root: return albums_root = albums_root.strip("/") #todo 允许直接设定 / ? albums_home_sort = site_configs.get("albums_home_sort", "-date") album_items_sort = site_configs.get("album_items_sort", "-date") page_title = site_configs.get("albums_title") or get_just_name( albums_root, for_folder=True) if re.match("album/?$", request_path): # folders doc_type = "folder" doc_sort = albums_home_sort under = albums_root else: doc_type = "image" doc_sort = album_items_sort under = "%s/%s" % (albums_root, request_path.split("/", 1)[-1].strip("/")) folder_doc = get_record_by_path(bucket=bucket, path=under) if folder_doc: page_title = folder_doc.get("title") or get_just_name( folder_doc.get("path"), for_folder=True) else: page_title = get_just_name(under, for_folder=True) if doc_sort not in ["date", "-date"]: doc_sort = "-date" limit = 15 # todo 可以设定? doc_level = 1 # min_images_count = 1 docs = Data.get_data(path=under, type=doc_type, limit=limit, level=doc_level, sort=doc_sort, pager_name='album_docs_pager', exclude='default') if doc_type == "folder": for doc in docs: doc_path = get_path_from_record(doc, is_lower=True) relative_path = doc_path.replace(albums_root.lower(), "", 1).strip("/") doc["album_url"] = "/album/%s" % relative_path return render_api_template( "builtin_theme_album_waterfall.jade", docs=docs, page_title=page_title, )
def back_to_top(self, label=u'△'): # 页面右下角的返回顶部 html_content = render_api_template('back_to_top', label=label, return_html=True) return html_content
def ajax_submit(self, **kwargs): return render_api_template('ajax_submit.jade', **kwargs)